webアプリケーションのフォームで、予期せぬ値を入力できないようにしたくて、今回は、jQueryのライブラリであるflexdatalistを使って、オートコンプリート機能によって、入力値に制限を加える実装をしてみました。
他にも、バリデーションを厳しくかけたり、フォーム送信後に整形したりすることもありますが、今回は、オートコンプリート!
もくじ
- flexdatalistでカンタンなデモアプリを作ってみる
- Flaskのフォームでflexdatalistを使ってみる
flexdatalistでカンタンなデモアプリを作ってみる
Flaskに導入する前に、flexdatalistだけで超簡単なデモを作ってみます。
flexdatalistって何?
- flexdatalist 公式ドキュメント
- JQueryのライブラリ
- 「mutiple values」を使えば、複数の値をカンマ区切りで送信できる。 (← 今回はこれ使った)
ライブラリの読み込み
まず、ライブラリの読み込みから丁寧目にやります。
- index.htmlを作る
- 公式ドキュメントの下部にある「HOW TO INSTALL」をもとに、headの中に必要な情報を記入していきます。
- ドキュメント上部にあるDownloadボタンから、必要なファイルをlocalに置きます。
- js/libディレクトリを作って、その下にとりあえず置いておきます。(下の方に最終的なディレクトリ構造を載せてあります。)
(久しぶりに、jQueryを触って、いろいろ忘れていたから、じっくりと。)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>flexdatalist Sample</title>
<script src="https://code.jquery.com/jquery-3.3.1.js" integrity="sha256-2Kok7MbOyxpgUVvAk/HJ2jigOSYS2auK4Pfzbm7uH60=" crossorigin="anonymous"></script>
<link href="js/lib/jquery-flexdatalist-2.2.4/jquery.flexdatalist.min.css" rel="stylesheet" type="text/css">
<script src="js/lib/jquery-flexdatalist-2.2.4/jquery.flexdatalist.min.js"></script>
</head>
<body>
</body>
</html>
デモアプリ実装
とりあえず、index.htmlのbodyタグの中に、下記をベタ書きしていきます。
- 入力欄
- オートコンプリートで入力させたい文字列リスト
- jsの関数
<body>
<input type='text'
class='flexdatalist'
data-min-length='1'
multiple='multiple'
list='drink_list'
name='drink_list'>
<datalist id="drinki_list">
<option value="Late">Late</option>
<option value="Mocha">Mocha</option>
<option value="Cappuccino">Cappuccino</option>
<option value="Blend">Blend</option>
<option value="Espresso">Espresso</option>
<option value="Lemonade">Lemonade</option>
<option value="Chai">Chai</option>
<option value="Cold Brew">Cold Brew</option>
<option value="Single Origin Espresso">Single Origin Espresso</option>
<option value="Gibraltar">Gibraltar</option>
</datalist>
<script>
$('.flexdatalist').flexdatalist({
minLength: 1
});
</script>
</body>
ブラウザで開いて、正常に動くか確かめてみましょう。
(WebStormとか、PyCharmを使っていたら、index.htmlを右クリックで、「Open in Browser」でカンタン。)
ハマったところ
- minLength
- inputタグの中とscriptのjsの中で指定することができる。
- だが、反映される優先順位が高いのは、inputタグの中。
- jsの方で
minLength: 100
とかにしても、inputタグのdata-min-length='1'
が優先され、1文字入力すれば検索をしてくれる。
Flaskのフォームでflexdatalistを使ってみる
上で一通り作ったflexdatalistを、Flaskのフォームに適応させていきます。
Flaskのフォームを作る
まずは、適当にFlaskでフォームを作ってみます。
from flask import Flask, render_template, request, redirect
from flask_wtf import FlaskForm
from wtforms import StringField
from wtforms.validators import DataRequired
app = Flask(__name__)
app.config["SECRET_KEY"] = 'coffee drinker' #CSRF対策で必要らしい
class Form(FlaskForm):
drink_list = StringField("drink_list", validators=[])
@app.route("/", methods=["GET", "POST"])
def index():
form = Form()
return render_template("index.html", form=form)
@app.route("/submit", methods=["POST"])
def submit():
form = Form()
if form.validate():
drink_names = request.form["drink_list"]
return render_template("result.html", drink_name=drink_names)
return render_template("index.html", form=form)
if __name__ == "__main__":
app.run(debug=True)
flexdatalistにFlaskを適用してみる
先程作ったindex.htmlをFlask対応させた記述に変更します。
ついでに、htmlファイルにあったjsの記述は、新しくjsファイルを作って、そちらに移動させましょう。
ディレクトリの移動
まず、htmlファイルやjsファイルは、Flaskで決まっている位置に置きましょう。
ちなみに、ディレクトリ構造はこんな感じにしてあります。
flask-auto-complete
├── app.py
├── static
│ ├── drink_list.json
│ └── js
│ ├── lib
│ │ └── jquery-flexdatalist-2.2.4
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── bower.json
│ │ ├── jquery.flexdatalist.css
│ │ ├── jquery.flexdatalist.js
│ │ ├── jquery.flexdatalist.min.css
│ │ ├── jquery.flexdatalist.min.js
│ │ └── package.json
│ └── script.js
└── templates
├── index.html
└── result.html
※ script.js, drink_list.json, result.htmlは後で作る。
それに伴い、ファイル内のファイルパスの指定も url_for
を使って書き直しましょう。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>flexdatalist Sample</title>
<script src="https://code.jquery.com/jquery-3.3.1.js" integrity="sha256-2Kok7MbOyxpgUVvAk/HJ2jigOSYS2auK4Pfzbm7uH60=" crossorigin="anonymous"></script>
<link href="{{ url_for('static', filename='js/lib/jquery-flexdatalist-2.2.4/jquery.flexdatalist.min.css') }}" rel="stylesheet" type="text/css">
<script src="{{ url_for('static', filename='js/lib/jquery-flexdatalist-2.2.4/jquery.flexdatalist.min.js') }}"></script>
</head>
<body>
<form method="POST" action="/submit">
{{ form.hidden_tag() }}
<input type='text'
class='flexdatalist'
data-data="{{ url_for('static', filename='drink_list.json')}}"
name='drink_list'>
<input type="submit" value="Send">
</form>
<script src="{{ url_for('static', filename='js/script.js') }}"></script>
jsファイルへ移行
$('.flexdatalist').flexdatalist({
minLength: 1,
searchIn: 'name',
data: "{{ url_for('static', filename='drink_list.json') }}",
selectionRequired: true,
multiple: true
});
drink_listをjsonファイルに切り出す
htmlファイルにべた書きしておくと、単純にダサいですし、量が増えたときに見づらくなるので、切り出して別ファイルに置いておきます。
[
{"name": "Late"},
{"name": "Mocha"},
{"name": "Cappuccino"},
{"name": "Blend"},
{"name": "Espresso"},
{"name": "Lemonade"},
{"name": "Chai"},
{"name": "Cold Brew"},
{"name": "Single Origin Espresso"},
{"name": "Gibraltar"}
]
フォーム送信後のページを作成
せっかくなので、フォームを送信後のページを、入力した値を使って表示させました。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Result</title>
</head>
<body>
<h2>{{ drink_name }} 美味しかった!!!</h2>
</body>
</html>
このコマンドをターミナルで打つか、PyCharmで実行して、ブラウザにlocalhost:XXXXで、正しく動くか確認しましょう。
$ python app.py
終わりに
僕の力不足で、理解しづらい点もあったかもしれませんが、無事、実装できましたか?
GitHubに開発の流れでコミットしてるので、是非参考にしてください。
また、編集リクエストもお待ちしています。