Laravelで選択候補つきのセレクトボックス「Vue Select」を使う

こんにちは❗フリーランス・エンジニアの 九保すこひ です。

さてさて、私は運がいいことにいつもご配慮をいただけるクライアント様方からご依頼をいただいています。

そして、ご依頼をいただいた方々にはできる限り

  • おっ、これ便利だね❗
  • これで楽になるよ😊

と感じてもらえたら、と考えています。

つまり、「ユーザビリティ」の部分ですが、先日リサーチしていると、とても便利に使えるVueコンポーネント「Vue Select」を発見しました。

機能としては、jQuery select2 のように「入力候補がついているセレクトボックス」で、とてもシンプルに使えるのが特徴です。

(実は似たものは発見してたんですが、毎回「なんだか複雑だな・・・だったら、時間ができたら自分でつくろうかな😥」なんて考えてました)

ということで、今回は「Vue Select」をLaravelで使う方法、そして各種設定方法をご紹介します。

ぜひ皆さんのお役にたてると嬉しいです😊✨

まずは、デモページで体験してみてください。

「これまでは、Vue & select2
を連携させてました」

開発環境: Laravel 7.x(デモページは 5.8)、vue-select 3.10.7

Vue Selectをインストールする

まずはnpmを使ってVue Selectをインストールします。

npm install vue-select

※ なお、「npmは難しいからヤダ😭」という方はCDNを使うバージョンをご覧ください。

webpackでコンパイルする

続いて、webpackを使ってVue Selectをコンパイルします。

Laravelにはwebpackを使う環境が整っていますので、まずnpm installを実行してから以降の手順を試してみてください。

JavaScriptの設定

では、まずJavaScriptの設定です。
以下のようにコードを変更してください。

/resources/js/app.js

// 省略

require('./bootstrap');

window.Vue = require('vue');
Vue.component('v-select', require('vue-select').default); // 👈 追加

// 👇 不要な部分はコメントアウト

// const files = require.context('./', true, /\.vue$/i)
// files.keys().map(key => Vue.component(key.split('/').pop().split('.')[0], files(key).default))

// Vue.component('example-component', require('./components/ExampleComponent.vue').default);

// const app = new Vue({
//     el: '#app',
// });

CSSの設定

続いてCSSです。
同じくvue-select.scssを呼び出せるようにコードを追加してください。

/resources/sass/app.scss

// Fonts
@import url('https://fonts.googleapis.com/css?family=Nunito');

// Variables
@import 'variables';

// Bootstrap
@import '~bootstrap/scss/bootstrap';

// Vue Select
@import 'vue-select/src/scss/vue-select.scss'; // 👈 追加

webpackでコンパイルする

コードの準備が完了したら、以下のコマンドでコンパイル(トランスパイル)をしましょう。

npm run dev

もしくは、本番環境用のこちら。

npm run production

これで、JavaScriptCSSはそれぞれ以下のファイルにまとめられました。

  • /public/js/app.js
  • /public/css/app.css

使い方

ではVue Selectの実際の使い方です。

基本的な使い方

基本的にはタグを用意して選択肢を:optionsに入れるだけでOKです。

<html>
<head>
    <link rel="stylesheet" href="{{ mix('css/app.css') }}">
</head>
<body>
<div id="app" class="p-3">
    <h1>Laravel + Vue Select サンプル</h1>
        <div class="row">
            <div class="col-3">
                <v-select :options="options" v-model="name"></v-select>
            </div>
        </div>
        <div class="pt-2">
            選択されているデータ: <span v-text="name"></span>
        </div>
    </div>
    <script src="{{ mix('js/app.js') }}"></script>
    <script>

        new Vue({
            el: '#app',
            data: {
                name: '',
                options: [
                    '太郎',
                    '次郎',
                    '三郎',
                    '花子'
                ]
            }
        });

    </script>
</body>
</html>

もちろんv-modelをセットすればリアルタイム・バインディングに対応してくれます。

デモページはこちら。

選択肢にコレクションを使う場合

次に選択肢を単なる配列ではなく、コレクション(オブジェクトの配列)を使う場合です。

Vue Selectでは、labelが選択肢として表示されるキーになります。

new Vue({
    el: '#app',
    data: {
        name: '',
        // 👇 label をセットする
        options: [
            { id: 1, label: '太郎' },
            { id: 2, label: '次郎' },
            { id: 3, label: '三郎' },
            { id: 4, label: '花子' },
        ]
    }
});

ちなみに選択肢が選ばれた場合、変数の中身は次のようになります。

デモページはこちら。

なお、もし選択されたデータを絞り込みたい場合は:reduceを使ってください。

<v-select
    label="name"
    :options="options"
    :reduce="user => user.id"
    v-model="name"></v-select>

実行結果はこうなります。

選択肢のコレクションが独自のキーの場合

選択肢のコレクションにlabelが入っていなくても、代わりに任意のデータを表示させることができます。

例えば、DBからデータ取得する場合のデータ構造は以下のようになっています。

new Vue({
    el: '#app',
    data: {
        name: '',
        options: [
            { id: 1, name: '太郎' },
            { id: 2, name: '次郎' },
            { id: 3, name: '三郎' },
            { id: 4, name: '花子' },
        ]
    }
});

この場合は、タグの中にlabel="*****"というプロパティを追加してあげるだけで選択肢のキーを変更することができます。

<!-- 👇 options.name の内容を表示 -->
<v-select label="name" :options="options" v-model="name"></v-select>

先ほどと同じく、実際に選択されたときは該当するオブジェクトが変数として使われます。

デモページはこちら。

CDNでもっと簡単に使いたい場合

もしnpmを使わずにVue Selectを使いたい場合は次のようにcdnが使えます。

<html>
<head>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css">
    <link rel="stylesheet" href="https://unpkg.com/vue-select@latest/dist/vue-select.css">
</head>
<body>
<div id="app" class="p-3">
    <h1>CDNを使った Vue Select サンプル</h1>
        <div class="row">
            <div class="col-3">
                <v-select :options="options" v-model="name"></v-select>
            </div>
        </div>
        <div class="pt-2">
            選択されているデータ: <span v-text="name"></span>
        </div>
    </div>
    <script src="https://unpkg.com/vue@latest"></script>
    <script src="https://unpkg.com/vue-select@latest"></script>
    <script>

        // 👇 ここでコンポーネント有効化
        Vue.component('v-select', VueSelect.VueSelect);

        new Vue({
            el: '#app',
            data: {
                name: '',
                options: [
                    '太郎',
                    '次郎',
                    '三郎',
                    '花子'
                ]
            }
        });

    </script>
</body>
</html>

デモページはこちら

各種設定方法

Vue Selectはシンプルに使えるだけでなく、色々な設定をするとさらに便利になりますので特におすすめのものをご紹介します。

複数選択できるようにする

なんとVue Selectは複数選択に対応しています。
しかもタグにmultipleをつけるだけで以下のようになります。

コードはこうなります。

<v-select multiple label="name" :options="options" v-model="names"></v-select>
new Vue({
    el: '#app',
    data: {
        names: [], // 👈 変更
        options: [
            '太郎',
            '次郎',
            '三郎',
            '花子',
        ]
    }
});

※複数選択なので、namesとして初期値を配列に変更しています。

さらに、multipleに加えて次のプロパティを追加するとさらに機能を強力にできますよ!

  • taggable: 選択肢には入っていないものも入力でセットできるようになる
  • push-tags: taggableで入力されたものが自動で選択肢に入る

アイコンを変更する

セレクトボックスに使われるアイコンを変更することができます。

/resources/js/app.js

let vSelect = require('vue-select').default;
vSelect.props.components.default = () => ({
    Deselect: {
        render: createElement => createElement('span', '✕'),
    },
    OpenIndicator: {
        render: createElement => createElement('span', '▼'),
    },
});
Vue.component('v-select', vSelect);

※CDNバージョンは直接セットしてください。

これを実行するとこのように変更になります。

日本語化

Vue Selectは初期状態では選択肢が見つからないとき「Sorry, no matching options.」と英語でメッセージを表示しますが、これを日本語化するには以下のようにします。

<v-select :options="options" v-model="name">
    <template #no-options>
        選択肢が見つかりません。
    </template>
</v-select>

これを実行するとこうなります。

独自の選択肢をつくる

独自の形式で選択肢を表示したい場合には、#option={ *** }を使います。

<v-select :options="options" v-model="name">
    <!-- 👇 独自の選択肢をつくる -->
    <template #option="{ id, name }">
        <span v-text="name"></span> さん(ID: <span v-text="id"></span>)
    </template>
</v-select>
new Vue({
    el: '#app',
    data: {
        name: '',
        options: [
            { id: 1, name: '太郎' },
            { id: 2, name: '次郎' },
            { id: 3, name: '三郎' },
            { id: 4, name: '花子' },
        ]
    }
});

これを実行するとこうなります。

Ajaxでリアルタイム検索して選択肢を取得する

例えば、Laravelで作成した以下のユーザーから選択肢を取得してみましょう。

まずタグに用意するのが@search="*****"です。

これは、セレクトボックスが変更されると設定したメソッドを実行してくれるイベントです。

以下の例では、getusers()が実行されることになります。

<v-select
    label="name" 
    :options="options"
    @search="getUsers"
    v-model="name"></v-select>

次にAjax部分です。
今回はaxiosで実行します。

new Vue({
    el: '#app',
    data: {
        name: '',
        options: []
    },
    methods: {
        getUsers(search, loading) {

            loading(true); // ローダー(くるくる回るアイコン)を表示開始

            const url = '/search_users?keyword='+ search;
            axios.get(url)
                .then(response => {

                    this.options = response.data;

                })
                .catch(error => {

                    // エラーがあった場合の処理

                })
                .finally(() => {

                    loading(false); // ローダーを消す

                });

        }
    }
});

そして、最後にLaravelDBからデータを取得するのは次のようになります。(ルート部分は省略しています)

<?php

// 省略

class HomeController extends Controller
{
    public function search_users(Request $request) {

        return \App\User::where('name', 'LIKE', '%'. $request->keyword .'%')
            ->take(10) // 選択肢が多くなりすぎないように最大件数を決めておくといいかもしれません
            ->get();

    }

// 省略

これを実行するとこうなります。

おわりに

ということで、今回はユーザビリティを向上させることができるVueコンポーネント「Vue Select」をご紹介しました。

基本的な使い方をするだけでしたら、とてもシンプルなコードで実装できるのできっと使いやすいと思います。開発をされているJeff Sagalさんには感謝あるのみですね😊✨

ぜひ皆さんもこのパッケージを活用して使いやすいシステムを開発してみてくださいね。

ではでは〜❗

「ついに田舎の我が町にも
ストリートピアノが設置されたので
用もないのに出かけてきました😊👍」

今回の技術をつかった開発のご依頼、お待ちしております😊✨ お問い合わせ また、個人レッスンや、わかりにくい部分がありましたらからお気軽にご連絡ください。 どうぞよろしくお願いいたします!
このエントリーをはてなブックマークに追加       follow us in feedly