How to implement client-side pagination in Vue.js

How to implement client-side pagination in Vue.js

In this post, you'll see a simple example of how to implement client-side pagination in Vue.js

Originally published at https://jasonwatmore.com

The example contains a hard coded array of 150 objects split into 15 pages to demonstrate how the pagination component works.

Vue.js Pagination Component

Pagination is implemented with the <jw-pagination> component that comes with the jw-vue-pagination package available on npm.

Installation

Install the Vue pagination component with the command npm install jw-vue-pagination.

Integration with your Vue.js app

Import the JwPagination component from the 'jw-vue-pagination' package and register it globally within your Vue application by calling Vue.component('jw-pagination', JwPagination);

The first parameter is the component name, it defines the custom tag used to add the component to other components, in this case it will be with the tag <jw-pagination></jw-pagination>. The second parameter points to the actual Vue component.

Global registration makes the Vue component available to all other components within the Vue application, it's also possible to register components locally, for more info see https://vuejs.org/v2/guide/components-registration.html.

This is the main Vue entry file (/src/index.js) from the example, the pagination component is imported and registered globally on lines 6-7.

import Vue from "vue";

 

import App from "./app/App";

 

// register jw pagination component globally

import JwPagination from 'jw-vue-pagination';

Vue.component('jw-pagination', JwPagination);

 

new Vue({

    el: "#app",

    render: h => h(App)

});

Usage

There are 2 required properties for using the Vue.js pagination component:

  • items - the array of items to be paged
  • changePage - an event listener function for handling the changePage event

There are also a few optional properties:

  • pageSize - the number of items displayed on each page (defaults to 10)
  • maxPages - the max number of page links to display in the pagination nav (defaults to 10)
  • initialPage - the initial page to display (defaults to 1)

Example Vue.js Component with Pagination

This is the App component (/src/app/App.vue) from the example. The template renders the current page of items using the v-for Vue directive on line 5, and includes the pagination component (<jw-pagination ...>) on line 8.

The component logic creates a hardcoded array of exampleItems to be paged and updates the current page of items in the onChangePage() method.

<template>

    <div class="card text-center m-3">

        <h3 class="card-header">Vue.js Pagination Tutorial & Example</h3>

        <div class="card-body">

            <div v-for="item in pageOfItems" :key="item.id">{{item.name}}</div>

        </div>

        <div class="card-footer pb-0 pt-3">

            <jw-pagination :items="exampleItems" @changePage="onChangePage"></jw-pagination>

        </div>

    </div>

</template>

 

<script>

// an example array of items to be paged

const exampleItems = [...Array(150).keys()].map(i => ({ id: (i+1), name: 'Item ' + (i+1) }));

 

export default {

    data() {

        return {

            exampleItems,

            pageOfItems: []

        };

    },

    methods: {

        onChangePage(pageOfItems) {

            // update page of items

            this.pageOfItems = pageOfItems;

        }

    }

};

</script>

Styling the Pagination Component

The Vue pagination component comes with some very basic default styles. To use your own custom styles I'd recommend disabling the default styles by adding the property :disableDefaultStyles="true" to the <jw-pagination> component, then adding custom styles in your css with the following css selectors:

  • .pagination - Pagination component container (ul element)
  • .pagination li - All list items in the pagination component
  • .pagination li a - All pagination links including first, last, previous and next
  • .pagination li.page-number - All page numbers (1, 2, 3 etc) pagination elements
  • .pagination li.first - The 'First' pagination element
  • .pagination li.last - The 'Last' pagination element
  • .pagination li.previous - The 'Previous' pagination element
  • .pagination li.next - The 'Next' pagination element

Note: you can also plug in Bootstrap CSS (3.x or 4.x), that's what is used in the example.

If you prefer you can also override or extend the default styles (instead of disabling them) by passing a custom styles object to the jw-pagination component like this:

<template>

    ...

        <jw-pagination :items="exampleItems" @changePage="onChangePage" :styles="customStyles"></jw-pagination>

    ...

</template>

 

<script>

...

 

const customStyles = {

    ul: {

        border: '2px solid red'

    },

    li: {

        display: 'inline-block',

        border: '2px dotted green'

    },

    a: {

        color: 'blue'

    }

};

 

export default {

    data() {

        return {

            ...

            customStyles

        };

    },

    ...

};

</script>

Custom labels for First, Last, Next & Previous pagination buttons

You can use custom labels for the First, Last, Next & Previous buttons by passing a labels object to the jw-pagination component like this:

<template>

    ...

        <jw-pagination :items="exampleItems" @changePage="onChangePage" :labels="customLabels"></jw-pagination>

    ...

</template>

 

<script>

 

const customLabels = {

    first: '<<',

    last: '>>',

    previous: '<',

    next: '>'

};

 

export default {

    data() {

        return {

            ...

            customLabels

        };

    },

    ...

};

</script>

Hiding pagination buttons

To hide any of the buttons you can simply set them to display: none; using the css selectors described above.

Further Customisation of the Vue.js Pagination Component

If you want to make further customisations such as changing the HTML template of the component, I'd recommend just copying the pagination component code into your own custom Vue component, it's a fairly simple component and this approach will give you complete flexibility to make any changes you like.

To use this approach you need to install the jw-paginate package from npm with the command npm install jw-paginate. The jw-paginate package contains the pagination logic used to paginate any array or list of items.

This is the complete pagination component code, it's also available here on GitHub.

<template>

    <ul v-if="pager.pages && pager.pages.length" class="pagination" :style="ulStyles">

        <li class="page-item first" :class="{'disabled': pager.currentPage === 1}" :style="liStyles">

            <a class="page-link" @click="setPage(1)" :style="aStyles">{{labels.first}}</a>

        </li>

        <li class="page-item previous" :class="{'disabled': pager.currentPage === 1}" :style="liStyles">

            <a class="page-link" @click="setPage(pager.currentPage - 1)" :style="aStyles">{{labels.previous}}</a>

        </li>

        <li v-for="page in pager.pages" :key="page" class="page-item page-number" :class="{'active': pager.currentPage === page}" :style="liStyles">

            <a class="page-link" @click="setPage(page)" :style="aStyles">{{page}}</a>

        </li>

        <li class="page-item next" :class="{'disabled': pager.currentPage === pager.totalPages}" :style="liStyles">

            <a class="page-link" @click="setPage(pager.currentPage + 1)" :style="aStyles">{{labels.next}}</a>

        </li>

        <li class="page-item last" :class="{'disabled': pager.currentPage === pager.totalPages}" :style="liStyles">

            <a class="page-link" @click="setPage(pager.totalPages)" :style="aStyles">{{labels.last}}</a>

        </li>

    </ul>

</template>

 

<script>

    import paginate from 'jw-paginate';

 

    const defaultLabels = {

        first: 'First',

        last: 'Last',

        previous: 'Previous',

        next: 'Next'

    };

 

    const defaultStyles = {

        ul: {

            margin: 0,

            padding: 0,

            display: 'inline-block'

        },

        li: {

            listStyle: 'none',

            display: 'inline',

            textAlign: 'center'

        },

        a: {

            cursor: 'pointer',

            padding: '6px 12px',

            display: 'block',

            float: 'left'

        }

    };

 

    export default {

        props: {

            items: {

                type: Array,

                required: true

            },

            initialPage: {

                type: Number,

                default: 1

            },

            pageSize: {

                type: Number,

                default: 10

            },

            maxPages: {

                type: Number,

                default: 10

            },

            labels: {

                type: Object,

                default: () => defaultLabels

            },

            styles: {

                type: Object

            },

            disableDefaultStyles: {

                type: Boolean,

                default: false

            }

        },

        data () {

            return {

                pager: {},

                ulStyles: {},

                liStyles: {},

                aStyles: {}

            }

        },

        created () {

            if (!this.$listeners.changePage) {

                throw 'Missing required event listener: "changePage"';

            }

 

            // set default styles unless disabled

            if (!this.disableDefaultStyles) {

                this.ulStyles = defaultStyles.ul;

                this.liStyles = defaultStyles.li;

                this.aStyles = defaultStyles.a;

            }

 

            // merge custom styles with default styles

            if (this.styles) {

                this.ulStyles = { ...this.ulStyles, ...this.styles.ul };

                this.liStyles = { ...this.liStyles, ...this.styles.li };

                this.aStyles = { ...this.aStyles, ...this.styles.a };

            }

 

            // set page if items array isn't empty

            if (this.items && this.items.length) {

                this.setPage(this.initialPage);

            }

        },

        methods: {

            setPage(page) {

                const { items, pageSize, maxPages } = this;

 

                // get new pager object for specified page

                const pager = paginate(items.length, page, pageSize, maxPages);

 

                // get new page of items from items array

                const pageOfItems = items.slice(pager.startIndex, pager.endIndex + 1);

 

                // update pager

                this.pager = pager;

 

                // emit change page event to parent component

                this.$emit('changePage', pageOfItems);

            }

        }

    }

</script>

Thanks for reading

If you liked this post, share it with all of your programming buddies!

Follow us on Facebook | Twitter

Further reading

The Complete JavaScript Course 2019: Build Real Projects!

Vue JS 2 - The Complete Guide (incl. Vue Router & Vuex)

Nuxt.js - Vue.js on Steroids

Best JavaScript Frameworks, Libraries and Tools to Use in 2019

Build a Progressive Web App In VueJs

Build a CMS with Laravel and Vue

Beginner’s Guide to Vue.js

Hands-on Vue.js for Beginners

Top 3 Mistakes That Vue.js Developers Make and Should be Avoided

Top Vue.js Developers in USA

Top Vue.js Developers in USA

Vue.js is an extensively popular JavaScript framework with which you can create powerful as well as interactive interfaces. Vue.js is the best framework when it comes to building a single web and mobile apps.

We, at HireFullStackDeveloperIndia, implement the right strategic approach to offer a wide variety through customized Vue.js development services to suit your requirements at most competitive prices.

Vue.js is an open-source JavaScript framework that is incredibly progressive and adoptive and majorly used to build a breathtaking user interface. Vue.js is efficient to create advanced web page applications.

Vue.js gets its strength from the flexible JavaScript library to build an enthralling user interface. As the core of Vue.js is concentrated which provides a variety of interactive components for the web and gives real-time implementation. It gives freedom to developers by giving fluidity and eases the integration process with existing projects and other libraries that enables to structure of a highly customizable application.

Vue.js is a scalable framework with a robust in-build stack that can extend itself to operate apps of any proportion. Moreover, vue.js is the best framework to seamlessly create astonishing single-page applications.

Our Vue.js developers have gained tremendous expertise by delivering services to clients worldwide over multiple industries in the area of front-end development. Our adept developers are experts in Vue development and can provide the best value-added user interfaces and web apps.

We assure our clients to have a prime user interface that reaches end-users and target the audience with the exceptional user experience across a variety of devices and platforms. Our expert team of developers serves your business to move ahead on the path of success, where your enterprise can have an advantage over others.

Here are some key benefits that you can avail when you decide to hire vue.js developers in USA from HireFullStackDeveloperIndia:

  • A team of Vue.js developers of your choice
  • 100% guaranteed client satisfaction
  • Integrity and Transparency
  • Free no-obligation quote
  • Portal development solutions
  • Interactive Dashboards over a wide array of devices
  • Vue.js music and video streaming apps
  • Flexible engagement model
  • A free project manager with your team
  • 24*7 communication with your preferred means

If you are looking to hire React Native developers in USA, then choosing HireFullStackDeveloperIndia would be the best as we offer some of the best talents when it comes to Vue.js.