勉強も兼ねてLaravel8系とVue.jsで注文一覧ページを構築しています(管理画面)
Laravelはapiとして、SPAで構築しています。
注文番号(一部)を入力して検索ボタンをクリックして結果を表示するところで、以下のエラーが出ます。
[Vue warn]: Error in render: "TypeError: Cannot read properties of undefined (reading 'length')"
以下コードになります。
■OrderList.vue テーブル部分省略
<template> <div> <div class="content-header"> <div class="container-fluid"> <div class="row mb-2"> <div class="col-sm-6"> <h1 class="m-0 text-dark">注文一覧</h1> </div> <div class="col-sm-6"> <ol class="breadcrumb float-sm-right"> <li class="breadcrumb-item"><a href=/admin/>Home</a></li> <li class="breadcrumb-item active">Order</li> </ol> </div> </div> <order-search @aaa="search($event)" @set_order_id="setSearchOrderId($event)" @set_name="setSearchName($event)" > </order-search> <span class=""> <button type="button" class="btn bg-gradient-primary btn-xs download_btn" @click="listDownload">Download</button> </span> </div> </div> <section class="content"> <div class="container-fluid"> <div class="card"> <div class="table-responsive mb-4 p-4"> <paginate :page-count="getPageCount" :page-range="3" :margin-pages="2" :click-handler="clickCallback" :prev-text="'‹'" :next-text="'›'" :container-class="'pagination mb-4 float-left'" :page-class="'page-item'" :page-link-class="'page-link'" :prev-link-class="'page-link'" :next-link-class="'page-link'"> </paginate> <table class="table table-hover text-sm" id="tbl_product"> <thead> <tr> <th></th> <th>注文番号</th> </tr> </thead> <tbody> <tr v-for="(order, index) in getItems" :key="index"> <td> <router-link v-bind:to="{name: 'order.detail', params: {order_id: order.id}}"> <button type="button" class="btn btn-pill btn-block btn-warning">詳細</button> </router-link> </td> <td>{{ order.order_id }}</td> </tr> </tbody> </table> </div> </div> </div> </section> </div> </template> <script> import OrderSearch from './OrderSearch.vue'; import Util from '../util'; export default { names: 'OrderList', components: { 'order-search': OrderSearch, }, props: { csrf: { type: String, }, }, data() { return { orders: [], search_order_id: "", search_name: "", names: [ {label: "管理者", value: "管理者"}, {label: "一般", value: "一般"}, ], //pagenateで追加 par_page: 10, current_page: 1 } }, mounted() { axios.get('/api/orders') .then((response) => { this.orders = response.data; }); }, computed: { getItems: function() { //pagenateで追加 let current = this.current_page * this.par_page; let start = current - this.par_page; return this.orders.slice(start, current); }, getPageCount: function() { //pagenateで追加 console.log("getPageCount:" + this.orders.length); return Math.ceil(this.orders.length / this.par_page); }, getTotalPrice: function(price, buy_num) { return price * buy_num; } }, methods: { search: function(value) { const url = '/api/orders_search'; let params = new FormData(); params.append('search_order_id', value.id ?? ''); params.append('search_name', value.name ?? ''); console.log('ajax前のparams:' + params); axios.post(url, params) .then(response => { console.log("検索結果:" + response); this.orders = response.data.data; }) .catch(error => { console.log(error); }); }, setSearchOrderId: function(value) { this.search_order_id = value.id; }, setSearchName: function(value) { this.search_name = value.name; }, clickCallback: function (page_num) { //pagenateで追加 this.current_page = Number(page_num); }, }, mixins: [Util] } </script>
■OrderSearch.vue 検索部分のvueコンポーネント
<template> <div class="mb-2"> <form method="post" onsubmit="return false;"> <div class="form-group row mt-4"> <div class="col-md-3"> <label class="col-form-label text-sm">▼注文番号{{ search_order_id }}</label> <div class=""> <input type="text" class="form-control text-sm form-control-sm" maxlength="30" v-model="search_order_id" @input="$emit('set_order_id', {id:search_order_id})"> </div> </div> <div class="col-md-3"> <label class="col-form-label text-sm">▼名前{{ search_name }}</label> <div class=""> <select class="form-control text-sm form-control-sm" v-model="search_name" @change="$emit('set_name', {name:search_name})"> <option class="text-sm" value="">-----</option> <option v-for="(name, index) in names" v-bind:value="name.value" :key="index"> {{ name.label }} </option> </select> </div> </div> </div> <button class="btn btn-outline-info btn-flat" @click="$emit('aaa', {id:search_order_id, name:search_name})" >検索</button> </form> </div> </template> <script> export default{ props: { }, data() { return { search_order_id: "", search_name: "", names: [ {label: "管理者", value: "管理者"}, {label: "一般", value: "一般"}, ] } }, } </script>
■Controller部分 OrderController function searchのみ抜粋
public function search(Request $request) { $search_order_id = $request->search_order_id; $search_name = $request->search_name; $query = Order::query(); if(!empty($search_order_id)) { $query->where('order_id', 'like', '%'.$search_order_id.'%'); } /* if(!empty($search_name)) { $query->where('name', $search_name); } */ //$orders = $query->paginate(15); //★これだと成功。エラーにならない $orders = $query->get(); //エラーになる //dd($orders); return response()->json($orders); }
Controllerで$ordersを求める部分を、
$orders = $query->paginate(15);
にするとエラーになりませんでした。
しかし、どちらもdd($orders);
で検索結果を出力すると、1件と正しく取得されていました。
なぜ$orders = $query->get();
だとエラーになるのか、それとも別のところに原因があるのか、ページネーションはVueで行っているので、コントローラー側でpaginateをやりたくないのですが、いい方法などありましたらご教示いただけますと幸いです。
あなたの回答
tips
プレビュー