Laravel を利用した CRUD の SPA 作成 3 検索画面作成編
Vue.js を Laravel で使用する準備
まずは Vue.js を Laravel で使用する準備を行います。「package.json」に下記を追加します
"devDependencies": {
"axios": "^0.19",
"cross-env": "^5.1",
"laravel-mix": "^4.0.7",
"lodash": "^4.17.13",
"resolve-url-loader": "^2.3.1",
"sass": "^1.15.2",
"sass-loader": "^7.1.0",
"vue": "^2.5.7",
"vue-router": "^2.3.0",
"bootstrap": "^4.0.0"
}
それでは ホスト(私の場合はWindows) で「npm」コマンドを実行します。
なお、Node.js をインストールしていない場合は、ここなどが参考になると思います。
Vagrant の Linux OS でもできるのですが、たいていはシンボリックリンクうんぬんで失敗します。このためホストOS で行うのがおすすめです。
npm install
それでは Laravel のほうで、サーバーから返却される HTML を設定します。
<!DOCTYPE html>
<html lang="{{ app()->getLocale() }}">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>SPA</title>
<link href="{{ asset('css/app.css') }}" rel="stylesheet">
</head>
<body>
<div id="app">
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="container">
<h2>SPA</h2>
</div>
</nav>
<main id="app" class="container" style="padding-top: 60px;">
<router-view></router-view>
</main>
</div>
<script src="{{ asset('js/app.js') }}"></script>
</body>
</html>
Route::get('{any}', function () {
return view('spa');
})->where('any','.*');
デザイン面をちょっと整えるために「bootstrap」をインストールします。
@import "~bootstrap/scss/bootstrap";
npm run dev
それで「http://homestead.test/」にアクセスするとページが表示されます。
長かった。ここまで本当に。だがまだ検索のロジックが残っている、俺たちの戦いはここからだ ~ 完
検索ロジック作成 Laravel側
ということで、Laravel での検索に必要な機能を実装してきます。
コントローラー等は PHP がインストールされているゲストOS(Vagrant)で実行したほうが良いです。
vagrant ssh
cd /code/spa
php artisan make:controller ItemsController --resource
作成されたコントローラーは DBに格納されている Item を返却されるようコードを追記します。
public function index(Request $request) {
$itemName = $request->input('item_name', '');
$items = \App\Item::where('item_name', 'LIKE', "%$itemName%")->get();
return response($items);
}
Route::get('items', 'ItemsController@index');
http://homestead.test/api/items
↑全件が Json で返却される
http://homestead.test/api/items?itemName=%E3%81%82
↑引数に itemName をつければあいまい検索ができる
検索ロジック作成 Vue.js 側
まずは、変更があるたびごにょごにょやってくれる、素晴らしいコマンドをホストOSで実行します。
npm run watch-poll
それでは Vue のひな形を作ります。
<template>
<div>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text">検索</span>
</div>
<input type="text" class="form-control" v-on:blur="fetchItems" v-model="searchText">
</div>
<table class="table table-bordered table-dark">
<thead>
<tr>
<th scope="col">Id</th>
<th scope="col">名前</th>
</tr>
</thead>
<tbody>
<tr v-for="item in items">
<th scope="row">{{ item.id }}</th>
<td>{{ item.item_name }}</td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
export default {
created() {
},
data() {
return {
items: [],
searchText: '',
message: null
}
},
methods: {
}
}
</script>
import Vue from 'vue'
import VueRouter from 'vue-router'
import itmeIndex from './components/items/Index.vue'
require('./bootstrap');
Vue.use(VueRouter)
const router = new VueRouter({
mode: 'history',
routes: [
{ path: '/', component: itmeIndex }
]
})
const app = new Vue({
router,
el: '#app'
})
「/」(ルートパス)でアクセスした場合「Index.vue」を使用するようルーティングします。
テンプレートは「spa.blade.php」の「<router-view></router-view>」に描写されることになります。
これでいったんアクセスします。
<template>
<div>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text">検索</span>
</div>
<input type="text" class="form-control" v-on:blur="fetchItems" v-model="searchText">
</div>
<table class="table table-bordered table-dark">
<thead>
<tr>
<th scope="col">Id</th>
<th scope="col">名前</th>
</tr>
</thead>
<tbody>
<tr v-for="item in items">
<th scope="row">{{ item.id }}</th>
<td>{{ item.item_name }}</td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
export default {
created() {
this.fetchItems()
},
data() {
return {
items: [],
searchText: '',
message: null
}
},
methods: {
fetchItems() {
axios.get('/api/items', {params: {item_name:this.searchText}}).then((res)=>{
this.items = res.data
})
}
}
}
</script>
テンプレート
「v-on:blur」にてフォーカスアウト時にイベントを発火させ検索しに行くよう設定します。
「v-for」取得したデータをループさせて一覧表示します。
スクリプト
まず最初にcreated で初期化時に初期データ取得をする関数を呼びます。
axios で Laravel に問い合わせて結果を格納します。
ということで、検索画面が完成しました。
ディスカッション
コメント一覧
まだ、コメントがありません