Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

gidaban79's avatar

Laravel interiajs and multiple paginators on same page?

I have some issue with couple paginations in one main component

return Inertia::render('Company/Show', [
           'reviews' => fn () => CompanyReviewResource::collection($filterable->builder->paginate(5)),
           'gallery' => fn () => GalleryResource::collection(
                $company->media()->where('collection_name', 'gallery')->paginate(5)->through(fn ($media) => ['thumb' => $media->getUrl('thumb'), 'image' => $media->getUrl('gallery')])),      
        ]);

and my vue component:

<template>
  <nav class="d-flex justify-content-end">
    <BPagination
      :per-page="meta.per_page"
      :total-rows="meta.total"
      first-number
      last-number
    />
  </nav>
</template>


<script setup>
let props = defineProps({
  meta: {
    type: Object,
    required: true
  },
})
</script>```

For pagination i am using bootstrap 5 vue package. Any ideas how to hadle it? Just change page for  `gallery` or `review` without changing url ?
0 likes
3 replies
tykus's avatar

Multiple paginators on the same page each need their own page name; the paginate method takes a $pageName argument:

return Inertia::render('Company/Show', [
    'reviews' => fn () => CompanyReviewResource::collection($filterable->builder->paginate(perPage: 5, pageName: 'reviews')),
    'gallery' => fn () => GalleryResource::collection(
        $company->media()->where('collection_name', 'gallery')
            ->paginate(perPage: 5, pageName: 'gallery')
            ->through(fn ($media) => ['thumb' => $media->getUrl('thumb'), 'image' => $media->getUrl('gallery')])
    ),      
        ]);

On the client-side application; I believe you will need the b-pagination-nav component which allows customising the Request URL (and query params)

1 like
LaryAI's avatar
Level 58

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:

  1. Backend (Laravel) Setup:

    • Ensure that each paginator has its own pagination state and data.
    • Use query parameters to differentiate between the paginators.
  2. 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

  1. Backend:

    • The controller now handles pagination for reviews and gallery separately using query parameters (reviews_page and gallery_page).
  2. 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.

Please or to participate in this conversation.