[HxGrid] A way to persist grid state (sorting, current page) ?
Is there a way to persist (e.g. in a cookie) the current state of the grid? It would be nice if the grid is initialized/restored to its last state after a user navigates back. I understand that the grid state is not enough by itself, but it's current page and sorting are important elements for that purpose.
You can use the CurrentUserState parameter and bind it to persisted field/property of your choice. E.g. serialize it to localStorage, cookie or just to any application-scoped storage (static field, singleton, ...).
Got a warning Component parameter 'CurrentUserState' should not be set outside of its component. Is it (CurrentUserState) json serializable?
You have to use the @bind-CurrentUserState="myField" to bind to the parameter safely.
It should be serializable (let me know if you find the opposite).
Not serializable.
When using Default newtonsoft json serialization settings, exception: "Self referencing loop detected for property 'ManifestModule' with type 'System.Reflection.RuntimeModule'. Path 'Sorting[0].SortKeySelector.Body.Operand.Member.Module.Assembly'."
When using ReferenceLoopHandling.Serialize, program goes into infinite recursion.
When using ReferenceLoopHandling.Ignore, serialization takes suspiciously long time and ends with an exception:
"Unable to find a constructor to use for type System.Linq.Expressions.Expression1[System.Func2[A5Soft.ClaimManager.Domain.Claims.Queries.FullCaseStateQueryResult,System.IComparable]]. A class should either have a default constructor, one constructor with arguments or a constructor marked with the JsonConstructor attribute. Path 'Sorting[0].SortKeySelector.Type', line 1, position 71."
Most likely cause - SortKeySelector property of Expression type.
P.S. it only happens if the grid is sorted by some column. P.P.S. You could actually serialize Expression (e.g. https://github.com/6bee/Remote.Linq), but that would open a huge security hole...
Thanks for opening this issue and testing the serializability. We will prepare some guidance and/or adjustments to enable this use-case (preserving the grid state).
Just to be sure. Do you need to preserve the state over application restart (i.e. next user visit) or just within single application run (i.e. user travels across the app and returns to the screen with grid)? For the second, you can just save the state in app/circuit/scoped service.
cc @jirikanda
I thought about standard user options persistence over application restart but the idea with a scoped service will do for starters.
We had a short chat (ad hoc design meeting :-D) with @jirikanda. Recording major thoughts for future:
- It should be possible to replace the
SortItemusage inGridUserStatewith some sort of alternativeSortItemDtowhere theExpression SortKeySelector(and possiblySortString) will be replaced with some sort of serializable reference to the originatingGridColumn(such as ColumnId) => allowing serialization ofGridUserState - The
HxGriditself would have to interpret such reference when buildingGridDataProviderRequestand pickup theExpression ColumnBase.SortKeySelectorfrom the corresponding columns.
Unfortunately, this is not on top of our priority list, as we do not feel any major demand for the related use-case. Pull-request will be welcomed, sponsorship might also help to prioritize this on our side. :-D
Not a priority for me as well ;) It turned out that my users themselves are not sure if they want to save these specific GUI settings between sessions at all. They are quite happy about single session solution.
I think the feature could be implemented by extension methods without touching HxGrid code. The SortItemDto <-> Dto conversions could be done externally if Expression SortKeySelector could be semantically simplified to a property name (string). Does it always point to a property?
I think the feature could be implemented by extension methods without touching HxGrid code. The SortItemDto <-> Dto conversions could be done externally if Expression SortKeySelector could be semantically simplified to a property name (string). Does it always point to a property?
Unfortunately not. The SortKeySelector can be any expression and in some scenarios it is being used in more complicated way. For the simple sorting "markers" (e.g. for API calls), use SortString where the interpretation of what is the meaning od the SortString value is up to the final data provider.
Took a quick look at your code. I think if you implement HxGrid method
public IEnumerable<Expression<Func<TItem, IComparable>>> GetAvailableSortings()
=> columnsList.Where(c => null != c.SortKeySelector).Select(c => c.SortKeySelector);
the serialization could be simplified by trivial ToString. I.e. you persist SortKeySelector.ToString() and after deserialization just pick one of the existing ones.
the serialization could be simplified by trivial ToString. I.e. you persist SortKeySelector.ToString() and after deserialization just pick one of the existing ones
👍 Also one of the options to be able to rebuild the original state or pick the right expression for the sorting.
...but still we have to take in account the scenarios where the CurrentUserState of the grid is not only saved and restored, but also can be manipulated (e.g. external controls for setting the sorting, etc.). It has to be intuitive for the developers, what the GridUserState holds and how to manipulate it (I admit, that the current implementation is not that friendly for such scenarios in combination with Expression SortKeySelector, we use it with SortString).
...but still we have to take in account the scenarios where the
CurrentUserStateof the grid is not only saved and restored, but also can be manipulated (e.g. external controls for setting the sorting, etc.). It has to be intuitive for the developers, what theGridUserStateholds and how to manipulate it (I admit, that the current implementation is not that friendly for such scenarios in combination withExpression SortKeySelector, we use it withSortString).
Yes, I am looking for functionality to manipulate sorting from the c# code. Tried it with the bind suggestions on CurrentUserState in this post, but it didn't help. I will wait until this feature is implemented.
@jim-craane The functionality was already published in one of earlier releases and is part of the documentation (just forgot to close this issue). See https://havit.blazor.eu/components/HxGrid#persisting-state
On one of our projects, we do manipulate the CurrentUserState from outside. Fragments you might be interested in (this time we didn't use the column Id, but a enum-based SortString for every single column, which is then switch-ed on server side when preparing data for the grid):
private void HandleSortingChanged()
{
var sorting = clientCardListFilterSortModel.ToSortingItems();
currentUserState = currentUserState with { Sorting = sorting };
}
<HxGridColumn ... SortString="@nameof(ClientCardSort.LegalType)" />
public IReadOnlyList<SortingItem<ClientCardListItem>> ToSortingItems()
{
var result = new List<SortingItem<ClientCardListItem>>();
if (Sort.Value is not null)
{
result.Add(new SortingItem<ClientCardListItem>(
Enum.GetName(Sort.Value.SortExpression),
null, Sort.Value.SortDirection, null));
}
return result;
}
public enum ClientCardSort
{
[Description("Podle příjmení")] LastName,
[Description("Podle města")] City,
[Description("Podle typu subjektu")] LegalType,
[Description("Podle rodného čísla")] BirthNumber,
[Description("Podle hodnocení")] Rating,
[Description("Podle platnosti klientské karty")] CardValidity,
[Description("Podle poslední aktivity")] LastActivity,
[Description("Podle datumu vytvoření")] BtCreated,
[Description("Podle splnění GDPR")] HasConsent
}