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 cell-border" ref="grid" :theme="isDark ? 'darkMaterial' : 'material'" :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, RowOddPlugin, RowSelectPlugin} 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, RowOddPlugin, RowSelectPlugin];
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