Infinite Row Model (Enterprise)

The infinite (server-side) row model in apex-grid-enterprise fetches fixed-size blocks of rows from a datasource as the user scrolls, and pushes sort, filter, and quick-filter to the server. Use it for datasets too large to hold in the browser.

Grouped data? This model serves one flat list. If the user explores a hierarchy and only ever opens part of it, the Server-Side Row Model fetches one group level at a time, with server-computed aggregates on the group rows. The two are mutually exclusive.

Setting a datasource

import 'apex-grid-enterprise/define';

const grid = document.createElement('apex-grid-enterprise');
grid.columns = columns;

grid.infiniteRowModel = {
  datasource: {
    async getRows(params) {
      const res = await fetch('/api/rows', {
        method: 'POST',
        body: JSON.stringify(params),
      });
      const { rows, total } = await res.json();
      return { rows, rowCount: total };
    },
  },
  blockSize: 100,
  initialRowCount: 1000,
};

document.body.appendChild(grid);

InfiniteRowModelConfig

FieldTypeDescription
datasourceInfiniteDataSource<T>Object with a getRows(params) method
blockSizenumberRows fetched per block (optional)
initialRowCountnumberRow count assumed before the first block loads (optional)
maxRetriesnumberTimes a rejected getRows is retried. Default 2, at most 10; 0 turns retrying off (0.8)
retryDelaynumberMilliseconds before the first retry, doubled for each later one. Default 1000 (0.8)

The getRows contract

getRows receives the current query and returns (or resolves to) the block:

InfiniteGetRowsParams:

FieldDescription
startRow / endRowRow index range for the requested block
sortModelActive sort expressions (apply server-side)
filterModelActive filter expressions (apply server-side)
quickFilterGlobal quick-filter term
advancedFilterModelThe active advanced filter, or null (0.8). Apply it server-side; while it is set it replaces the column filters, so ignore filterModel then

InfiniteGetRowsResult:

FieldDescription
rowsThe rows for the requested block
rowCountTotal count for the current query, if known. Omit for pure "infinite" mode where the total is unknown
datasource: {
  getRows({ startRow, endRow, sortModel, filterModel, quickFilter }) {
    return db.query({
      offset: startRow,
      limit: endRow - startRow,
      sort: sortModel,
      filter: filterModel,
      search: quickFilter,
    });
  },
}

Server owns ordering

Setting infiniteRowModel disables client-side sort and filter: the server owns ordering. Keep pagination off; the grid virtualizes and lazily loads instead.

Reacting to loads

The apex-rows-loaded event fires after each block resolves:

import { ROWS_LOADED_EVENT } from 'apex-grid-enterprise';

grid.addEventListener(ROWS_LOADED_EVENT, (e) => {
  const { rowCount, exact, loadedBlocks, blockSize } = e.detail;
  console.log(`${loadedBlocks} block(s) loaded, ~${rowCount} rows`);
});

When a block fails

From 0.8 a rejected getRows is retried up to maxRetries times, retryDelay milliseconds apart and doubling, and each failure fires apex-rows-load-failed with { startRow, endRow, error, retrying }. After the last attempt (retrying: false) the block's rows stay placeholders until refreshRows() or a sort or filter change. Before 0.8 the grid asked again on every scroll over a failed block.

import { ROWS_LOAD_FAILED_EVENT } from 'apex-grid-enterprise';

grid.addEventListener(ROWS_LOAD_FAILED_EVENT, (e) => {
  const { startRow, endRow, error, retrying } = e.detail;
  if (!retrying) showBanner(`Rows ${startRow} to ${endRow} failed to load`, error);
});

Loading state

Check whether a specific row's block is still loading:

if (grid.isRowLoading(row)) {
  // show a skeleton / spinner for this row
}

Forcing a refresh

Discard cached blocks and refetch (for example, after a mutation):

grid.refreshRows();

React example

import { useEffect, useRef } from 'react'
import 'apex-grid-enterprise/define'

export default function InfiniteGrid() {
  const ref = useRef<any>(null)

  useEffect(() => {
    const grid = ref.current
    grid.columns = columns
    grid.infiniteRowModel = {
      datasource: {
        async getRows(params: any) {
          const res = await fetch('/api/rows', {
            method: 'POST',
            body: JSON.stringify(params),
          })
          const { rows, total } = await res.json()
          return { rows, rowCount: total }
        },
      },
      blockSize: 100,
    }
  }, [])

  return <apex-grid-enterprise ref={ref} style={{ height: 520 }} />
}