Blazor Pivot Grid State Persistence

    The Ignite UI for Blazor State Persistence in Blazor Pivot Grid allows developers to easily save and restore the grid state. When the IgbGridState is applied on the Blazor IgbPivotGrid, it exposes the GetStateAsStringAsync and ApplyStateFromStringAsync methods that developers can use to achieve state persistence in any scenario.

    Supported Features

    IgbGridState directive supports saving and restoring the state of the following features:

    Usage

    The GetStateAsStringAsync returns a serialized JSON string, so developers can just take it and save it on any data storage (database, cloud, browser localStorage, etc).

    The developer may choose to get only the state for a certain feature/features, by passing in an array with feature names as an argument. Empty array will result to using the default state options.

    <IgbPivotGrid>
        <IgbGridState @ref="gridState"></IgbGridState>
    </IgbPivotGrid>
    
    @code {
        // get all features` state in a serialized JSON string
        string stateString = gridState.GetStateAsStringAsync(new string[0]);
    
        // get the sorting and filtering expressions
        string sortingFilteringStates = gridState.GetStateAsStringAsync(new string[] { "sorting", "filtering" });
    }
    

    ApplyStateFromStringAsync - The method accepts a serialized JSON string as argument and will restore the state of each feature found in the JSON string or specified features as second argument.

    gridState.ApplyStateFromStringAsync(gridStateString, new string[0]);
    gridState.ApplyStateFromStringAsync(sortingFilteringStates, new string[0])
    

    The Options object implements the IgbGridStateOptions interface, i.e. for every key, which is the name of a certain feature, there is the boolean value indicating if this feature state will be tracked. GetStateAsStringAsync methods will not put the state of these features in the returned value and ApplyStateFromStringAsync methods will not restore state for them.

    gridState.Options = new IgbGridStateOptions
        {
            CellSelection = false,
            Sorting = false
        };
    

    The simple to use single-point API's allows to achieve a full state persistence functionality in just a few lines of code. Copy paste the code from below - it will save the grid state in the browser LocalStorage object every time the user leaves the current page. Whenever the user returns to main page, the grid state will be restored. No more need to configure those complex advanced filtering and sorting expressions every time to get the data you want - do it once and have the code from below do the rest for your users:

    @using IgniteUI.Blazor.Controls
    @using Newtonsoft.Json
    @implements IDisposable
    
    @inject IJSRuntime JS
    @inject NavigationManager Navigation
    
    <IgbPivotGrid Rendered="OnGridRendered">
        <IgbGridState @ref="gridState"></IgbGridState>
        <IgbColumn Field="ContactName" Header="Name" MinWidth="200px" ></IgbColumn>
        <IgbColumn Field="ContactTitle" Header="Title" MinWidth="200px" Sortable="true" Filterable="true" Groupable="true"></IgbColumn>
        <IgbColumn Field="CompanyName" Header="Company" MinWidth="200px" Sortable="true" Filterable="true" Groupable="true"></IgbColumn>
    </IgbPivotGrid>
    
    @code {
        protected override void OnAfterRender(bool firstRender)
        {
            Navigation.LocationChanged += OnLocationChanged;
        }
    
        void OnLocationChanged(object sender, LocationChangedEventArgs e)
        {
            SaveGridState();
        }
    
        void IDisposable.Dispose()
        {
            // Unsubscribe from the event when our component is disposed
            Navigation.LocationChanged -= OnLocationChanged;
        }
    
        void OnGridRendered()
        {
            RestoreGridState();
        }
    
        async void SaveGridState() {
            string state = gridState.GetStateAsStringAsync(new string[0]);
            await JS.InvokeVoidAsync("window.localStorage.setItem", "grid-state", state);
        }
    
        async void RestoreGridState() {
            string state = await JS.InvokeAsync<string>("window.localStorage.getItem", "grid-state");
            if (state) {
                gridState.ApplyStateFromStringAsync(state, new string[0]);
            }
        }
    }
    

    Restoring Pivot Configuration

    IgbGridState will not persist pivot dimension functions, value formatters, etc. by default (see limitations). Restoring any of these can be achieved with code on application level. The IgbPivotGrid exposes two events which can be used to set back any custom functions you have in the configuration: DimensionInit and ValueInit. Let's show how to do this:

    • Assign event handlers for the DimensionInit and ValueInit events:
        <IgbPivotGrid
            @ref="grid"
            Width="95%"
            Height="500px"
            PivotConfiguration="PivotConfiguration"
            ValueInitScript="OnValueInit">
        </IgbPivotGrid>
    

    The DimensionInit and ValueInit events are emitted for each value and dimension defined in the PivotConfiguration property.

    • In the ValueInit event handler set all custom aggregators, formatters and styles:
    // In Javascript
    const totalSale = (members, data) => {
        return data.reduce((accumulator, value) => accumulator + value.ProductUnitPrice * value.NumberOfUnits, 0);
    };
    
    const totalMin = (members, data) => {
        let min = 0;
        if (data.length === 1) {
            min = data[0].ProductUnitPrice * data[0].NumberOfUnits;
        } else if (data.length > 1) {
            const mappedData = data.map(x => x.ProductUnitPrice * x.NumberOfUnits);
            min = mappedData.reduce((a, b) => Math.min(a, b));
        }
        return min;
    };
    
    const totalMax = (members, data) => {
        let max = 0;
        if (data.length === 1) {
            max = data[0].ProductUnitPrice * data[0].NumberOfUnits;
        } else if (data.length > 1) {
            const mappedData = data.map(x => x.ProductUnitPrice * x.NumberOfUnits);
            max = mappedData.reduce((a, b) => Math.max(a, b));
        }
        return max;
    };
    
    igRegisterScript("OnValueInit", (args) => {
        const value = args.detail;
        if (value.member === "AmountOfSale") {
          value.aggregate.aggregator = totalSale;
          value.aggregateList?.forEach((aggr) => {
            switch (aggr.key) {
              case "SUM":
                aggr.aggregator = totalSale;
                break;
              case "MIN":
                aggr.aggregator = totalMin;
                break;
              case "MAX":
                aggr.aggregator = totalMax;
                break;
            }
          });
        }
    }, false);
    

    Demo

    Limitations

    • GetState method uses JSON.stringify() method to convert the original objects to a JSON string. JSON.stringify() does not support Functions, thats why the IgbGridState directive will ignore the pivot dimension MemberFunction, pivot values Member, Formatter, custom Aggregate functions, Styles and pivot configuration strategies: ColumnStrategy and RowStrategy.