Search code examples
angularag-gridag-grid-angular

Ag grid infinite datasource - set sort/filter model after first load


Short version: Using an infinite row model on Ag-grid I need a way to set the filter and sort model after the first getRows() request (I can't set the column definitions before the first request is completed). Does anyone have a way to do this without triggering more getRows?

Full Context: I am using Ag-grid with the infinite row model for an Angular app. We're using it to view filter/sort large flat datasets. The grid correctly handles it so that when a user changes a filter or sort on the grid, the getRows request in the datasource is triggered with the new filter/sort model.

I also need to have routing on the app. If a user opens a grid of a certain dataset, adds a filter/sort this should be reflected in the url. The idea being that a user can then share the link of the page and if opened in a new window the page will automatically load the data that the first user was looking at. I have the routing working as well. It's also worth noting that we will never know exactly what the column definitions will be when loading a new grid.

Issue: When the second user opens the link the grid loads and sends a request to the server with the correct filters. However the grid's sort/filter state doesn't reflect this, which is fair enough since we've just initialised a new grid and haven't set the sort/filter model, but it needs to be set otherwise when the user scrolls the original filters will no longer be applied. However I am having trouble actually setting the sort/filter model as well as struggling to not trigger additional requests to the server. We are generating the column definitions after the first load of data, so what I have tried is after generating the column definitions calling gridApi.setSortModel(sortModel) and gridApi.setFilterModel(filterModel) as well as setting a global variable to tell the grid not to ask for rows again after setting the models.

This is not working. The getRows() request is triggered again, but for some reason the filter and sort models are still empty. Here is a rough idea of the datasource I'm using:

createDatasource(grid): IDatasource {
  return {
    getRows: params => {
         if (grid.ignoreRequest) {
            grid.ignoreRequest = false;
            params.failCallback();
            return;
         } else {
             const query = generateQuery(params);
             this.api.getData(query).then(response => {
                 if (!grid.columnDefs.length) {
                     const sortModel = generateSortModel(query);
                     grid.ignoreRequest = true;
                     grid.columnDefs = grid.generateColumnDefs(response[0]);
                     grid.gridApi.setSortModel(sortModel);
                 }
                 params.successCallback(response, response.length);
             } handleErr);
         }
    }
  };
}

(Note the above code is slightly simplified, but the structure is the same).

When configured as above the grid will load the data once, correctly create column definitions, then hit the getRows() request again, which will correctly handle the ignoreRequest param but the sortModel isn't set correctly. Also despite the first request working correctly and setting rows, after the second request is ignored there is no row data in the grid, just the column definitions.

I found someone asking a similar thing on git hub, but the examples haven't helped me as I need to set column definitions after the first request, not before: https://github.com/ag-grid/ag-grid/issues/1785

Any help would be appreciated.


Solution

  • There are 2 things wrong with the code in the question.

    • The column definitions need to be set using the grid api, not just setting a variable. Setting the variable on the grid means the columns will be displayed correctly, but unless gridApi.setColumnDefs(columnDefs) is called, then the subsequent call to set the sort or filter model won't work. Once this change is made the sortModel will be correctly reflected.

    • In other examples I had seen, failCallback() was being used when we want to ignore the request. For me this was just setting the rows blank, perhaps that method has been updated to do that since those other solutions were posted. Instead it should be changed to successCallback. This method requires the row data, so before setting the filter/sort model the rowData needs to be persisted in some way.

    Here is an updated (basic) version of the getRows() function.

    createDatasource(grid): IDatasource {
      return {
        getRows: params => {
             if (_.get(grid, 'ignoreRequestount', 0) > 0) {
                grid.ignoreRequestCount--;
                params.successCallback(grid.rowData);
             } else {
                 const query = generateQuery(params);
                 this.api.getData(query).then(response => {
                     grid.ignoreRequestCount = 0;
                     const sortModel = this.ODataQueryToSortModel(query);
                     const filterModel = this.ODataQueryToFilterModel(query);
                     grid.columnDefs = gridTab.generateColumnDefs(response[0]);
                     grid.gridApi.setColumnDefs(grid.columnDefs);
                     if (_.keys(filterModel).length) {
                         grid.ignoreRequestCount += 1;
                         grid.gridApi.setFilterModel(filterModel);
                     }
                     if (sortModel.length) {
                         grid.ignoreRequestCount += 1;
                         grid.gridApi.setSortModel(sortModel);
                     }
                     params.successCallback(response, response.length);
                 } handleErr);
             }
        }
      };
    }
    

    Again this is simplified, but covers it mostly. I had to adjust the check if it should ignore the request as in some cases the filterModel and sortModel could be being set, which would cause multiple triggers. It's a bit hacky, but it will have to do unless someone has a better solution...