How to Implement Bootstrap Pagination for Displaying Posts in Laravel 11 with Vue 3?

Code Snippet
Jul 03, 2024
How to Implement Bootstrap Pagination for Displaying Posts in Laravel 11 with Vue 3?

To implement pagination for displaying posts in Laravel 11 and Vue 3, as well as displaying pagination using Bootstrap, you need to use Laravel's built-in pagination capabilities and configure Vue to work with this data.

 

Setting Up the Laravel Controller

In the controller, instead of using Post::all(), use the paginate method to get the paginate data:

use App\Http\Resources\PostResource;
use App\Models\Post;

public function index()
{
    $posts = Post::paginate(10);
    return PostResource::collection($posts);
}

 

Setting Up PostResource

Ensure that your PostResource properly handles the collection:

use Illuminate\Http\Resources\Json\JsonResource;

class PostResource extends JsonResource
{
    public function toArray($request)
    {
        return [
            'id' => $this->id,
            'title' => $this->title,
            'content' => $this->content,
        ];
    }
}

 

Creating a Pagination Component 

Create a new component Pagination.vue to manage pagination:

<template>
  <nav>
    <ul class="pagination">
      <li class="page-item" :class="{ disabled: currentPage === 1 }">
        <a class="page-link" href="#" @click.prevent="changePage(currentPage - 1)">Previous</a>
      </li>
      <li v-if="startPage > 1" class="page-item">
        <a class="page-link" href="#" @click.prevent="changePage(1)">1</a>
      </li>
      <li v-if="startPage > 2" class="page-item disabled">
        <span class="page-link">...</span>
      </li>
      <li class="page-item" 
          v-for="page in limitedPages" 
          :key="page" 
          :class="{ active: currentPage === page }">
        <a class="page-link" href="#" @click.prevent="changePage(page)">{{ page }}</a>
      </li>
      <li v-if="endPage < lastPage - 1" class="page-item disabled">
        <span class="page-link">...</span>
      </li>
      <li v-if="endPage < lastPage" class="page-item">
        <a class="page-link" href="#" @click.prevent="changePage(lastPage)">{{ lastPage }}</a>
      </li>
      <li class="page-item" :class="{ disabled: currentPage === lastPage }">
        <a class="page-link" href="#" @click.prevent="changePage(currentPage + 1)">Next</a>
      </li>
    </ul>
  </nav>
</template>

<script setup>
import { defineProps, defineEmits, computed } from 'vue';

const props = defineProps({
  currentPage: {
    type: Number,
    required: true,
  },
  lastPage: {
    type: Number,
    required: true,
  }
});

const emits = defineEmits(['pageChanged']);

const startPage = computed(() => {
  let start = props.currentPage - 2;
  return start > 0 ? start : 1;
});

const endPage = computed(() => {
  let end = props.currentPage + 2;
  return end < props.lastPage ? end : props.lastPage;
});

const limitedPages = computed(() => {
  const pagesArray = [];
  for (let i = startPage.value; i <= endPage.value; i++) {
    pagesArray.push(i);
  }
  return pagesArray;
});

const changePage = (page) => {
  if (page > 0 && page <= props.lastPage) {
    emits('pageChanged', page);
  }
};
</script>

<style>
.pagination {
  justify-content: center;
}
</style>

 

Using the Pagination Component

Now update your main component to use the pagination component:

<template>
  <div>
    <div v-for="post in posts" :key="post.id">
      <h2>{{ post.title }}</h2>
      <p>{{ post.content }}</p>
    </div>

    <Pagination 
      :currentPage="currentPage" 
      :lastPage="lastPage" 
      @pageChanged="fetchPosts"
    />
  </div>
</template>

<script setup>
import { ref, onMounted } from 'vue';
import axios from 'axios';
import Pagination from './Pagination.vue';

const posts = ref([]);
const currentPage = ref(1);
const lastPage = ref(1);

const fetchPosts = async (page = 1) => {
  try {
    const response = await axios.get(`/posts?page=${page}`);
    posts.value = response.data.data;
    currentPage.value = response.data.current_page;
    lastPage.value = response.data.last_page;
  } catch (error) {
    console.error('Failed to fetch posts:', error);
  }
};

onMounted(() => {
  fetchPosts();
});
</script>

 

Result

Now your post component will use Bootstrap pagination for navigation between pages. The Pagination component emits a pageChanged event when the page changes, which triggers the fetchPosts function in your main component to retrieve data from the new page.