Localstorage/Persistence not working with Kendo Grid

1 Answer 412 Views
Grid
Thomas
Top achievements
Rank 2
Iron
Thomas asked on 08 May 2023, 09:42 AM

Hi Telerik,

I have a Grid with persistence implemented exactly like described here => https://demos.telerik.com/aspnet-core/grid/persist-state

Sequence of actions:

1) Start application
2) Reorder columns
3) Save state
4) Reorder columns again for testing purpose => another reorder, not reordering back to the original order
5) Load state

=> everything is working fine, order is back to saved state

But:
1) Start application
2) Reorder columns
3) Save state
4) Close app/browser
5) Run app again => original order is back
6) Load state

=> The order of the columns is changing to the saved state, but the Grid hangs in an infinite loop loading the data

 

Grid:


Html.Kendo().Grid<OalViewModel>()
                .Name("grid")
                .Columns(columns =>
                {
                    columns.Bound(p => p.OrderNumber).Filterable(ftb => ftb.Multi(true).Search(true).CheckAll(true)).Width(100).Title("Auftrag").HtmlAttributes(new { style = "text-align: center" }).Locked(true);
                    columns.Command(command => { command.Edit(); }).Width(150).HtmlAttributes(new { style = "text-align: center" }).Locked(true);
                    columns.Bound(p => p.Split).Filterable(ftb => ftb.Multi(true).Search(true).CheckAll(true)).Width(80).HtmlAttributes(new { style = "text-align: center" });
                    columns.Bound(p => p.OrderType).Filterable(ftb => ftb.Multi(true).Search(true).CheckAll(true)).Width(80).Title("Art").HtmlAttributes(new { style = "text-align: center" });
                    columns.Bound(p => p.OutletIndicator).Filterable(ftb => ftb.Multi(true).Search(true).CheckAll(true)).Width(80).Title("FIL").HtmlAttributes(new { style = "text-align: center" });
                    columns.Bound(p => p.AcceptanceDate).Format("{0: dd.MM.yyyy}").Filterable(ftb => ftb.Cell(y => y.Template("datePicker"))).Title("Angenommen am").Width(150).HtmlAttributes(new { style = "text-align: center" });
                    columns.Bound(p => p.AcceptedBy).Filterable(ftb => ftb.Multi(true).Search(true).CheckAll(true)).Title("Angenommen von").Width(150).HtmlAttributes(new { style = "text-align: center" });
                    columns.Bound(p => p.CreatedBy).Filterable(ftb => ftb.Multi(true).Search(true).CheckAll(true)).Title("Erstellt von").Width(125).HtmlAttributes(new { style = "text-align: center" });
                    columns.Bound(p => p.Make).Filterable(ftb => ftb.Multi(true).Search(true).CheckAll(true)).Title("Marke").Width(80).HtmlAttributes(new { style = "text-align: center" });
                    columns.Bound(p => p.Status).Filterable(ftb => ftb.Multi(true).Search(true).CheckAll(true)).Width(80).HtmlAttributes(new { style = "text-align: center" });
                    columns.Bound(p => p.InvoiceDate).Format("{0: dd.MM.yyyy}").Filterable(ftb => ftb.Cell(y => y.Template("datePicker"))).Title("RG-Dat.").Width(100).HtmlAttributes(new { style = "text-align: center" });
                    columns.Bound(p => p.InvoicePrintedOk).Filterable(ftb => ftb.Multi(true).Search(true).CheckAll(true)).Title("RG-Druck").Width(80).HtmlAttributes(new { style = "text-align: center" });
                    columns.Bound(p => p.LicenseNumber).Filterable(ftb => ftb.Multi(true).Search(true).CheckAll(true)).Title("Kennz.").Width(100).HtmlAttributes(new { style = "text-align: center" });
                    columns.Bound(p => p.CustomerNumber).Filterable(ftb => ftb.Multi(true).Search(true).CheckAll(true)).Title("KD-Nr").Width(100).HtmlAttributes(new { style = "text-align: center" });
                    columns.Bound(p => p.Customer).Filterable(ftb => ftb.Multi(true).Search(true).CheckAll(true)).Title("KD").Width(100);
                    columns.Group(x => x
                        .Title("Integration").HeaderHtmlAttributes(new { style = "border-color:#642A3F; border: 1pt solid #642A3F;" })
                        .Columns(info =>
                        {
                            info.Bound(p => p.ExactDescription).Width(250).HtmlAttributes(new { style = "border-color:#642A3F; border: 1pt solid #642A3F; text-align: left" }).HeaderHtmlAttributes(new { style = "border-color:#642A3F; border: 1pt solid #642A3F" }).Title("Genaue Beschreibung");
                            info.Bound(p => p.PlannedCompletionDate).Format("{0: dd.MM.yyyy}").Filterable(ftb => ftb.Cell(y => y.Template("datePicker"))).HtmlAttributes(new { style = "border-color:#642A3F; border: 1pt solid #642A3F; text-align: center" }).HeaderHtmlAttributes(new { style = "border-color:#642A3F; border: 1pt solid #642A3F" }).Title("Fertigstellung").Width(100);
                            info.Bound(p => p.PlannedSettlementDate).Format("{0: dd.MM.yyyy}").Filterable(ftb => ftb.Cell(y => y.Template("datePicker"))).HtmlAttributes(new { style = "border-color:#642A3F; border: 1pt solid #642A3F; text-align: center" }).HeaderHtmlAttributes(new { style = "border-color:#642A3F; border: 1pt solid #642A3F" }).Title("RG-Stellung").Width(100);
                            info.Bound(p => p.OrderAvailable).Filterable(ftb => ftb.Multi(true).Search(true).CheckAll(true)).HtmlAttributes(new { style = "border-color:#642A3F; border: 1pt solid #642A3F; text-align: center" }).HeaderHtmlAttributes(new { style = "border-color:#642A3F; border: 1pt solid #642A3F" }).Title("Auftrag vorhanden?").Width(100);
                            info.Bound(p => p.OrderBillable).Filterable(ftb => ftb.Multi(true).Search(true).CheckAll(true)).HtmlAttributes(new { style = "border-color:#642A3F; border: 1pt solid #642A3F; text-align: center" }).HeaderHtmlAttributes(new { style = "border-color:#642A3F; border: 1pt solid #642A3F" }).Title("Auftrag abrechenbar?").Width(100);
                            //info.Bound(p => p.OrderStatus).Filterable(ftb => ftb.Multi(true).Search(true).CheckAll(true)).HtmlAttributes(new { style = "border-color:#642A3F; border: 1pt solid #642A3F" }).HeaderHtmlAttributes(new { style = "border-color:#642A3F; border: 1pt solid #642A3F" }).Title("Auftrags-Status?").Width(100);

                        }));
                    columns.Bound(p => p.OrderValueTotal).Format("{0:C}").ClientFooterTemplate("#= kendo.format('{0:c}', sum)#").Title("Auftragswert").Width(100).HtmlAttributes(new { style = "text-align: center" });
                    columns.Bound(p => p.Tax).Format("{0:C}").ClientFooterTemplate("#= kendo.format('{0:c}', sum)#").Title("Steuer").Width(100).HtmlAttributes(new { style = "text-align: center" });
                    columns.Bound(p => p.OrderValueTotalNoTax).Format("{0:C}").ClientFooterTemplate("#= kendo.format('{0:c}', sum)#").Title("Auftragswert o. MwSt.").Width(100).HtmlAttributes(new { style = "text-align: center" });
                    columns.Bound(p => p.OrderValueVehicle).Format("{0:C}").ClientFooterTemplate("#= kendo.format('{0:c}', sum)#").Title("Auftragswert Fzg").Width(100).HtmlAttributes(new { style = "text-align: center" });
                    columns.Bound(p => p.OrderValueEquipment).Format("{0:C}").ClientFooterTemplate("#= kendo.format('{0:c}', sum)#").Title("Auftragswert Zubehör").Width(100).HtmlAttributes(new { style = "text-align: center" });
                    columns.Bound(p => p.OrderValueFlatRateUnits).Format("{0:C}").ClientFooterTemplate("#= kendo.format('{0:c}', sum)#").Title("Auftragswert AW").Width(100).HtmlAttributes(new { style = "text-align: center" });
                    columns.Bound(p => p.OrderValueParts).Format("{0:C}").ClientFooterTemplate("#= kendo.format('{0:c}', sum)#").Title("Auftragswert Teile").Width(100).HtmlAttributes(new { style = "text-align: center" });
                    columns.Bound(p => p.OrderValueSublets).Format("{0:C}").ClientFooterTemplate("#= kendo.format('{0:c}', sum)#").Title("Auftragswert Sonstiges").Width(100).HtmlAttributes(new { style = "text-align: center" });
                })
                .ColumnResizeHandleWidth(20)
                .ColumnMenu()
                .Sortable()
                .Scrollable(s => s.Height("auto"))
                .Filterable()
                .Reorderable(reorder => reorder.Columns(true))
                .Editable(editable => editable.Mode(GridEditMode.PopUp).TemplateName("CustomPopupOAL"))
                .ToolBar(toolbar =>
                {
                     toolbar.Custom().Text("Import DMS").IconClass("k-icon k-i-file-excel").HtmlAttributes(new { id = "customCommand" });
                     toolbar.Excel();
                     toolbar.Pdf();
                     toolbar.Custom().Text("Ansicht speichern").IconClass("k-icon k-i-export").HtmlAttributes(new { id = "save" });
                     toolbar.Custom().Text("Ansicht laden").IconClass("k-icon k-i-import").HtmlAttributes(new { id = "load" });
                     toolbar.Search();
                })
                .Pdf(pdf => pdf.AllPages(true))
                .Excel(excel => excel.AllPages(true))
                .Pageable(p => p
                     .ButtonCount(5)
                     .PageSizes(new[] { 10, 25, 50 })
                     .Refresh(true)
                     .Input(true)
                )
                .HtmlAttributes(new { style = "height:600px;" })
                .DataSource(dataSource => dataSource
                    .SignalR()
                    .AutoSync(false)
                    .PageSize(10)
                    .Aggregates(aggregates =>
                    {
                        aggregates.Add(p => p.OrderValueTotal).Sum();
                        aggregates.Add(p => p.Tax).Sum();
                        aggregates.Add(p => p.OrderValueTotalNoTax).Sum();
                        aggregates.Add(p => p.OrderValueVehicle).Sum();
                        aggregates.Add(p => p.OrderValueEquipment).Sum();
                        aggregates.Add(p => p.OrderValueFlatRateUnits).Sum();
                        aggregates.Add(p => p.OrderValueParts).Sum();
                        aggregates.Add(p => p.OrderValueSublets).Sum();
                    }                    )
                    .Transport(tr => tr
                        .Promise("hubStart")
                        .Hub("hub")
                        .Client(c => c
                            .Read("read")
                            .Create("create")
                            .Update("update")
                            .Destroy("destroy"))
                        .Server(s => s
                            .Read("read")
                            .Create("create")
                            .Update("update")
                            .Destroy("destroy")))
                    .Schema(schema => schema
                        .Model(model =>
                        {
                            model.Id(order => order.OrderNumber);
                            model.Field(p => p.OrderNumber).Editable(false);
                            model.Field(p => p.Split).Editable(false);
                            model.Field(p => p.OrderType).Editable(false);
                            model.Field(p => p.OutletIndicator).Editable(false);
                            model.Field(p => p.AcceptanceDate).Editable(false);
                            model.Field(p => p.AcceptedBy).Editable(false);
                            model.Field(p => p.CreatedBy).Editable(false);
                            model.Field(p => p.Make).Editable(false);
                            model.Field(p => p.Status).Editable(false);
                            model.Field(p => p.InvoiceDate).Editable(false);
                            model.Field(p => p.InvoicePrintedOk).Editable(false);
                            model.Field(p => p.LicenseNumber).Editable(false);
                            model.Field(p => p.CustomerNumber).Editable(false);
                            model.Field(p => p.Customer).Editable(false);
                        }
                 )
              )
            )

Javascript:


<script>
    $(document).ready(function () {
        var grid = $("#grid").data("kendoGrid");

        $("#save").click(function (e) {
            e.preventDefault();
            localStorage.kendogridoptions = kendo.stringify(grid.getOptions());

        });

        $("#load").click(function (e) {
            e.preventDefault();
            var options = localStorage.kendogridoptions;
            if (options) {
                grid.setOptions(JSON.parse(options));
            }
        });

    });
</script>

Note: In the javascript code above you will see a difference to the demo code. I Changed 


localStorage["kendo-grid-options"] = kendo.stringify(grid.getOptions());

to


localStorage.kendogridoptions = kendo.stringify(grid.getOptions());

Because I researched the problem and found a lot of sources telling that the proper/better way of accessing the localstorage would be by using "localStorage.<VALUE-NAME>".

But first I tried with the exaxt demo code, also running into the same problem.

What am I doing wrong? After restarting the app and loading the state, the order of the colums is changed, but the grid is unable to load the data.

Is it because I use SignalR binding? I need realtime updates as many users are working in the same grid at the same time, and this is only working with SignalR, correct?

Appreciate any tips!

Thanks

Thomas

1 Answer, 1 is accepted

Sort by
0
Accepted
Mihaela
Telerik team
answered on 10 May 2023, 04:57 PM

Hello Thomas,

Thank you for providing the Grid configuration and taking the time to describe the overall scenario in detail.

Generally, the getOptions() method retrieves the current state of the Grid and its DataSource. When setting all Grid options through the setOptions() method, the Grid's DataSource configuration options are modified, as well. However, when the Grid is set up with SignalR binding, the setOptions() method could not be directly integrated with the SignalR hub. The Grid is destroyed and recreated based on the passed options, but the Grid's DataSource cannot reconnect to the SignalR Hub. With that said, I am afraid the Save State functionality is not supported for SignalR bound Grid.

However, if you need to persist particular Grid options rather than all options (for example, the columns and their order, visibility and etc.), you could pass only the required options to the setOptions() method:

        $("#load").click(function (e) {
            e.preventDefault();
            var options = localStorage.kendogridoptions;
            if (options) {
                let parsedOptions = JSON.parse(options); //parse the stored options
                grid.setOptions({ columns: parsedOptions.columns }); //apply the persisted column options
            }
        });

As an alternative, you would have to apply all of the options via the exposed API methods. You could find the full list of methods here:

https://docs.telerik.com/kendo-ui/api/javascript/ui/grid#methods

Finally, If you feel this feature is important for you, I can suggest submitting a feature request in our Feedback portal. We regularly monitor the items there and the ones that gain lots of popularity are usually included in the Road Map.

https://feedback.telerik.com/aspnet-core-ui/

Let me know if you have any questions.

Regards, Mihaela Progress Telerik

Stay tuned by visiting our public roadmap and feedback portal pages! Or perhaps, if you are new to our Telerik family, check out our getting started resources
Thomas
Top achievements
Rank 2
Iron
commented on 10 May 2023, 05:37 PM

Hi Mihaela,

thank you very much for the explanation and the example!

It works perfectly for the order of the columns!

The only thing which is still relevant and not loaded are the filters saved for each column. Is there any chance to load them separately from the saved options without using the API stuff?

Thanks

Thomas

Mihaela
Telerik team
commented on 15 May 2023, 08:21 AM

Hello Thomas,

Thank you for your response.

To avoid triggering the setOptions() method for the Grid's DataSource options (i.e., filters), I would recommend the following approach:

  • Access the saved column filters through the "parsedOptions" variable and use the filter() method of the DataSource to apply them:
        $("#load").click(function (e) {
            e.preventDefault();
            var options = localStorage.kendogridcustomoptions;
            if (options) {
                let parsedOptions = JSON.parse(options);
                grid.setOptions({ columns: parsedOptions.columns, sortable: parsedOptions.sortable});
                grid.dataSource.filter(parsedOptions.dataSource.filter);
            }
        });

Best,

Mihaela

Thomas
Top achievements
Rank 2
Iron
commented on 15 May 2023, 08:27 AM

Hi Mihaela,

works perfectly, thanks!

Cheers
Thomas

Tags
Grid
Asked by
Thomas
Top achievements
Rank 2
Iron
Answers by
Mihaela
Telerik team
Share this question
or