Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/sun0fabeach/vue-use-paginator

Vue 3 use-hook to reactively paginate data and arrange paginator buttons
https://github.com/sun0fabeach/vue-use-paginator

Last synced: about 2 months ago
JSON representation

Vue 3 use-hook to reactively paginate data and arrange paginator buttons

Awesome Lists containing this project

README

        

# vue-use-paginator

Vue 3 composition API hook function to reactively paginate data and arrange paginator buttons. Completely renderless.

## Demo

* [Live demo](https://demo-vue-use-paginator.netlify.app/)
* [Demo code](https://github.com/Sun0fABeach/demo-vue-use-paginator/blob/master/src/components/Demo.vue)

## Installation

```shell
$ npm install vue-use-paginator
```

## Basic Setup

```html

import usePaginator from 'vue-use-paginator'

const {
page,
pageSize,
numPages,
numItems,
numButtons,
slice,
buttons,
hasPrev,
hasNext,
goStart,
goPrev,
goNext,
goEnd,
} = usePaginator({
pageSize: 10,
numItems: 70,
numButtons: 5,
})

```

## Details

### Hook API

Function `usePaginator` returns an object of type [`IPagination`](<#user-content-definitions> "IPagination") which contains the following reactive data plus some convenience functions. You can initialize `page`, `pageSize`, `numItems` and `numButtons` by passing an object of type [`IOptions`](<#user-content-definitions> "IOptions"). Otherwise, default initial values will be used.

| Name | Type | Description
| -------------- | ---------------------------------- | -----------
| `page` | `Ref` | Current active page (default initial value: 1)
| `pageSize` | `Ref` | Size of each page (default initial value: 5)
| `numItems` | `Ref` | Total number of items to paginate (default initial value: 0)
| `numButtons` | `Ref` | Number of paginator buttons to display (default initial value: 5)
| `numPages` | `ComputedRef` | Total number of pages
| `slice` | `ComputedRef<[number, number]>` | Tuple containing start and end index delimiting the currently active page (0 based, end index is exclusive). For example, given you are on page 2, `pageSize` is 10 and `numItems` is greater than or equal to 20, `slice` will be `[10, 20]`.
| `buttons` | `ComputedRef` | Array of objects usable for displaying paginator buttons (details below)
| `hasPrev` | `ComputedRef` | Whether the currently active page is the first page
| `hasNext` | `ComputedRef` | Whether the currently active page is the last page
| `goPrev` | `() => number` | Go to next page
| `goNext` | `() => number` | Go to previous page
| `goStart` | `() => 1` | Go to first page
| `goEnd` | `() => number` | Go to last page

* `page`, `pageSize`, `numItems`, as well as `numButtons` are writable refs that will cause the other reactive properties to adjust when changed. Once you know how many items to paginate, you need to set `numItems` at least.
* You can move to another page by either calling `goPrev`, `goNext`, `goStart`, `goEnd`, or by assigning to `page` directly. Note that assigning a value outside of 1 and `numPages` will be ignored.

### Paginator buttons

When displaying paginator buttons, you often don't have enough slots for each page and therefore need to use a placeholder like '...'. Calculating the positions of these placeholders is not trivial. Luckily, `buttons` is an array of [`IPaginatorButton`](<#user-content-definitions> "IPaginatorButton") where each item contains the following properties to help you out.

| Name | Type | Description
| ---------- | ---------- | -----------
| `page` | `number` | The page to navigate to when clicking this button
| `active` | `boolean` | Whether this button shows the currently active page
| `ellipsis` | `boolean` | Whether this button is a placeholder for omitted pages

#### Template example

Here is a minimal example how you could write your paginator markup.

```vue



  1. {{ '<<' }}


  2. {{ '<' }}


  3. {{ button.ellipsis ? '...' : button.page }}


  4. {{ '>' }}


  5. {{ '>>' }}


```

Notice how certain classes and texts are set based on the values of `hasPrev`, `hasNext`, `button.active` and `button.ellipsis`. How you style these elements is completely up to you.

### API integration

This library doesn't make any assumptions about whether you paginate in the frontend or call a paginated endpoint.

If you paginate in the frontend, just assign the length of your collection to `numItems` and use the values from `slice` to slice out the items to display for your current page.

If you call a paginated endpoint, it needs to tell you the total number of items in order to set `numItems`. You can then use `slice` or `page`/`pageSize` to fetch a page. You will normally want to set up a watcher in order to fetch a new page when `page` or `pageSize` changes.

```typescript
watch([page, pageSize], ([newPage, newPageSize]) => {
fetchPage(newPage, newPageSize);
})
```

### Types

#### Definitions

```typescript
interface IOptions {
page?: number | Ref
pageSize?: number | Ref
numItems?: number | Ref
numButtons?: number | Ref
}

interface IPagination {
page: Ref
pageSize: Ref
numItems: Ref
numButtons: Ref
numPages: ComputedRef
slice: ComputedRef<[number, number]>
buttons: ComputedRef
hasPrev: ComputedRef
hasNext: ComputedRef
goPrev: () => number
goNext: () => number
goStart: () => 1
goEnd: () => number
}

interface IButton {
page: number
}

interface IPageButton extends IButton {
active: boolean
ellipsis: false
}

interface IEllipsisButton extends IButton {
active: false
ellipsis: true
}

type IPaginatorButton = IPageButton | IEllipsisButton
```

#### Importing Types

```typescript
import { IOptions, IPagination, IPaginatorButton } from 'vue-use-paginator'
```