vkuzel.com

Initialise column filters and sorting in ag-Grid Enterprise 21

2019-07-05

Goal is to be able to set filter values, sorting and column states without causing multiple get rows requests. Also, there should be a possibility to pre-set a grid before a first get rows request is send to a server.

Ag-Grid has limited options to do such a thing. There is GridOptions.columnDefs property which allows to initialise sorting of any column and to set its state, unfortunately there are no such properties for filters.

On the other hand GridOptions.columnApi.setColumnState(), GridOptions.api.setFilterModel() and GridOptions.api.setSortModel() methods allows to do such task, but some of those methods cause rows to be reloaded from a server which leads to multiple server calls and unnecessary data transfer.

Solution

After examining ag-Grid's code I have found that easiest way to accomplish this is to just ignore some of the endpoint calls. For example setting a filter model and a sort model cause two endpoint calls. So first call will be ignored.

@Component(...)
export class AgGridComponent implements OnInit, AfterViewInit {

    @ViewChild('agGrid')
    private agGrid: AgGridAngular;
    private service: AgGridService;

    constructor(private httpClient: HttpClient) {
    }

    ngOnInit() {
        this.service = new AgGridService(this.agGrid, this.entityClassName, this.httpClient);
    }

    ngAfterViewInit() {
        this.service.initGrid();
    }

    // User wants to set filters, sorting, etc. to a different set of values.
    selectLayout(gridLayout: GridLayout) {
        this.service.selectLayout(gridLayout);
    }
}

class AgGridService implements IServerSideDatasource {

    private requestsToIgnore = 0;

    constructor(private agGrid: AgGridAngular, private httpClient: HttpClient) {
    }

    initGrid(): void {
        this.httpClient.get('get-grid-config').subscribe((gridConfig: GridConfig) => {
            // We have a grid configuration so let's set grid up. Methods setServerSideDatasource(),
            // setFilterModel() and setSortModel() cause get-rows endpoint to be called, so we have
            // to ignore two of those three calls.
            this.requestsToIgnore = 2;
            const gridOptions = this.agGrid.gridOptions;
            gridOptions.api.setColumnDefs(gridConfig.columnDefs);
            // Method setServerSideDatasource() resets any filter or sort models so it has to be
            // called first.
            gridOptions.api.setServerSideDatasource(this);
            gridOptions.columnApi.setColumnState(gridConfig.defaultGridLayout.columnState);
            gridOptions.api.setFilterModel(gridConfig.defaultGridLayout.filterModel);
            gridOptions.api.setSortModel(gridConfig.defaultGridLayout.sortModel);
        });
    }

    selectLayout(gridLayout: GridLayout): void {
        // In this case we have to ignore only one call.
        this.requestsToIgnore = 1;
        const gridOptions = this.agGrid.gridOptions;
        gridOptions.columnApi.setColumnState(gridLayout.columnState);
        gridOptions.api.setFilterModel(gridLayout.filterModel);
        gridOptions.api.setSortModel(gridLayout.sortModel);
    }

    getRows(params: IServerSideGetRowsParams): void {
        if (this.requestsToIgnore-- > 0) {
            params.failCallback();
        } else {
            this.httpClient.post('get-rows', params.request).subscribe(
                (rows: any) => params.successCallback(rows.data, rows.lastRow),
                () => params.failCallback()
            );
        }
    }

    destroy(): void {
    }
}

interface GridConfig {
    columnDefs: (ColDef | ColGroupDef)[]
    defaultGridLayout: GridLayout,
    gridLayouts: GridLayout[]
}

interface GridLayout {
    columnState: any,
    filterModel: any,
    sortModel: any
}

Rationale

In ag-Grid's column.ts.Column.constructor(), you can clearly see that there are not too many possibilities to preinitialise a column's state. There are a few properties for sorting and showing/hiding a column, but there is no such a thing like pre-setting filter values.

Filter values can be set by GridOptions.api.setFilterModel() method, which internally raises two model-updated events. Model-updated event leads to a server request. Actually these two events leads to a single request because second event is swallowed in serverSideCache.ts.ServerSideCache.getRow() method.

There has been call for this functionality to be implemented in ag-Grid's init phase, unfortunately the feature request was closed without proper solution.