When I put a sort order property on one of my columns on a table in which the data is loaded in through an async api call, the columns do not render sorted. If I initialize the list with some values that are displayed on the table, they will be sorted and the little arrow will show on the column header indicating that it is sorted. However, if the list is created empty and the api calls go through and replace the data in the list, the table is no longer sorts the new values. The same little arrow is still on the column header, but the values are in whatever order they came in and the column header must be clicked to properly sort the data. How do I have the new data automatically be sorted?
A code example demonstrating the problem can help us to provide more info or fix if necessary.
The goal of this whole thing is to save a user's sort preferences on a page reload. There's a lot of code but here are the main parts:
There's the table
<RadzenDataGrid .... Data="@migrations" Sort=@OnSortChange ...>
The function that stores the SortOrder using a ProtectedLocalStorage service
private async Task OnSortChange(DataGridColumnSortEventArgs<LatestMigration> evt){
await store.SetAsync($"latest_migrations_grid_sort:{evt.Column.Property}", ColumnSortData.FromColumnSort<LatestMigration>(evt));
}
The SortOrder is grabbed out in OnAfterRenderAsync (.s for indentation):
protected override async Task OnAfterRenderAsync(){
...bool filtered = false;
...foreach (var col in dataGrid.ColumnsCollection){
......var sort = await store.GetAsync<ColumnSortData>($"latest_migrations_grid_sort:{col.Property}");
......if (sort.Success){
.........col.SortOrder = sort.Value?.SortOrder;
.........filtered = true;
......}
...}
...if (filtered){
......await dataGrid.Reload();
...}
...StateHasChanged();
}
and the data is retrieved in OnParametersSetAsync:
protected override async Task OnParametersSetAsync(){
IEnumerable<LatestMigration> result = await client.GetLatestMigrationsAsync(siteFilter);
migrations = result?.ToList() ?? new List<LatestMigration>();
StateHasChanged();
}
All of this results in the sort arrow showing up on the columns that were sorted by the user before the page was reloaded, but the data is not sorted. Strangely enough, the filter works correctly using the exact same method, but the sort does not.
I’m afraid I hardly read what you’ve pasted - what I’ve asked is runnable code example that reproduces the problem.
here is an isolated example of the column being set to Descending but the data not sorting. You can see that the arrow shows up on the column but the data is not sorted.
@page "/example"
<RadzenDataGrid Data="@migrations" Count="@migrations.Count" TItem="ThingInventor" @ref=@dataGrid AllowSorting="true" ColumnWidth="200px">
<Columns>
<RadzenDataGridColumn TItem="ThingInventor" Property="Name" Title="Name" />
</Columns>
</RadzenDataGrid>
@code {
List<ThingInventor> migrations;
private RadzenDataGrid<ThingInventor> dataGrid;
protected override void OnAfterRender(bool firstRender)
{
foreach (var col in dataGrid.ColumnsCollection)
{
col.SortOrder = SortOrder.Descending;
}
dataGrid.Reload();
}
protected override async Task OnInitializedAsync()
{
await Refresh();
StateHasChanged();
}
private async Task Refresh()
{
migrations = new List<ThingInventor>() { new ThingInventor("A"), new ThingInventor("C"), new ThingInventor("B") };
}
public class ThingInventor
{
public string Name { get; private set; }
public ThingInventor(string name)
{
Name = name;
}
}
}
Yes, but the goal here is to retrieve the SortOrder that the user has chosen from local storage, which can only be done in OnAfterRender. Is there any better way to save the SortOrder state?
This does seem to be what I'm looking for and it works perfectly when I use the example in the code, but when I implement it in my own page by copying all the functions, it does not work. It seems that in the Radzen example, the LoadStateAsync method runs once when the page is loaded and SaveStateAsync runs once when the table is sorted, as expected. However on my page, every time I refresh, SaveStateAsync runs twice, then LoadStateAsync, then SaveStateAsync again before the page is fully loaded. All I did was copy the functions exactly from the example or add them to an existing function, OnAfterRenderAsync, for example. Do you have any idea what might be causing this? What exactly calls these functions?
@enchev Looking in further, it seems that the cause of this is the data being loaded through an asynchronous call. If you take the given example in the page you linked me and load the Employee list in through an async call instead of dbContext.Employees, you will see that it ceases to load the saved settings on a page refresh.
Here is a modified version of our example that might be useful in your case:
@page "/datagrid-save-settings"
@using Radzen
@using RadzenBlazorDemos.Data
@using RadzenBlazorDemos.Models.Northwind
@using Microsoft.EntityFrameworkCore
@using RadzenBlazorDemos.Services
@using Microsoft.JSInterop
@using System.Text.Json
@inject IJSRuntime JSRuntime
@inject NavigationManager NavigationManager
@inherits DbContextPage
<RadzenText TextStyle="TextStyle.H3" TagName="TagName.H1" Class="my-4">
DataGrid <strong>save settings</strong>
</RadzenText>
<RadzenExample Name="DataGridSaveSettings" Heading="false" Documentation="false">
<p>This example shows how to save/load DataGrid state using Settings property.</p>
<p>The state includes current page index, page size, groups and columns filter, sort, order, width and visibility.</p>
<RadzenButton Click="@(args => Settings = null)" Text="Clear saved settings" Style="margin-bottom: 16px" />
<RadzenButton Click="@(args => NavigationManager.NavigateTo("/datagrid-save-settings", true))" Text="Reload" Style="margin-bottom: 16px" />
<RadzenDataGrid @bind-Settings="@Settings" AllowFiltering="true" AllowColumnPicking="true" AllowGrouping="true" AllowPaging="true" PageSize="4"
AllowSorting="true" AllowMultiColumnSorting="true" ShowMultiColumnSortingIndex="true"
AllowColumnResize="true" ColumnWidth="200px"
FilterCaseSensitivity="FilterCaseSensitivity.CaseInsensitive" Data="@employees" TItem="Employee">
<Columns>
<RadzenDataGridColumn TItem="Employee" Property="Photo" Title="Employee" Sortable="false" Filterable="false">
<Template Context="data">
<RadzenImage Path="@data.Photo" style="width: 40px; height: 40px; border-radius: 8px; margin-right: 8px;" />
@data.FirstName @data.LastName
</Template>
</RadzenDataGridColumn>
<RadzenDataGridColumn TItem="Employee" Property="Title" Title="Title" />
<RadzenDataGridColumn TItem="Employee" Property="EmployeeID" Title="Employee ID" />
<RadzenDataGridColumn TItem="Employee" Property="HireDate" Title="Hire Date" FormatString="{0:d}" />
<RadzenDataGridColumn TItem="Employee" Property="City" Title="City" />
<RadzenDataGridColumn TItem="Employee" Property="Country" Title="Country" />
</Columns>
</RadzenDataGrid>
</RadzenExample>
<EventConsole @ref=@console Class="mt-4" />
@code {
IEnumerable<Employee> employees;
EventConsole console;
bool loaded;
protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();
await Task.Delay(2000);
employees = await Task.FromResult(dbContext.Employees);
loaded = true;
}
DataGridSettings _settings;
public DataGridSettings Settings
{
get
{
return _settings;
}
set
{
if (_settings != value)
{
_settings = value;
}
}
}
private async Task LoadStateAsync()
{
await Task.CompletedTask;
var result = await JSRuntime.InvokeAsync<string>("window.localStorage.getItem", "Settings");
if (!string.IsNullOrEmpty(result))
{
_settings = JsonSerializer.Deserialize<DataGridSettings>(result);
}
}
private async Task SaveStateAsync()
{
await Task.CompletedTask;
await JSRuntime.InvokeVoidAsync("eval", $@"window.localStorage.setItem('Settings', '{JsonSerializer.Serialize<DataGridSettings>(Settings)}')");
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender || loaded)
{
await LoadStateAsync();
StateHasChanged();
loaded = false;
}
else
{
await SaveStateAsync();
}
}
}
Thank you, this works perfectly. One last issue is that the sort indexes come back in ascending order instead of the original order. For example, if you sort by EmployeeID first, there will be the number 1in the blue circle on the Employee ID column header, and then by Title which puts the number 2 in the Title header, so going left to right the sort index will be 2 then 1. However if you refresh the page, the indexes will come back 1 then 2.

