Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Datagrid in SaveStateInUrl (not working for sort orientation) #3128

Closed
fdonnet opened this issue Jan 6, 2025 · 6 comments
Closed

fix: Datagrid in SaveStateInUrl (not working for sort orientation) #3128

fdonnet opened this issue Jan 6, 2025 · 6 comments
Labels
triage New issue. Needs to be looked at

Comments

@fdonnet
Copy link

fdonnet commented Jan 6, 2025

🐛 Bug Report

This "SaveStateInUrl" option on datagrid is not working for sort orientation. When the sort is "desc" it's rolled back to "asc".

The private void SaveStateToQueryString() seems to work correctly. The "desc" option is correctly put in the url but when the param is used in
private void LoadStateFromQueryString(string queryString) the url is rolled back to "asc"

?orderby=Code desc&page=2&top=25 then refresh and it becomes ?orderby=Code asc&page=2&top=25

🤔 Expected Behavior

Sort orientation needs to be keeped between calls

😯 Current Behavior

"Desc" orientation saving seems to work, but not the loading.

💁 Possible Solution

I'm on 4.11, so maybe it's already corrected on the dev branch. I cannot identify the problem in the dev branch code.

🔦 Context

I want to use that to pass state between pages and be able to come back with the correct state on the grid.
If I had the possibility to extract the sort values (title + orientation) from the Grid itself via a property I would not use the url but manage the state myself. I didn't find this possibility, maybe I m missing someting...

🌍 Your Environment

4.11

@microsoft-github-policy-service microsoft-github-policy-service bot added the triage New issue. Needs to be looked at label Jan 6, 2025
@fdonnet
Copy link
Author

fdonnet commented Jan 6, 2025

I think I will end up making something as bad as that to retrieve the current sort state.

var columnSortedName = ReflectionTweak.GetPrivateFieldValue<ColumnBase<AuthorizationUiObj>?>(_grid, "_sortByColumn")?.Title;
var sortDirection = (_grid.SortByAscending ?? false) ? "asc" : "desc";
    public static class ReflectionTweak
    {
        public static T? GetPrivateFieldValue<T>(object obj, string fieldName)
        {
            return (T?)obj.GetType()
                          .GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic)?
                          .GetValue(obj);
        }
    }

My final goal is to store the state in a scoped service.

  • Page number
  • Search value (I don't use column filter but a separate FluentSearch)
  • Sort info
  • New Id or edit Id info (when present) to put the user on the correct grid page after he added or eddited a resource on another site page. (cannot really use the panel thing for now).

I think it will work.

But to avoid the dirty reflection thing. A public property that retrieves the sort "title" info will be really cool for my use case.

@vnbaaij
Copy link
Collaborator

vnbaaij commented Jan 10, 2025

As mentioned in the code comment. saving the state in the URL is an experimental feature.

What I've found so far is that when reading the query string, the 'desc' is read correctly but it get overwritten by the value of the default sort column. I've not found a way to overcome that yet.

Closing this issue for now. We will take this into account when we work on the feature more.

@vnbaaij vnbaaij closed this as completed Jan 10, 2025
@fdonnet
Copy link
Author

fdonnet commented Jan 10, 2025

thx, I used my state thing. It allows more flexibility.
The cool thing with url, it's that the user can save the present state in his Favorites.

Thx for the return.

@vnbaaij
Copy link
Collaborator

vnbaaij commented Jan 10, 2025

@fdonnet interested to see what you have done with your state thing. Would be great if you can share! If not, that is fine too.

@fdonnet
Copy link
Author

fdonnet commented Jan 10, 2025

nothing really fancy... and it stays maybe too much time in memory (life of the circuit) if on interative server. But because I use interactive auto, I think it's fine.

In my shared project I have small service like that

    public class AuthorizationsState
    {
        public int CurrentPageNumber { get; private set; } = 0;
        public string? SortColumnName { get; private set; }
        public string SortColumnDirection { get; private set; } = "asc";
        public string? SearchValue { get; private set; }
        public int ItemsPerPage { get; private set; } = 20;
        public Guid? SelectedId { get; private set; }


        public void UpdateGridState(int pageIndex, string? searchValue, string? sortColumnName, string sortColumnDirection, int itemsPerPage)
        {
            CurrentPageNumber = pageIndex;
            SearchValue = searchValue;
            SelectedId = null;
            SortColumnName = sortColumnName;
            SortColumnDirection = sortColumnDirection;
            ItemsPerPage = itemsPerPage;
        }

        public void SetSelectedId(Guid selectedId)
        {
            CurrentPageNumber = 1;
            SearchValue = null;
            SelectedId = selectedId;
            SortColumnName = "Code";
            SortColumnDirection = "asc";
        }

        public void CleanGridState()
        {
            CurrentPageNumber = 1;
            SearchValue = null;
            SelectedId = null;
            SortColumnName = null;
            SortColumnDirection = "asc";
            ItemsPerPage = 20;
        }
    }

"AuthorizationsState" is just the name related to the state on my pages managing "autorizations" resources.

This service is declared as scoped in the server project and as singleton in client-wasm project. (for auto mode)

When I click on the add or edit button from the grid that will drive me to another page /add or /{id]. I update the state with

        private void UpdateStateForTheGrid()
        {
            var columnSortedName = ReflectionTweak.GetPrivateFieldValue<ColumnBase<AuthorizationUiObj>?>(_grid, "_sortByColumn")?.Title;
            var sortDirection = (_grid.SortByAscending ?? false) ? "asc" : "desc";

            _state.UpdateGridState(_pagination.CurrentPageIndex, _searchValue, columnSortedName, sortDirection, _pagination.ItemsPerPage);
        }

That's here that I use the "reflection" bad thing to be able to store the title of the column that is sorted.

On my edit or add page, if the operation is cancelled or if the user click on the FluentBreadcrum 😉 , it comes back to the page with this info in the url "?state=true".

If the add or edit is OK:

I just set the state to
_state.SetSelectedId(result!.Id);
before navigating to "?state=true"

On my main grid page when the state query param is present I will do someting questionnable in OnInitializedAsync :

if (RendererInfo.IsInteractive)
{
    _isLoading = true;

    await RefreshDataAsync(false);
    await InvokeAsync(StateHasChanged);
    await ManageStateAsync();

    _isLoading = false;
}

I refresh the grid, call a "statechanged" and after I will put back my state information.

        private async Task ManageStateAsync()
        {
            if (!string.IsNullOrEmpty(UseState) && bool.TryParse(UseState, out _))
            {
                if (!(await ManageSelectedItemInState()))
                {
                    await ManagePageNumberAsync();
                    await ManageSortAsync();
                    ManageSearchValue();
                    ManageItemsPerPage();
                }
            }
            else
            {
                _state.CleanGridState();
            }
        }

It works not too bad... when an Edit or Add is made... the grid is shown on the correct page and the new/edited items is selected .I choose to not sort or filter when a write operation was made, or we will have the case where the new item is not present to be selected (maybe I will retrieve the sort for this case... will see).
But if it's a back to the page, the grid is like before even with the filter/search etc

It seems to work... and I think it will work not too bad if the state service is updated on the same side (wasm/server) in auto mode. I need to test if I have case where the state is set serverside and the add/edit compos(pages) are in "webassembly" already...

EDIT:

When writting this, I saw that I can call the await InvokeAsync(StateHasChanged); only if the ?state=true is present, and it will be better 😄

@fdonnet
Copy link
Author

fdonnet commented Jan 10, 2025

When a selectedId is present, after an edit or add I do that:

        private async Task<bool> ManageSelectedItemInState()
        {
            if (_state.SelectedId != null)
            {
                var newItem = _authorizations?.FirstOrDefault(a => a.Id == _state.SelectedId);

                if (newItem != null && _authorizations != null)
                {
                    //Select the item
                    newItem.Selected = true;

                    // Navigate to the page containing the new item (code is the primary sort)
                    var pageIndex = _authorizations!
                        .OrderBy(x => x.Code)
                        .ToList()
                        .FindIndex(a => a.Id == newItem.Id) / _pagination.ItemsPerPage;

                    await _pagination.SetCurrentPageIndexAsync(pageIndex);

                    //Reset the state
                    ManageItemsPerPage();
                    _state.UpdateGridState(pageIndex, null, "Code", "asc", _pagination.ItemsPerPage);

                    return true;
                }
            }

            return false;
        }

It will not work with "virtualized" etc.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
triage New issue. Needs to be looked at
Projects
None yet
Development

No branches or pull requests

2 participants