LaravelLinuxVue.js

【試してみた】bootstrap-table+Laravelでのテーブル操作【最高!!】

Laravel

前の記事でTableを操作するVueライブラリを比較してみました。

Vueのテーブルライブラリについて紹介されているページは幾つかあるのですが、機能の紹介レベルだけで、実装する方法が掲載されているページは少なめだったので、実際に検証した「bootstrap-table」についてLaravelとの連携手順について紹介します。Laravelの知識としては感簡単なCRUDのシステムを作ったことがあれば大丈夫だと思います。ちなみに私はVue.js歴は1ヶ月くらいの超初心者です^_^;

現在jqueryを使っていてVue.jsなどの他のフロントエンドフレームワークに切りかえたいな〜、と思っている方は是非試してみてください。

欲しい機能、必要な機能

今回の比較する機能は、私が個人的に最低限欲しい以下の機能に絞って調査しています。

  • 検索(グローバル/列ごと)
  • ページネート(1ページの表示アイテムの切替、詳細情報表示)
  • ソート
  • 列の表示/非表示の切り替え
  • CSV or Excelなどへのエクスポート機能
  • アイテムに対して操作(Edit/Delete)をするために、任意の列を追加できるか

他にもグルーピングやチェックボックスの機能など色々ありますが、現時点では使うことないので調査してません。

最終的なページ(動画もあるよ)

テーブル操作をVueのライブラリで簡単に制御できるようなページを作成します。

前提

今回の環境は以下となります。今回は以下のDockerで環境を構築しました。ですが、普通にLaravelでVue.jsが有効の環境があれば同じ手順で構築できます。

ホストOSMacOS Catalina 10.15.3
Docker for MacEngine 19.03.5
Compose 1.25.4
Laravel # php artisan -V
Laravel Framework 6.17.1
Vue.js# npm list vue
vue@2.6.11 
NPM# npm -v
3.10.10
PHP# php -v 
PHP 7.4.2 (cli) (built: Jan 21 2020 11:35:20) ( NTS )

作成したコンテナは以下のようになってます。(私の環境は他のコンテナでポートを使っていてめちゃめちゃなので、普通に80とか8080使ってください)

$ docker-compose ps
            Name                          Command               State                 Ports               
----------------------------------------------------------------------------------------------------------
bootstrap_table                /usr/sbin/httpd -D FOREGROUND    Up      0.0.0.0:8003->80/tcp              
bootstrap_table_mysql_1        docker-entrypoint.sh mysqld      Up      0.0.0.0:33063->3306/tcp, 33060/tcp
bootstrap_table_phpmyadmin_1   /docker-entrypoint.sh apac ...   Up      0.0.0.0:8004->80/tcp 

Laravelの言語と時刻の設定

最初にLaravelの言語と時刻の設定を変更します。

config/app.phpの以下の部分を修正します。

    'timezone' => 'Asia/Tokyo',
    'locale' => 'ja',
    'fallback_locale' => 'ja',
    'faker_locale' => 'ja_JP', //<- もしこのあとのダミーデータを日本語で作成したければ変更

データ準備(Migrate)

今回は例として社員情報テーブルを想定して、employeesテーブルを作成して検証します。

また、テーブルを作成しただけでは、検証ができないので初期のダミーデータをFactoryとSeederを利用して作ってます。

まずはコンテナへ接続したらLaravel Projectフォルダへ移動して下さい。

Migration作成

まずはMigration用のファイルを作成します。

# php artisan make:migration create_employees_table
Created Migration: 2020_03_02_225321_create_employees_table

ファイルを以下のように修正します。今回はあくまで検証のためということでこれくらいの項目数で作ることにしてます。

    public function up()
    {
        Schema::create('employees', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('employee_id')->nullable(); // 社員番号
            $table->string('name')->nullable(); // 氏名
            $table->integer('year')->nullable(); // 年齢
            $table->string('email')->nullable(); // E-mail
            $table->string('dept')->nullable(); // 所属部門
            $table->date('start_day')->nullable();
            $table->timestamps();
        });
    }

確認のため、migrate:refreshを行って、テーブル作成が成功することを確認します。

# php artisan migrate:refresh
Rolling back: 2019_08_19_000000_create_failed_jobs_table
Rolled back:  2019_08_19_000000_create_failed_jobs_table (0.12 seconds)
Rolling back: 2014_10_12_100000_create_password_resets_table
Rolled back:  2014_10_12_100000_create_password_resets_table (0.03 seconds)
Rolling back: 2014_10_12_000000_create_users_table
Rolled back:  2014_10_12_000000_create_users_table (0.03 seconds)
Migrating: 2014_10_12_000000_create_users_table
Migrated:  2014_10_12_000000_create_users_table (0.13 seconds)
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated:  2014_10_12_100000_create_password_resets_table (0.07 seconds)
Migrating: 2019_08_19_000000_create_failed_jobs_table
Migrated:  2019_08_19_000000_create_failed_jobs_table (0.04 seconds)
Migrating: 2020_03_08_093112_create_employees_table
Migrated:  2020_03_08_093112_create_employees_table (0.04 seconds)

データ準備(ダミーデータの登録)

employeesテーブル作成ができましたので、次に実際のサンプルとしてのダミーデータを作成します。まずはデータを追加するためのEmployeeモデルを作成します。

Model作成

# php artisan make:model Employee

Factory作成

次にFactoryファイルを作成します。これはダミーデータを生成するためのものです。

# php artisan make:factory EmployeeFactory

database/factories/EmployeeFactory.phpを編集します。
App\Modelになっている部分をApp\Employeeに変更するのも忘れずに。

<?php

/** @var \Illuminate\Database\Eloquent\Factory $factory */

use App\Employee;
use Faker\Generator as Faker;

$factory->define(App\Employee::class, function (Faker $faker) {
    return [
      'name' => $faker->name,
      'year' => $faker->numberBetween($min = 10, $max = 99),
      'email' => $faker->email,
      'dept' => $faker->company,
      'start_day' => $faker->dateTime($max = 'now', $timezone = date_default_timezone_get()),
    ];
});

Seeder作成

Seederファイルを作成します。これは先ほどのFactoryで作成したダミーデータを登録するためのものです。

# php artisan make:seed EmployeesTableSeeder

「database/seeds/EmployeesTableSeeder.php」を編集します。今回はテーブル操作をするためにそこそこデータ量が欲しいので500件登録します。

<?php

use Illuminate\Database\Seeder;

class EmployeesTableSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        factory(App\Employee::class, 500)->create();
    }
}

最後にSeederをまとめている「database/seeds/DatabaseSeeder.php」に登録します。

<?php

use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    /**
     * Seed the application's database.
     *
     * @return void
     */
    public function run()
    {
        $this->call(EmployeesTableSeeder::class);
    }
}

Seederの実行+ダミーデータ確認

実際にSeederを実行し、ダミーデータが500件登録されることを確認します。

# php artisan db:seed
Seeding: EmployeesTableSeeder
Seeded:  EmployeesTableSeeder (1.03 seconds)
Database seeding completed successfully.

補足:Migrate:refreshとSeederを同時する場合には以下でできます。

# php artisan migrate:refresh --seed

と、いうことでまずはここまででデータの準備が完了です!

bootstrap-tableのインストール

初期データの準備が終わったら、npmコマンドでbootstrap-tableをインストールします。今回は合わせてFontAwesomeとテーブルをファイルへTableexportのJqueryプラグインもインストールします。TableexportのJqueryプラグインのインストールには事前にGitが必要でした。

# npm install bootstrap-table
# npm install @fortawesome/fontawesome-free 

# yum install -y git
# npm install tableexport.jquery.plugin

.envファイル修正

他のアプリと見分けやすいためにタイトルだけ修正します。(無理して変更しなくてもOK)

APP_NAME=[Test]Bootstrap-table

ルーティング修正

/routes/web.php に以下を追加します。
/empへアクセスした際にこの後作成するEmpoyeeコントローラのindexメソッドへ処理を投げます。

routes/web.php

// ↓追加
use App\Employee;

Route::get('/', function () {
    return view('welcome');
});
Auth::routes();
Route::get('/home', 'HomeController@index')->name('home');

// ↓追加
Route::get('/emp', 'EmployeeController@index')->name('emp');

コントローラー作成

コントローラを作成します。

# php artisan make:controller --resource EmployeeController

以下のように修正します。employeesテーブルの全データをempのビューへを渡してます。

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Employee;

class EmployeeController extends Controller
{
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        $models = Employee::all();
        return view('emp', ['models'=>$models]);
    }
}

ビューの作成

次にビューを作成します。ビューの作成にはコマンドがないので手で以下のファイルを作成します。ここでコンポーネントへ対してブレード側から先ほどの全てのemployeesデータ($models)をjsonで渡すようにしています。
resources/views/emp.blade.php

@extends('layouts.app')

@section('content')
<div class="container">
    この下にコンポーネントが表示されます
    <bootstrap-table-component models='@json($models)' />
</div>
@endsection

念のため、ページが開けることを確認します。

Vueの設定

次にいよいよVue側の設定を行います。

Vue Componentファイルの作成

resources/js/components/BootstrapTableComponent.vueのファイルを新規で作成して以下のように修正します。

たったのこれだけでもかなりの機能があります!myOptionsの部分に追記すると追加で機能を利用できるようになります。今回は以下の機能を有効化してます。

  • グローバル検索
  • ページネーション
  • 列ごとの表示/非表示の切替え
  • 列ごとのフィルター
  • 印刷機能
  • データExport機能
    • フィルタ条件は生かした上で全件Export(1ページ内で表示されているアイテムだけでなく)

他にも機能は山のようにあります。是非公式ドキュメントを参照してみてください。

Bootstrap Table · An extended table to the integration with some of the most widely used CSS frameworks. (Supports Bootstrap, Semantic UI, Bulma, Material Design, Foundation)
An extended table to the integration with some of the most widely used CSS frameworks. (Supports Bootstrap, Semantic UI, Bulma, Material Design, Foundation)

<template>
    <div>
        <div id="toolbar">
            <a href="create" class="btn btn-primary"><i class="fas fa-plus-circle"></i> 新規登録</a>
        </div>
        <bootstrap-table :data="myData" :options="myOptions" :columns="myColumns" />
    </div>
</template>

<script>
    import BootstrapTable from 'bootstrap-table/dist/bootstrap-table-vue.min.js'
    export default {
        props: ['models'],
        components: {
            'bootstrap-table': BootstrapTable
        },
        data () {
            return {
                mySelections: [],
                myData: [],
                myOptions: {
                    search: true, 
                    pagination: true,
                    paginationPreText: 'Previous',
                    paginationNextText: 'Next',
                    pageSize: 5,
                    pageList: [5, 10, 25, 50, 100, 200, "All"],
                    showColumns: true,
                    showPrint: true,
                    showExport: true,
                    exportDataType: "all",
                    filterControl: true,
                    toolbar: '#toolbar',
                    clickToSelect: true,
                    idField: 'id',
                    selectItemName: 'id',
                },
                myColumns: [
                    { field: 'id', title: 'ID', sortable: true },
                    { field: 'name', title: '名前', sortable: true, filterControl: 'input' },
                    { field: 'employee_id', title: '社員番号', sortable: true, filterControl: 'input' },
                    { field: 'year', title: '年齢', sortable: true, filterControl: 'select'},
                    { field: 'email', title: 'E-Mail', sortable: true, filterControl: 'input'},
                    { field: 'dept', title: '部署', sortable: true, filterControl: 'select'},
                    {
                        field: 'action',
                        title: 'Actions',
                        align: 'center',
                        width: '140px',
                        clickToSelect: false,
                        formatter: function (e, value, row){
                            return '<button class="btn btn-sm btn-info mr-1 show"><i class="fas fa-eye"></i></button><button class="btn btn-sm btn-warning mr-1 edit"><i class="fas fa-edit"></i></button><button class="btn btn-sm btn-danger mr-1 destroy"><i class="fas fa-trash"></i></button>'
                        },
                        events: {
                            'click .show': function (e, value, row){
                                alert("詳細ページへ移動");
                                //return window.location.assign('/emp/'+row.id)
                            },
                            'click .edit': function (e, value, row){
                                alert("編集ページへ移動");
                                //return window.location.assign('/emp/'+row.id+'/edit')
                            },
                            'click .destroy': function (e, value, row){
                                alert("アイテム削除へ移動");
                                //axios.delete('/emp/'+row.id, {
                                //    id: row.id
                                //})
                                //return window.location.replace('/emp')
                            },
                        }
                    }
                ]
            }
        },
        created () {
            this.myData = JSON.parse(this.models)
        },
        methods: {
        }
    }
</script>

app.jsの修正

最後に「resources/js/app.js」へ利用するライブラリのインポートと先ほど作ったVue Component(bootstrap-table-component)を登録します。

require('./bootstrap');

window.Vue = require('vue');

require('@fortawesome/fontawesome-free/js/all.js');
require('bootstrap-table/dist/bootstrap-table.min.css');
require('bootstrap-table/dist/bootstrap-table.js');

require('tableexport.jquery.plugin');
require('bootstrap-table/dist/extensions/export/bootstrap-table-export.min.js');
require('bootstrap-table/dist/extensions/print/bootstrap-table-print.min.js');

require('bootstrap-table/dist/extensions/filter-control/bootstrap-table-filter-control.min.css');
require('bootstrap-table/dist/extensions/filter-control/bootstrap-table-filter-control.min.js');

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

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

動作確認

修正したら再度コンパイルしてページ動作を確認してみます。

# npm run dev

ページが以下のように表示されることを確認します。グローバル検索や、ソートや列ごとの検索、ページネート、ファイルエクスポートなどが利用できることができます。

FontAwesomeもインストールしているので、アイコンも表示されるはずです。さらにアイテムに対してのアクション(Show/Edit/Delete)ができる列も表示できてます。アクションのボタンはクリックするとアラートだけ表示するようにしています。

現時点ではテーブルの表示だけのため、新規登録やアクション系の操作については作り込んでいませんが、これをベースとして容易に追加することができるかと思います。

まとめ

今回検証した「bootstrap-table(+tableexport)」を使うことで簡単にテーブル操作をすることができました!!

テーブル操作の処理をLaravel側で実装しようとすると、検索機能を実装するだけでもかなりの時間がかかる作業になりますが、Vue.jsのライブラリに操作を任せれることで、時間を大幅に短縮することができますね!!

今回のリポジトリについてはgithubに上げておきますので参考にしてください。

GitHub - gogoloon/try_bootstrap_table: Tutorial bootstrap-table with vue.js and Laravel
Tutorial bootstrap-table with vue.js and Laravel. Contribute to gogoloon/try_bootstrap_table development by creating an account on GitHub.

以上となります。

コメント