Persisting and restoring AG Grid state with React & Redux

  |   Tutorial

Introduction

AG Grid gives great flexibility in saving and restoring its state. This is especially useful when your users want to have their own AG Grid configuration by default or switch between different views and keep the AG Grid setup when they return. You can also save AG Grid state as part of the user profile and load it each time a user opens the application. In this post, we will show how to do this by persisting AG Grid state using React and Redux.

Example APP

We've demonstrated this in an example with several views, each having a few tabs. Each of these tabs hosts an instance of AG Grid with its own state that gets persisted as the user makes changes to the application.

Please see a GIF illustrating this below and note how the configuration (state) of AG Grid is saved and then restored after the page is refreshed:

Please try out the live sample below following these steps:

  1. On the active tab, change the state of AG Grid. For example, hide columns from the columns menu on the right by unchecking some of the checkboxes.
    You can also filter by hovering over a column header and selecting the filter menu.
  2. Now switch between views or tabs and note that when you come back to the original tab, the AG Grid state is exactly as you left it in step (1).
  3. You can also save your changes to Local Storage by clicking SAVE STATE TO LOCAL STORAGE button.
  4. Now you can refresh the page and note you'll have the same AG Grid state loaded after the refresh.
Note: The ag-Grid state gets stored in the Redux store whenever the user performs an action. However, when you refresh the page, the Redux state is lost. This is why we added the SAVE STATE TO LOCAL STORAGE button to save the Redux store to LocalStorage. This way, when you reload the page, the application initializes the store from LocalStorage and restores the ag-Grid state.



Managing state in AG Grid

So how is this implemented? AG Grid provides granular control over which aspects of its state you wish to get or set through its API. In our project, we are going to save the filter, sort, column, column group and pivot enabled/disabled state. We will use AG Grid state change events to save the state and the onFirstDataRendered event to restore the saved state whenever the user refreshes the page or switches between tabs.

onFirstDataRendered is an event that gets triggered when the grid is initialized, and the data has been rendered in the grid. We use it to restore any persisted state on AG Grid.

The approach to save and restore state is almost identical for the different aspects of AG Grid, so please jump to the part you are interested in:

Column Sort state

You can save and restore the sorting state of columns in AG Grid, as shown by the GIF below:

Here are the steps for saving and restoring the column sort state implemented in the code below.

  1. When the columns get sorted, a sortChanged event will get fired.
  2. We add an onSortChanged event listener to <AgGridReact/> Component.
  3. The Sort State is a part of the column state. In our listener, we save the Column state by calling the columnApi.getColumnState() and we dispatch an action with the column state as its payload.
  4. The reducer saves the sort state to our Redux store.
  5. Finally, we add onFirstDataRendered listener to restore the state from our Redux store.
// [...]
// src/components/MyGrid/MyGrid.jsx

class MyGrid extends Component {
	// [...]

  onSaveGridColumnState() {
  	// [...]
    let columnState = this.gridColumnApi?.getColumnState();
      
    this.debounceSaveGridColumnState(this.props.id, columnState);
  }

  onFirstDataRendered(params) {
     //	[...]

    let columnState = this.props?.columnState;
    
    if (columnState) {
      this.gridColumnApi.applyColumnState({
        state: columnState,
        applyOrder: true
      });
    }
  }

  render() {
    // [...]
    return (
      <AgGridReact
        onSortChanged={this.onSaveGridColumnState.bind(this)}
        onFirstDataRendered={this.onFirstDataRendered.bind(this)}
      />
    );
  }
}

You can learn more about sorting in ag-Grid here - Row Sorting, Sorting API.

Column Filter state

You can save and later restore the filter applied to a column in AG Grid, as shown by the GIF below:

Here are the steps for saving and restoring the filter state implemented in the code below.

  1. When the columns get filtered, a filterChanged event will get fired.
  2. We add an onFilterChanged event listener to <AgGridReact /> Component.
  3. In our listener, we save the filter state by calling the api.getFilterModel() and we dispatch an action with the filter state as its payload
  4. The reducer saves the filter state to our Redux store.
  5. Finally, we add onFirstDataRendered listener that simply restores the state from our Redux store.
// [...]
// src/components/MyGrid/MyGrid.jsx

class MyGrid extends Component {
  // [...]

  onFilterChanged(params) {
    let filterModel = params.api.getFilterModel();
    this.props.actions.saveGridFilterModel(this.props.id, filterModel);
  }

  onFirstDataRendered(params) {
    //	[...]
    let filterModel = this.props?.filterModel;

    if (filterModel) {
      this.gridApi.setFilterModel(filterModel);
    }
  }

  render() {
    // [...]
    return (
      <AgGridReact
        onFirstDataRendered={this.onFirstDataRendered.bind(this)}
        onFilterChanged={this.onFilterChanged.bind(this)}
      />
    );
  }
}

You can learn more about filtering in AG Grid here - Column Filters, Filter API.

Column & Column Group state

You can also save and restore the AG Grid column state, including pinned columns, column size, visibility and order. Please see these illustrated in GIF below:

Here are the steps for saving and restoring Column & Column Group state implemented in the code below.

  1. When the user resizes, pins, moves columns and hides columns, the grid will fire the following events: columnResized, columnPinned ,columnMoved ,columnVisible, columnValueChanged, columnPivotChanged.  
  2. We add the same listener for all the above events on the <AgGridReact /> Component.
  3. In our listener, we save the column & column group state by calling the gridColumnApi.getColumnState() & gridColumnApi.getColumnGroupState() and we dispatch 2 actions, one for saving column state and the other for column group state. Both of them will send the corresponding state as the payload
  4. The reducer saves the column & column group state to our Redux store.
  5. Finally, we add onFirstDataRendered listener that simply restores the state from our redux store.
// [...]
// src/components/MyGrid/MyGrid.jsx

class MyGrid extends Component {
  // [...]

  onSaveGridColumnState(e) {
    if (!this.gridColumnApi) return;
    let columnState = this.gridColumnApi?.getColumnState();
    let columnGroupState = this.gridColumnApi?.getColumnGroupState();

    this.debounceSaveGridColumnState(this.props.id, columnState);
    this.debounceSaveGridColumnGroupState(this.props.id, columnGroupState);
  }

  onFirstDataRendered(params) {
    //	[...]
    let columnState = this.props?.columnState;
    let columnGroupState = this.props?.columnGroupState;

    if (columnState) {
      this.gridColumnApi.applyColumnState({
        state: columnState,
        applyOrder: true
      });
    }

    if (columnGroupState) {
      this.gridColumnApi.setColumnGroupState(columnGroupState);
    }
  }

  render() {
    // [...]
    return (
      <AgGridReact
        onFirstDataRendered={this.onFirstDataRendered.bind(this)}
        onColumnVisible={this.onSaveGridColumnState.bind(this)}
        onColumnPinned={this.onSaveGridColumnState.bind(this)}
        onColumnResized={this.onSaveGridColumnState.bind(this)}
        onColumnMoved={this.onSaveGridColumnState.bind(this)}
        onColumnRowGroupChanged={this.onSaveGridColumnState.bind(this)}
        onColumnValueChanged={this.onSaveGridColumnState.bind(this)} // A value column was added or removed.
        onColumnPivotChanged={this.onSaveGridColumnState.bind(this)} // A pivot column was added, removed or order changed.
      />
    );
  }
}

You can learn more about column and column groups in AG Grid here - Column Groups, Saving and Restoring Column State.

Pivot mode enabled / disabled state

You can save and restore the pivot mode state in AG Grid, as shown by the GIF below:

Here are the steps for saving and restoring the pivot on/off state implemented in the code below.

  1. When the Pivot Mode is toggled, a columnPivotModeChanged event gets fired.
  2. We add an onColumnPivotModeChanged event listener to <AgGridReact /> Component.
  3. In our listener, we save the pivot mode state by calling the gridColumnApi.isPivotMode() and we dispatch an action with the pivot state as its payload
  4. The reducer saves the pivot state to our Redux store.
  5. Finally, we add onFirstDataRendered listener that simply restores the state from our Redux store.
// [...]
// src/components/MyGrid/MyGrid.jsx

class MyGrid extends Component {
  // [...]

  onSavePivotModeState() {
    let isPivotMode = this.gridColumnApi.isPivotMode();

    let isPivotModeDifferentFromProps =
      this.gridColumnApi.isPivotMode() !== this.props.isPivotMode;
    if (isPivotModeDifferentFromProps)
      this.debounceSaveGridPivotModeState(this.props.id, isPivotMode);
  }

  onFirstDataRendered(params) {
    //	[...]

    let isPivotMode = this.props?.isPivotMode; // boolean
    let isPivotModeDifferent =
      this.gridColumnApi?.isPivotMode() !== this?.props?.isPivotMode;

    if (this?.props?.isPivotMode !== undefined && isPivotModeDifferent) {
      this.gridColumnApi.setPivotMode(isPivotMode);
    }
  }

  render() {
    // [...]
    return (
      <AgGridReact
        onFirstDataRendered={this.onFirstDataRendered.bind(this)}
        onColumnPivotModeChanged={this.onSavePivotModeState.bind(this)}
      />
    );
  }
}

You can learn more about pivoting in AG Grid here - Pivoting, Saving & Restoring Column State with Pivot.

What's next?

I hope you find this article useful when persisting state with AG Grid. Please check out our other blog posts and documentation for a great variety of scenarios you can implement with AG Grid.

If you would like to try out AG-Grid, check out our getting started guides (JS / React / Angular / Vue)

Happy coding!

Read more posts about...