Now that we have a select input for the category, let's make it work as a filter. After selecting a category, the list should show only the posts that only belong to that category.
Vue: Watch the Selected Category
To get all the posts that belong to a category, we need to watch the selectedCategory
variable. First, we need to import watch
from the Vue.
resources/js/components/Posts/Index.vue:
<template> // ...</template> <script setup>import { onMounted, ref } from "vue"; import { onMounted, ref, watch } from "vue"; import { TailwindPagination } from 'laravel-vue-pagination';import usePosts from "@/composables/posts";import useCategories from "@/composables/categories";// ...</script>
Now using this watch()
function, we can watch the selectedCategory
variable for the changes with two values: current
and previous
.
Inside watch
we can call the getPosts
which already accepts page, but we can now also pass the current
value of the selected category.
resources/js/components/Posts/Index.vue:
<script setup>import { onMounted, ref, watch } from "vue";// ... watch(selectedCategory, (current, previous) => { getPosts(1, current)}) </script>
Composable: Accept & Pass the Category
Next, we need to modify posts Composable so that getPosts
would accept the category, which by default will be an empty string.
And the same as for the page parameter, pass the category to the API request.
resources/js/composables/posts.js:
import { ref } from 'vue' export default function usePosts() { const posts = ref({}) const getPosts = async (page = 1) => { axios.get('/api/posts?page=' + page) const getPosts = async (page = 1, category = '') => { axios.get('/api/posts?page=' + page + '&category=' + category) .then(response => { posts.value = response.data; }) } return { posts, getPosts }}
Laravel: Filter by Category
And now, back to the back-end: we need to add a conditional clause to the Eloquent query where we get the posts.
app/Http/Controllers/Api/PostController.php:
use Illuminate\Database\Eloquent\Builder; class PostController extends Controller{ public function index() { $posts = Post::with('category') ->when(request('category'), function (Builder $query) { $query->where('category_id', request('category')); }) ->paginate(10); return PostResource::collection($posts); }}
Now the filter should work.
Fixing Pagination
But wait: the pagination is broken! For example, if you would change paginate to 2 records instead of 10 and select the category which has more posts than 2, you will see the pagination. But after clicking on the second page, the category wouldn't be passed and the pagination would break.
This can be seen clearly in the developer tools network tab.
Unfortunately, the fix isn't documented, but in one of the GitHub issues the author provided the solution. We need to pass the page as a parameter.
resources/js/components/Posts/Index.vue:
<template> <div class="overflow-hidden overflow-x-auto p-6 bg-white border-gray-200"> <div class="min-w-full align-middle"> // ... <TailwindPagination :data="posts" @pagination-change-page="getPosts" class="mt-4" /> <TailwindPagination :data="posts" @pagination-change-page="page => getPosts(page, selectedCategory)" class="mt-4" /> </div> </div></template> <script setup>// ...</script>
Now the pagination with the filter works as expected.
Really straightforward example of using Vue watchers.
Hello, I would like to make filter data without any relationship between Category and Post so I have PostController and I want to pass the query request into that
$posts = Post::with('category') ->when(request('category'), function (Builder $query) { $query->where('category_id', request('category')); })->paginate(10);
I want to make multi filter data what should I do :)?
Hi, sir , when I use where with the function Builder it highlight the where clause with redline but still working what is the problem of red underline . $posts = Post::with('category')->when(request('category'), function (Builder $builder){ $builder->where('category_id', request('category')); })->paginate(3);
Hard to tell why it underlines, might be your ide