How to select a row on ag-grid in Infinite Row mode

Viewed 534

Many similar questions here, but I'm unable to find a solution to my basic requirement.

I'm using ag-grid in React in the Infinite Row model. Data are loaded from server by blocks of 100.

I would like to preselect a row - for example row id 500. This requires loading the right block and, once loaded, then selecting the right node.

Example here: (click on Jump to 500 button) demo code

const jumpTo500 = () => {
  if (gridApi.getInfiniteRowCount() < 501) {
    gridApi.setRowCount(501, false);
  }
  gridApi.ensureIndexVisible(500, 'middle');

  gridApi.forEachNode((node) => {
    if (node.rowIndex === 499) {
      node.setSelected(true);
    }
  });
};

Right now I need to click twice on the button because I try to select to row before the node is loaded.

Question: How to know when the grid is rendered and the new nodes are loaded?

onRowDataChanged() and onRowDataUpdated() events are never called.

2 Answers

my current workaround...

    const jumpTo500 = async () => {
      if (!gridApi) return;

      const node = gridApi.getModel().getRow(500);
      if (node) {
        until(() => !!node.id, 50, 5000)
            .then((ms) => {
                console.log("ok in ", ms, "ms");
                node.setSelected(true, false, true);
                gridApi.ensureNodeVisible(node, "middle");
            })
            .catch((ms) => console.log("timeout after", ms, "ms"));
      }
  };

I'm able to select the row once the node.id is available. Utility method until() will retry every 50ms until the condition is ok or if timeout after 5sec.

    const until = (condition: () => boolean, interval: number, timeout: number) =>
      new Promise<number>((resolve, reject) => {
        if (condition()) {
            resolve(0);
        }
        const start = new Date().getTime();
        const intervalTimer = setInterval(() => {
            const elapsed = new Date().getTime() - start;
            if (condition()) {
                clearInterval(intervalTimer);
                resolve(elapsed);
            } else {
                if (elapsed >= timeout) {
                    clearInterval(intervalTimer);
                    reject(elapsed);
                }
            }
        }, interval);
    });

In createDataSource, after setting the data, call callback.

Code in onGridReady:

    const calllbackAfterSetData = (): boolean => {
        const defIndex = localeSaver.loadObjectOrDefault<RowClicked>({ [rowClicked]: null })
        const infiniteRow = params.api.getInfiniteRowCount()

        if (!defIndex || defIndex.rowIndex === -1 || !infiniteRow) return false

        if (infiniteRow < (defIndex.rowIndex + 1)) {
            params.api.setRowCount(defIndex.rowIndex + 1, false)
        }
        params.api.ensureIndexVisible(defIndex.rowIndex, "top") 

        const node = params.api.getRowNode(defIndex.nodeId)

        if (node) {
            node?.setSelected(true)
            localeSaver.clear({ [rowClicked]: null })

            return true
        } else return false
    }

    const dataSource: IDatasource = dataSource(params.api, params.columnApi, calllbackAfterSetData)
    params.api.setDatasource(dataSource)

Code in createDataSource:

function dataSource( gridApi: GridApi, columnApi: ColumnApi, calllbackAfterSetData?: () => boolean) {
    return {
        getRows: async (params: IGetRowsParams) => {

            const response: string[] = []
            // any fetch
            if (response) {
                params.successCallback(response, 100)

                if (calllbackAfterSetData) {
                    const result = calllbackAfterSetData()
                    if (result) calllbackAfterSetData = undefined
                }

            } else {
                params.failCallback()
            }
        },


        destroy: () => {

        }
    }
}
Related