WEBシステムでフォームを作っている際に必ずと言ってもいいほど必要になるのが「AutoComplete(Suggest)」の機能です。
私はかなり前からjQueryのTypeheadの機能を利用してAutoCompleteを実装していたのですが、Vue.jsを触りはじめたのでそろそろjQueryから脱却したいと思ってました。Vueはコンポーネントとして機能を切り出しやすいのがいいですよね。ちなみにVue.js歴は1ヶ月程度の初心者です。
今回は脱jQuetyを目標にAutoCompleteの機能をVue.jsで作ってみたいと思います。また、AutoCompleteの動作としてAjaxを利用しての連携が行えるようにしたいと思います。
Vue.jsでAutoComplteを実装する方法
はじめにVue.jsを利用したAutoComplete関連のライブラリで利用できるものがないか調べてみました。
調べてみると以下のようなVue.jsライブラリが有名なようです。
- vue-simple-suggest
- vue-cool-select
- vue-instant
こちらについても今後試してみたいと思いますが、今回は一番簡単な方法としてHTML5のdatalistを使ってAutoCompleteを自作することにしました。
他の方法についても追々でテストしてみたいと思います。
Datalistを使うことで簡単にAutoCompleteを実装できますが注意点が一つだけあります。当然といえば当然ですが、HTML5に対応しているブラウザ以外は動作しません。また、iPhoneの場合にはブラウザ問わず(Safari/Chrome)動作しないとの情報がありますので注意してください。(ちなみに私のiPhone環境 iOS 13.3 では動いたのですが・・・)
それでは作っていきながら説明していきます。
最終的なページ
最終的には以下のようなページを作成します。パラメータとしてemailでサジェストするようにします。
また、Vueコンポーネント化をしてLaravelブレードから読み込むとともに、他のパラメータ(名前とか)でも簡単に使えるようにします。
動画も以下にのせておきます
事前準備
テストデータの準備
事前に実際にテストで利用するデータを準備します。以下の記事にあるテストデータの準備まで行っておいてください。
こんな感じのダミーデータが入っていればOKです。
Autocompleteの作成
Ajax用のAPIを作成
はじめにAjax用のAPIを作成します。/search/emailでアクセスした際にemailで検索したデータをJson形式で最大10件返すものを作成します。
routes/web.phpに以下を追記してルートを追加します。(合わせてページ表示するためのルート追加してます)
// ページ表示用
Route::resource('/emp', 'EmployeeController');
// API用
Route::get('/search/email', 'EmployeeController@search_email')->name('search.email');
app/Http/Controllers/EmployeeController.phpファイルに追加します。
// API用
public function search_email(Request $request)
{
$searchquery = $request->input('query');
$data = Employee::where('email', 'like', '%' . $searchquery . '%')->limit(10)->get();
return response()->json($data);
}
// ページ表示用
public function create()
{
return view('create');
}
実際にURLへアクセスして正しく値が取れるかを確認します。私の環境では以下のURLです。http://localhost:8003/search/email?query=ishi
Vue Componentファイルの作成
続いてVueコンポーネントの作成を行います。まずは以下の場所に以下のファイルを作成します。内容はコピペして下さい、あとで解説します。
resources/js/components/AutoCompleteDatalistComponent.vue
<template>
<div>
<input
type="text"
v-model="query"
@input="getSuggestionList"
Autocomplete="on"
:list="param"
placeholder="Please input..."
class="form-control"
:name="param"
/>
<datalist :id="param">
<option
v-for="result in results"
:key="result.id"
:value="result[param]"
/>
</datalist>
</div>
</template>
<script>
export default {
props: ["param", "url"],
data() {
return {
query: "",
results: []
};
},
methods: {
getSuggestionList() {
this.results = [];
if (this.query.length > 1) {
axios
.get(this.url, {
params: { query: this.query }
})
.then(Response => {
this.results = Response.data;
})
.catch(error => {
console.log(error);
});
}
}
}
};
</script>
続いて[resources/js/app.js]に作成したファイルパスを登録します。
Vue.component(
"auto-complete-datalist-component",
require("./components/AutoCompleteDatalistComponent.vue").default
);
Laravel側の準備
Laravelのビューとしてブレードファイルを作成します。/emp/createでページを表示するようにします。
resources/views/create.blade.php
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">Test AutoCoplete Datalist</div>
<div class="card-body">
<form method="POST" action="{{ route('emp.store') }}">
@csrf
<div class="form-group row">
<label for="email" class="col-md-4 col-form-label text-md-right">E-mail</label>
<div class="col-md-6">
<auto-complete-datalist-component param="email" url="/search/email" />
</div>
</div>
<div class="form-group row mb-0">
<div class="col-md-8 offset-md-4">
<button type="submit" class="btn btn-primary">
登録
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection
動作確認
それでは動作を確認してみましょう。npm run devを実施してからアクセスして下さい。以下のようにサジェスト表示がされれば成功です。
解説
Vueコンポーネントの呼び出し
create.blade.phpファイル内にある以下の行でVueコンポーネントを呼び出ししてます。また、柔軟に対応できるようにparamとurlにパラメータを渡すようにしています。
<auto-complete-datalist-component param="email" url="/search/email" />
続いてAutoCompleteDatalistComponent.vue側の解説に進みます。
Ajax動作
まずはAjaxの部分について解説します。
- axiosを使って先ほど渡したパラメータurl(search/email)に対して通信を実施(queryで検索)
- 2文字目の入力で発動(if (this.query.length > 1)の部分)、適宜変更する
- フォーム入力したタイミングでgetSuggestionListを呼び出し(@input=”getSuggestionList”の部分)
<template>
<div>
<input
type="text"
v-model="query"
@input="getSuggestionList"
Autocomplete="on"
:list="param"
placeholder="Please input..."
class="form-control"
:name="param"
/>
(省略)
methods: {
getSuggestionList() {
this.results = [];
if (this.query.length > 1) {
axios
.get(this.url, {
params: { query: this.query }
})
.then(Response => {
this.results = Response.data;
})
.catch(error => {
console.log(error);
});
}
}
}
datalistの動作
次にdatalist部分の動作です。
- inputとdatalistを紐付けるためにはinputタグのlistと、datalistタグのidが同じユニークな値である必要がある。とりあえずparamで渡してますがユニークであればOKです。
- v-forで取得した値をループして表示していきます。
- :value=”result[param]”の部分が肝です。paramにはemailが入ってます。本当はresult.emailの値を取得すればよいのですが、配列のキーを変数にしているので鍵カッコで囲みます。
<template>
<div>
<input
type="text"
v-model="query"
@input="getSuggestionList"
Autocomplete="on"
:list="param"
placeholder="Please input..."
class="form-control"
:name="param"
/>
<datalist :id="param">
<option
v-for="result in results"
:key="result.id"
:value="result[param]"
/>
</datalist>
</div>
</template>
<script>
export default {
props: ["param", "url"],
data() {
return {
query: "",
results: []
};
},
(省略)
今回はかなり簡単にHTML5のdatalistを利用してAutoCompleteを実装してみました。
幾つかブラウザなどの制約があったりするので使えないパターンもありますので、今度時間のあるときにAutocompleteのライブラリもしくは自作にチャレンジしたいと思います。
今回は以上です。
コメント