理系公務員のプログラミング日記

【Laravel9×Vue3】本の貸し出しシステム5(本の検索)

タグ:
Laravel
Vue

登録されている本の中から指定した本を検索する

本を借りたいなと思ったときに、検索窓から探したい本のキーワードを入力することで、検索結果を表示する機能を作っていきます。

検索について

この機能の実装の仕方として、2通りの方法が考えられます。

フロントエンド側で検索を行う方法

まずはフロントエンド側のみの処理で実装を行う方法を考えます。

mountedのタイミングで取得するデータをAPIdataという変数名に変更し、指定したキーワードによる検索結果を保存する変数をBooksとします。

また、データを処理するためにfilter()includes()という JavaScript のメソッドを利用します。

下記のようにこの2つを組み合わせることで、配列から検索した文字を含む要素だけを抜き出した配列を作成できます。

Array.filter((value) => value.includes('検索したい文字'));

また、検索フォームは本を追加するための入力フォームで作成したものと同じ方法で作成します。

BookList.vue

<template> <h2></h2> <div class="my-3"> <label for="search" class="form-label">本の検索</label> <input type="text" id="search" class="form-control" v-model="keyword" /> <button class="btn btn-primary" v-on:click="search">検索</button> </div> <ul v-for="Book in Books" class="list-group"> <li class="list-group-item">{{ Book.title }}</li> </ul> </template> <script> import axios from 'axios'; export default { name: 'BookList', data() { return { // data: '', APIdata: '', Books: '', keyword: '', }; }, // mounted:このBookListコンポーネントが作られたあとに1度動作する async mounted() { const url = '/api/books'; const response = await axios.get(url); console.log(response.data); // このresponse.dataは3つのオブジェクトが入った配列 // APIから取得した全データを保存 this.APIdata = response.data; // 検索機能で上書きするためにコピーを作る this.Books = response.data; }, methods: { search() { console.log(this.keyword); // 指定した文字を含む場合を作りたい const result = this.APIdata.filter((book) => book.title.includes(this.keyword)); console.log(result); // this.Booksを上書き this.Books = result; }, }, }; </script>

バックエンド側で検索を行う方法

もう一つの方法として、検索窓に入力したキーワードを axios を利用してバックエンド API に渡す方法があります。

データの量が少ない場合はとりあえず全てを受け取ってフロントエンドで表示するものを選択する上の方法で良いですが、DBを利用する場合はそのデータの量が大量にある場合がほとんどですので、基本はこちらの方法で検索を行います。

まず、分かりやすくするために、バックエンドAPIに検索キーワードを投げるコンポーネントとして、BookSearch.vueを作ります。

基本はBookList.vueのコピーですが、

  • 画面を開いたタイミングで本の一覧を見る必要はないので、mounted()は削除
  • その代わり、axios.post()を使い、バックエンドの/api/books/searchというルーティングにキーワードを送信する。

という仕様に変更しています。

BookSearch.vue

<template> <h2>検索</h2> <div class="my-3"> <label for="search" class="form-label">本の検索</label> <input type="text" id="search" class="form-control" v-model="keyword"> <button class="btn btn-primary" v-on:click="search">検索</button> </div> <ul v-for="Book in Books" class="list-group"> <li class="list-group-item">{{ Book.title }}</li> </ul> </template> <script> import axios from "axios"; export default { name: 'BookSearch', data() { return { APIdata: '', Books: '', keyword: '' } }, methods: { async search() { console.log(this.keyword); const url = "/api/books/search"; // axios.post('送信先のurl','データ') const response = await axios.post( url, { keyword: this.keyword } ); console.log(response); } } } </script>

ついでに、このコンポーネントを表示するために,vue-router周りの設定も追記しておいてください。

次に、LaravelのAPIのルーティングとコントローラーの設定を行います。

routes/api.php

// これを追記 Route::post('/books/search', [BookController::class, 'search']);

BookController.php

public function search(Request $request) { // キーワードを受け取れているか確認 // dd($request->keyword); // 教科書P246参照 $books = Book::where('title', 'like','%'.$request->keyword.'%')->get(); return $books; }