To handle multiple paginators on the same page in a Laravel application using Inertia.js and Vue, you need to ensure that each paginator can independently manage its state without interfering with the other. Here’s a step-by-step solution:
-
Backend (Laravel) Setup:
- Ensure that each paginator has its own pagination state and data.
- Use query parameters to differentiate between the paginators.
-
Frontend (Vue) Setup:
- Create separate components for each paginator.
- Use Vue's reactive properties to manage the pagination state.
Backend (Laravel) Setup
Modify your controller to handle pagination for both reviews and gallery separately:
public function show(Company $company, Request $request)
{
$reviewsPage = $request->query('reviews_page', 1);
$galleryPage = $request->query('gallery_page', 1);
return Inertia::render('Company/Show', [
'reviews' => fn () => CompanyReviewResource::collection(
$company->reviews()->paginate(5, ['*'], 'reviews_page', $reviewsPage)
),
'gallery' => fn () => GalleryResource::collection(
$company->media()->where('collection_name', 'gallery')->paginate(5, ['*'], 'gallery_page', $galleryPage)
->through(fn ($media) => [
'thumb' => $media->getUrl('thumb'),
'image' => $media->getUrl('gallery')
])
),
]);
}
Frontend (Vue) Setup
Create separate components for reviews and gallery pagination. Here’s an example of how you can structure your Vue components:
ReviewsPagination.vue
<template>
<nav class="d-flex justify-content-end">
<BPagination
:per-page="reviews.meta.per_page"
:total-rows="reviews.meta.total"
first-number
last-number
@change="changePage"
/>
</nav>
</template>
<script setup>
import { ref } from 'vue';
import { usePage } from '@inertiajs/inertia-vue3';
const { props } = usePage();
const reviews = ref(props.value.reviews);
const changePage = (page) => {
Inertia.get(route('company.show', { company: props.value.company.id, reviews_page: page }), {}, { preserveState: true });
};
</script>
GalleryPagination.vue
<template>
<nav class="d-flex justify-content-end">
<BPagination
:per-page="gallery.meta.per_page"
:total-rows="gallery.meta.total"
first-number
last-number
@change="changePage"
/>
</nav>
</template>
<script setup>
import { ref } from 'vue';
import { usePage } from '@inertiajs/inertia-vue3';
const { props } = usePage();
const gallery = ref(props.value.gallery);
const changePage = (page) => {
Inertia.get(route('company.show', { company: props.value.company.id, gallery_page: page }), {}, { preserveState: true });
};
</script>
CompanyShow.vue
Finally, include these components in your main CompanyShow.vue component:
<template>
<div>
<h1>Company Details</h1>
<!-- Other company details -->
<h2>Reviews</h2>
<ReviewsPagination />
<h2>Gallery</h2>
<GalleryPagination />
</div>
</template>
<script setup>
import ReviewsPagination from './ReviewsPagination.vue';
import GalleryPagination from './GalleryPagination.vue';
</script>
Explanation
-
Backend:
- The controller now handles pagination for
reviews and gallery separately using query parameters (reviews_page and gallery_page).
-
Frontend:
- Separate components (
ReviewsPagination.vue and GalleryPagination.vue) are created for each paginator.
- Each component listens for page changes and makes an Inertia request to update the respective paginator without affecting the other.
This setup ensures that each paginator can independently manage its state and update without interfering with the other, providing a smooth user experience.