Vue.js

Vue.js+LaravelでAutoCompleteを自作する【HTML5 Datalist編】

Vue.js

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のライブラリもしくは自作にチャレンジしたいと思います。

今回は以上です。

コメント

タイトルとURLをコピーしました