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.

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)

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

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`);
});

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 }} />
}