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.