Pagination Remote
This example shows how to use pagination with remote data in the grid. To enable pagination you’ll need to use the PaginationPlugin
.
This plugin provides the necessary functionality to paginate data within the grid.
Source code
import { defineCustomElements } from '@revolist/revogrid/loader';defineCustomElements(); // Define the custom element
import { PaginationPlugin, ColumnStretchPlugin, type PaginationFullConfig} from '@revolist/revogrid-pro';
import { fetch, type PaginatedResponse } from '../composables/remoteData';import { currentTheme } from '../composables/useRandomData';import type { Person } from '../composables/makeData';
const { isDark } = currentTheme();
export function load(parentSelector: string) { const grid = document.createElement('revo-grid');
/** * Handles pagination for a grid component. * Takes in parameters: * - config (pagination configuration) * - revogrid (the grid element). */ const paginationService = async ({ config: cfg, revogrid, }: { config: PaginationFullConfig; revogrid: HTMLRevoGridElement; }) => { /** * Set the initial skip and take values */ let skip = 0; let config = { ...cfg };
/** * Request data from remote server */ async function updateGridItems({ skip, take, count, }: { skip: number; take: number; count: boolean; }) { // Show loader revogrid.classList.add('busy'); // Send request to remote server to get data try { const url = `/api/users?skip=${skip}&take=${take}&count=${count}`; const response = await fetch(url); if (!response.ok) { const errorData = await response.json(); throw new Error(`Error ${response.status}: ${errorData.message}`); } const result: PaginatedResponse<Person> = await response.json();
// Hide loader revogrid.classList.remove('busy'); return result;
} catch (error) { // Hide loader revogrid.classList.remove('busy'); console.error('Failed to fetch users with pagination:', error); throw error; } }
/** * Event handler for page change and update the skip and take values */ grid.addEventListener('pagechange', ({ detail }) => { /** * Update the skip and take values */ skip = detail.skip; /** * Request new data */ updateGridItems({ skip: detail.skip * config.itemsPerPage, take: config.itemsPerPage, count: false, }).then((result) => { revogrid.source = result.data; }); }); /** * Request the data source of the grid */ const { data, count } = await updateGridItems({ skip, take: config.itemsPerPage, count: true, });
/** * Update pagination plugin data if count is present */ if (count) { config.total = count; revogrid.getPlugins().then((plugins) => { /** * Find the pagination plugin */ const paginationPlugin = plugins.find( (plugin) => plugin instanceof PaginationPlugin, ); (paginationPlugin as PaginationPlugin)?.setConfig(config); }); } revogrid.source = data; };
/** * Set the columns of the grid */ grid.columns = [ { name: 'First Name', prop: 'firstName', }, { name: 'Last Name', prop: 'lastName', }, { name: 'Relationship', prop: 'status', } ]; /** * Set the additional data for the grid */ grid.additionalData = { /** * Add stretch config to the grid */ stretch: 'all', }; // Define pagination plugin grid.plugins = [PaginationPlugin, ColumnStretchPlugin];
/** * Run pagination service */ paginationService({ config: { itemsPerPage: 10, initialPage: 0, total: 0, buttonCount: 5, }, revogrid: grid, });
grid.theme = isDark() ? 'darkCompact' : 'compact'; grid.hideAttribution = true; document.querySelector(parentSelector)?.appendChild(grid);}
<template> <VGrid class="overflow-hidden" ref="grid" :theme="isDark ? 'darkCompact' : 'compact'" :columns="columns" :source="rows" :plugins="plugins" :additionalData="additionalData" :class="{ busy }" hide-attribution @pagechange="handlePageChange" /></template>
<script setup lang="ts">import { ref, onMounted } from 'vue';import { currentThemeVue } from '../composables/useRandomData';import { fetch as fetchData, type PaginatedResponse,} from '../composables/remoteData';import type { Person } from '../composables/makeData';
import { VGrid } from '@revolist/vue3-datagrid';
import { PaginationPlugin, ColumnStretchPlugin,} from '@revolist/revogrid-pro';
const { isDark } = currentThemeVue();
const grid = ref<{ $el: HTMLRevoGridElement } | null>(null);const busy = ref(false);
const columns = ref([ { name: 'Full Name', prop: 'fullName' }, { name: 'Relationship', prop: 'status' },]);
const plugins = [PaginationPlugin, ColumnStretchPlugin];
const rows = ref<Person[]>([]);const additionalData = ref({ stretch: 'all', pagination: { itemsPerPage: 10, initialPage: 0, total: 0, buttonCount: 5,}});
const getGridItems = async ({ skip: s, take, count,}: { skip: number; take: number; count: boolean;}): Promise<PaginatedResponse<Person>> => { busy.value = true; try { const url = `/api/users?skip=${s}&take=${take}&count=${count}`; const response = await fetchData(url); if (!response.ok) { const errorData = await response.json(); throw new Error(`Error ${response.status}: ${errorData.message}`); } const result: PaginatedResponse<Person> = await response.json(); busy.value = false; return result; } catch (error) { busy.value = false; console.error('Failed to fetch users with pagination:', error); throw error; }};
const handlePageChange = async ({ detail: { skip = 0, count = false },}: { detail: { skip?: number; count?: boolean; };}) => { const items = await getGridItems({ skip: skip * additionalData.value.pagination.itemsPerPage, take: additionalData.value.pagination.itemsPerPage, count, }); if (count) { additionalData.value = { ...additionalData.value, pagination: { ...additionalData.value.pagination, total: items.count ?? 0 }, }; } rows.value = items.data;};
onMounted(() => handlePageChange({ detail: { count: true } }));</script>
import { useState, useMemo, useRef, useEffect } from 'react';import { RevoGrid } from '@revolist/react-datagrid';import { PaginationPlugin, ColumnStretchPlugin, type PaginationFullConfig,} from '@revolist/revogrid-pro';import { fetch as fetchRemote, type PaginatedResponse,} from '../composables/remoteData';import { currentTheme } from '../composables/useRandomData';import type { Person } from '../composables/makeData';import React from 'react';
function PaginationRemote() { const { isDark } = currentTheme(); const gridRef = useRef<HTMLRevoGridElement>(null); const [loading, setLoading] = useState(false); const [source, setSource] = useState<Person[]>([]); const [additionalData, setAdditionalData] = useState<{ stretch: string; pagination?: Partial<PaginationFullConfig>; }>({ stretch: 'all', pagination: { itemsPerPage: 10, initialPage: 0, total: 0, buttonCount: 5, }, });
const columns = useMemo( () => [ { name: 'First Name', prop: 'firstName' }, { name: 'Last Name', prop: 'lastName' }, { name: 'Relationship', prop: 'status' }, ], [], );
const updateGridItems = async ({ skip, take, count, }: { skip: number; take: number; count: boolean; }) => { const grid = gridRef.current; setLoading(true); try { const url = `/api/users?skip=${skip}&take=${take}&count=${count}`; const response = await fetchRemote(url); if (!response.ok) { const errorData = await response.json(); throw new Error(`Error ${response.status}: ${errorData.message}`); } const result: PaginatedResponse<Person> = await response.json(); setLoading(false); return result; } catch (error) { setLoading(false); console.error('Failed to fetch users with pagination:', error); throw error; } };
const handlePageChange = async (event: CustomEvent<{ skip: number }>) => { const skip = event.detail.skip; try { const result = await updateGridItems({ skip: skip * (additionalData.pagination?.itemsPerPage || 0), take: additionalData.pagination?.itemsPerPage || 0, count: false, }); setSource(result.data); } catch (error) { // Handle error as needed } };
const fetchInitialData = async () => { try { const result = await updateGridItems({ skip: 0, take: additionalData.pagination?.itemsPerPage || 0, count: true, }); if (result.count !== undefined) { setAdditionalData((prev) => ({ ...prev, pagination: { ...prev.pagination, total: result.count }, })); } setSource(result.data); } catch (error) { // Handle error as needed } };
useEffect(() => { fetchInitialData(); }, []);
return ( <RevoGrid ref={gridRef} class={loading ? 'busy' : ''} columns={columns} source={source} additionalData={additionalData} hide-attribution theme={isDark() ? 'darkCompact' : 'compact'} plugins={[PaginationPlugin, ColumnStretchPlugin]} onPagechange={handlePageChange} /> );}
export default PaginationRemote;
import { Component, ViewEncapsulation, ViewChild, ElementRef, type OnInit } from '@angular/core';import { RevoGrid } from "@revolist/angular-datagrid";import { PaginationPlugin, ColumnStretchPlugin } from '@revolist/revogrid-pro';import { fetch as fetchRemote, type PaginatedResponse } from '../composables/remoteData';import { currentTheme } from '../composables/useRandomData';import type { Person } from '../composables/makeData';
@Component({ selector: 'pagination-remote-grid', standalone: true, imports: [RevoGrid], template: `<revo-grid #gridRef [ngClass]="{ busy: busy }" [columns]="columns" [source]="source" [additionalData]="additionalData" [hideAttribution]="true" [theme]="theme" [plugins]="plugins" style="height: 400px;" (pagechange)="handlePageChange($event)" ></revo-grid>`, encapsulation: ViewEncapsulation.None,})export class PaginationRemoteGridComponent implements OnInit { @ViewChild('gridRef', { static: true }) gridRef!: ElementRef<HTMLRevoGridElement>; theme = currentTheme().isDark() ? 'darkCompact' : 'compact'; source: Person[] = []; busy = false;
additionalData = { stretch: 'all', pagination: { itemsPerPage: 10, initialPage: 0, total: 0, buttonCount: 5, }, };
columns = [ { name: 'First Name', prop: 'firstName' }, { name: 'Last Name', prop: 'lastName' }, { name: 'Relationship', prop: 'status' }, ];
plugins = [PaginationPlugin, ColumnStretchPlugin];
async updateGridItems(skip: number, take: number, count: boolean) { const grid = this.gridRef.nativeElement; this.busy = true;
try { const url = `/api/users?skip=${skip}&take=${take}&count=${count}`; const response = await fetchRemote(url);
if (!response.ok) { const errorData = await response.json(); throw new Error(`Error ${response.status}: ${errorData.message}`); }
const result = await response.json() as PaginatedResponse<Person>;
this.busy = false; return result; } catch (error) { this.busy = false; console.error('Failed to fetch users with pagination:', error); throw error; } }
async handlePageChange(event: any) { const skip = event.detail.skip * this.additionalData.pagination.itemsPerPage;
try { const result = await this.updateGridItems(skip, this.additionalData.pagination.itemsPerPage, false); this.source = result.data; } catch (error) { // Handle error as needed } }
async fetchInitialData() { try { const result = await this.updateGridItems(0, this.additionalData.pagination.itemsPerPage, true);
if (result.count !== undefined) { this.additionalData.pagination.total = result.count; }
this.source = result.data; } catch (error) { console.error('Failed to fetch users with pagination:', error); } }
ngOnInit() { this.fetchInitialData(); }}
// fixing render for multiframework