في أي لوحة تحكم أو موقع لا بد من توفر خاصية البحث، ومن أجل تجربة مستخدم أفضل يفضل أن يكون البحث بشكل مباشر عند كتابة أي حرف في خانة البحث ودون الضغط على زر بحث.
في هذا المقال وضمن سلسة تعلم VueJs + Laravel سيتم شرح ذلك.
في الملف resources/js/components/Posts/index.vue نضيف textField مخصص للبحث
<div class="col-6"> <input v-model="title_search" type="text" class="form-control" placeholder="Search For Title"> </div>
فيصبح لدينا الشكل التالي
توضيح
data() { return { posts: {}, categories: {}, category_id: '', sort_field: 'created_at', sort_direction: 'desc', title_search:'', } },
watch: { category_id(value) { this.getResults() }, title_search(){ this.getResults(); } },
كما نرى أن الدالة title_search ستراقب أي تغير في textField وعند حدوث أي تغيير فإنها سوف تستدعي الدالة this.getResults الموجوده في methods
getResults(page = 1) { axios.get('/api/posts?page=' + page + '&category_id=' + this.category_id + '&sort_field=' + this.sort_field + '&sort_direction=' + this.sort_direction + '&title_search=' + this.title_search) .then(response => { this.posts = response.data; }); },
كما نلاحظ في الدالة getResults فإنه سيتم إرسال متغير جديد بإسم title_search وهو ما سيتم إستقباله في لارافيل.
في الدالة index سيتم إستخدام when
public function index() { $sortField=\request('sort_field', 'created_at'); if(!in_array($sortField,['id','title','body','created_at'])){ $sortField = 'created_at'; } $sortDirection=\request('sort_direction', 'desc'); if(!in_array($sortDirection,['asc','desc'])){ $sortDirection = 'desc'; } $posts=Post::when(request('category_id','') !='',function ($q){ $q->where('category_id',request('category_id')); })->when(request('title_search','') !='',function ($q){ $q->where('title','LIKE','%'.request('title_search').'%'); }) ->orderBy($sortField,$sortDirection) ->paginate(10); return PostResource::collection($posts); }
صفحة الكود بالكامل
<template> <div class="container"> <br/> <div class="row"> <div class="col-6"> <select v-model="category_id" class="form-control"> <option value="">--Choose Category--</option> <option v-for="category in categories" :value="category.id"> {{ category.name }} </option> </select> </div> <div class="col-6"> <input v-model="title_search" type="text" class="form-control" placeholder="Search For Title"> </div> </div> <br/> <table class="table"> <thead> <tr> <th scope="col"> <a href="#" @click.prevent="change_sort('id')">id</a> <span :class="this.sort_field === 'id' && this.sort_direction === 'asc' ? 'text-dark' : 'text-black-50'">↑</span> <span :class="this.sort_field === 'id' && this.sort_direction === 'desc' ? 'text-dark' : 'text-black-50'">↓</span> </th> <th scope="col"> <a href="#" @click.prevent="change_sort('title')">title</a> <span :class="this.sort_field === 'title' && this.sort_direction === 'asc' ? 'text-dark' : 'text-black-50'">↑</span> <span :class="this.sort_field === 'title' && this.sort_direction === 'desc' ? 'text-dark' : 'text-black-50'">↓</span> </th> <th scope="col"> <a href="#" @click.prevent="change_sort('body')">body</a> <span :class="this.sort_field === 'body' && this.sort_direction === 'asc' ? 'text-dark' : 'text-black-50'">↑</span> <span :class="this.sort_field === 'body' && this.sort_direction === 'desc' ? 'text-dark' : 'text-black-50'">↓</span> </th> <th scope="col"> <a href="#" @click.prevent="change_sort('created_at')">created_at</a> <span :class="this.sort_field === 'created_at' && this.sort_direction === 'asc' ? 'text-dark' : 'text-black-50'">↑</span> <span :class="this.sort_field === 'created_at' && this.sort_direction === 'desc' ? 'text-dark' : 'text-black-50'">↓</span> </th> <th>Edit</th> <th>Delete</th> </tr> </thead> <tbody> <tr v-for="post in posts.data" :key="post.id"> <td>{{ post.id }}</td> <td>{{ post.title }}</td> <td>{{ post.body.substring(0, 30) }}</td> <td>{{ post.created_at }}</td> <td> <router-link :to="{ name:'posts.edit', params:{ id:post.id} }" class="btn btn-success">Edit </router-link> </td> <td> <button @click="delete_post(post.id)" class="btn btn-danger">Delete</button> </td> </tr> </tbody> </table> <pagination :data="posts" @pagination-change-page="getResults"></pagination> </div> </template> <script> export default { data() { return { posts: {}, categories: {}, category_id: '', sort_field: 'created_at', sort_direction: 'desc', title_search:'', } }, mounted() { axios.get('/api/category') .then(response => { this.categories = response.data.data; }); this.getResults(); }, watch: { category_id(value) { this.getResults() }, title_search(){ this.getResults(); } }, methods: { change_sort(field) { if (this.sort_field === field) { this.sort_direction = this.sort_direction === 'asc' ? 'desc' : 'asc'; } else { this.sort_field = field; this.sort_direction = 'asc'; } this.getResults(); }, getResults(page = 1) { axios.get('/api/posts?page=' + page + '&category_id=' + this.category_id + '&sort_field=' + this.sort_field + '&sort_direction=' + this.sort_direction + '&title_search=' + this.title_search) .then(response => { this.posts = response.data; }); }, delete_post(id) { swal({ title: "Are Your Shure You Want to Delete The Post ?", icon: "warning", buttons: ["No", "Yes"], dangerMode: true, }) .then((willDelete) => { if (willDelete) { axios.delete('/api/posts/' + id).then(response => { swal("Post Deleted Successfully"); this.getResults() }) } else { swal("Post Not Deleted"); } }).catch(error => { swal({ icon: 'error', title: 'Error Happened' }); }); } } } </script>