How to use Quick Filter with Server-side / Infinite row model?
Asked Answered
B

2

7

As per documentation: Quick Filter, quick filter works with clientSide row model.

We are using serverSide row model for and we have a requirement to use quick filter with the data we have at client - in the cache blocks of the grid.

I though of using filter pipe with [rowData]="myRowData", but with this row model, I don't get any data from myRowData.

For example, if you have a look at this plunk Server side row model - quick filter, I have assigned [rowData]="rowData" in the markup and initialised it as [].

After loading initial chunk from server, I was assuming that the cache block data should be accessible with it, so that using angular pipe, I would be able to filter out the data at client side (mimicking the quick filter with serverSide row model). Something like [rowData]="rowData | filter: filterText" - like what we used to do in

But I'm afraid the cache data are not accessible with rowData.

How can we somehow use Quick Filter with ag-grid having serverSide row model?

Busty answered 29/11, 2018 at 13:24 Comment(3)
provide a short sample pls, for playing workaroundRaskind
updated the question with link to the plunkBusty
I can't say enough thank you for asking this question. This is exactly what I was looking and the answer given solved the problem and save me lots of working and debugging hours. This community is the best for developers like getting in triouble often times.Charlot
R
5

I would say it wasn't an easy task.

But here is how it could be solved:

  1. As you already mentioned quickFilter is a clientSide model type feature
  2. But no one has cancelled the setFilterModel way of usages

    It would require a lot of hacks and could break something (you have to check it on your solution and write a feedback then)

First of all, setFilterModel can't work with virtual data (we have to define column especially for quickFilter logic)

{
    field:'-', would be used as a reference
    hide:true, - hide in grid data
    lockVisible:true, - disable visibility changing via menu
    filter:"agTextColumnFilter", - require for setFilterModel
    filterParams:{
      newRowsAction: "keep"
    }
},

Next, we need to create a workaround for filterModel in datasource

getRows: function(params) {
    setTimeout(function() {
        var dataAfterSortingAndFiltering = sortAndFilter(data, params.sortModel, params.filterModel);
        var rowsThisPage = dataAfterSortingAndFiltering.slice(params.startRow, params.endRow);
        var lastRow = -1;
        if (dataAfterSortingAndFiltering.length <= params.endRow) {
            lastRow = dataAfterSortingAndFiltering.length;
        }
        params.successCallback(rowsThisPage, lastRow);
    }, 3000);
}

function sortAndFilter(allOfTheData, sortModel, filterModel) {
  return sortData(sortModel, filterData(filterModel, allOfTheData));
}
function sortData(sortModel, data) {
  ... sort logic here (doesn't matter for now) ...
}

Now about quickFilter logic, we've defined dummy column for it and here how it should be used:

setFilterModel will accept only existing column name ("-" in our case)

and with limited object props: but we will use filter (as it used in real cases)

applyFilter(){
    this.gridApi.setFilterModel({"-":{filter: this.filterText}})
}

and the last point of implementation is filterData function

function filterData(filterModel, data) {
  let filterPresent = filterModel && Object.keys(filterModel).length > 0;
  if (!filterPresent) { - if filter model is empty - skip it
    return data;
  }
  data = data.filter(i=>{
    if(Object.keys(i).some(k => i[k] && i[k].toString().toLowerCase().includes(filterModel['-'].filter)))
      return i;
  })
  return data;
}

Each object would be explored, and if any property contains quickFilter value - it would be in the result

Moreover, once you will scroll out of existing range (infinite scroll case) requested data would be filtered by this property

*not sure about duplicated data check on request

My sample

Your modified sample

Raskind answered 1/12, 2018 at 10:30 Comment(3)
Thanks for your effort! Que: So when I use setFilterModel it anyways calls dataSource.getRows and calls server to fetch the data. It's just filter we are applying at the client side. Am I correct? If so, my aim is just to avoid the server trip by applying the filter with whatever data available at client.Busty
Seems so (about anyway server trip), I've tried to find a way to get data from cache but didn't get the clue. moreover, it doesn't request all count (as was loaded) and only operates with first block. *so I suppose ag-grid for now doesn't provide a possibility to handle your case, cuz even if you will try to update data directly it will throw the warning that for service-side model setRowData method is restricted.Raskind
This answer guided me in the right direction to solving this problem and save me lots of working and debugging hours. Super explanation and a great guide. Thank you for contibuting to this very essential developers' community. The filterData method is a little bit complex when dealing with more than one column with different data types. I hope to find time to create a demo plunker for this and share it here for others as well.Charlot
N
2

Eventually I found ag-Grid's support article:

https://ag-grid.zendesk.com/hc/en-us/articles/360020488612?input_string=serverside+quick+filter

Its first example suggests to edit the getRows of your ServerSideDatasource to append to params.request a new key.

For example, you could do something like the following:

const customParams = {};
customParams.quickFilterValue = 'someQuery';

In onGridReady:

const datasource = createServerSideDatasource(server, customParams);
event.api.setServerSideDatasource(datasource)
/**
 *
 * @param {object} server
 * @param {object} customParams
 * @returns {object}
 */
export function createServerSideDatasource(server, customParams) {
  // https://www.ag-grid.com/javascript-grid-server-side-model-datasource/

  return {
    getRows: function (params) {
      params.request.customParams = customParams // Our backend will need to handle this custom 'customParams' key that the frontend attaches to the request (which itself will contain a quickFilterValue key and maybe others).

      const response = server.getData(params.request);

      if (response.success) {
        params.successCallback(response.rows, response.lastRow);
      } else {
        params.failCallback();
      }

    },
  };
}
Nominal answered 16/12, 2020 at 18:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.