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

[DataGrid] Provide alternate way to refresh when working with remote data #3423

Merged
merged 6 commits into from
Mar 3, 2025

Conversation

EvandroMoSou
Copy link
Contributor

Pull Request

📖 Description

Using ItemsProvider and Virtualize like the sample in DataGrid Remote Data the API is called 6 or 7 times. Although it has a CancellationToken in the request this is not enough to mitigate the API's resource consumption.

You can test using the code below on the screen, or seeing the calls to the api in the output:

@using Microsoft.FluentUI.AspNetCore.Components

@inject HttpClient Http
@inject NavigationManager NavManager

<div style="height: 434px; overflow:auto;" tabindex="-1">
    <FluentDataGrid
                    ItemsProvider="foodRecallProvider"
                    OnRowDoubleClick="@(()=>DemoLogger.WriteLine("Row double clicked!"))"
                    Virtualize="true"
                    ItemSize="46"
                    GenerateHeader="GenerateHeaderOption.Sticky"
                    TGridItem="FoodRecall" >
        <PropertyColumn Title="ID" Property="@(c => c!.Event_Id)" />
        <PropertyColumn Property="@(c => c!.State)" Style="color: #af5f00 ;" />
        <PropertyColumn Property="@(c => c!.City)" />
        <PropertyColumn Title="Company" Property="@(c => c!.Recalling_Firm)" Tooltip="true"/>
        <PropertyColumn Property="@(c => c!.Status)" />
        <TemplateColumn Title="Actions" Align="@Align.End">
            <FluentButton aria-label="Edit item" IconEnd="@(new Icons.Regular.Size16.Edit())" OnClick="@(() => DemoLogger.WriteLine("Edit clicked"))" />
            <FluentButton aria-label="Delete item" IconEnd="@(new Icons.Regular.Size16.Delete())" OnClick="@(() => DemoLogger.WriteLine("Delete clicked"))" />
        </TemplateColumn>
    </FluentDataGrid>
</div>

<p>Total: <strong>@numResults results found</strong></p>
<p>Call Times: <strong>@qtdCall</strong></p>


@code {
    GridItemsProvider<FoodRecall> foodRecallProvider = default!;
    int? numResults;
    int qtdCall;

    protected override async Task OnInitializedAsync()
    {
        // Define the GridRowsDataProvider. Its job is to convert QuickGrid's GridRowsDataProviderRequest into a query against
        // an arbitrary data soure. In this example, we need to translate query parameters into the particular URL format
        // supported by the external JSON API. It's only possible to perform whatever sorting/filtering/etc is supported
        // by the external API.
        foodRecallProvider = async req =>
        {
            qtdCall++;
            await InvokeAsync(StateHasChanged);

            var url = NavManager.GetUriWithQueryParameters("https://api.fda.gov/food/enforcement.json", new Dictionary<string, object?>
                    {
                { "skip", req.StartIndex },
                { "limit", req.Count },
                    });

            var response = await Http.GetFromJsonAsync<FoodRecallQueryResult>(url, req.CancellationToken);

            // Simulate a slow data retrieval process
            if (req.Count is null)
            {
                await Task.Delay(2500);
            }
            return GridItemsProviderResult.From(
                items: response!.Results,
                totalItemCount: response!.Meta.Results.Total);
        };

        // Display the number of results just for information. This is completely separate from the grid.
        numResults = (await Http.GetFromJsonAsync<FoodRecallQueryResult>("https://api.fda.gov/food/enforcement.json"))!.Meta.Results.Total;
    }
}

After several failed attempts due to multiples refresh by QuickGrid and loss of sequence due to cancellation tokens. I decided to deal with the problem with a different approch.

Normally the API itself takes care of filtering, sorting and pagination, so a new type of grid update was created the 'RefreshItems'.

Basically you can define a method that will call the API.
This method is called once and only once when there is a change in the request (initial, pagination, ordering).
You must update the 'Items' and the 'SetTotalItemCountAsync'.

Along with the necessary commit, the page 'DataGridRemoteData.razor' was updated so you can see how it works.
The display of records, pagination and sorting are working.

Additionally, the option to force the datagrid refresh was added, so that if there is an API filter on the screen that has been modified, you can treat this refresh as a change in the requset.
And a new property in the column 'SortName' to facilitate the assembly of the request for the api.

🎫 Issues

#1066

👩‍💻 Reviewer Notes

Start the application and go to "/datagrid-remote-data" you can test here.

📑 Test Plan

I did it in a way that the old datagrid functions will not be affected if you have not defined the 'RefreshItems'.
Refresh force is optional and is set to false, so nothing changes for old things either.
And I believe that the new property in the column does not affect anything

✅ Checklist

General

  • I have added tests for my changes.
  • [X ] I have tested my changes.
  • I have updated the project documentation to reflect my changes.
  • I have read the CONTRIBUTING documentation and followed the standards for this project.

Component-specific

  • I have added a new component
  • I have added Unit Tests for my new component
  • I have modified an existing component
  • I have validated the Unit Tests for an existing component

⏭ Next Steps

Check the interaction of the grid's internal filtering with the new method

@EvandroMoSou
Copy link
Contributor Author

I agree with the CLA

@vnbaaij
Copy link
Collaborator

vnbaaij commented Feb 21, 2025

Hi, Thanks for your contribution. We will take a good look soon.

You need to agree to the CLA in the format as mentioned.

@EvandroMoSou
Copy link
Contributor Author

@microsoft-github-policy-service agree

Copy link
Collaborator

@vnbaaij vnbaaij left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your contribution! Sorry it took a while to review.

There is basically only 1 change I want to see: Create a new page for the altered DataGridRemoteData sample and leave the 'old' one as-is. Now that we have separate grid sample pages it is easy to have (and good) to have more. People can compare the code of both samples to find the differences. And maybe you can also explain what the differences are in the sample page itself.

@vnbaaij vnbaaij removed the request for review from dvoituron February 24, 2025 22:06
@vnbaaij vnbaaij added this to the v4.11.6 milestone Feb 24, 2025
@EvandroMoSou
Copy link
Contributor Author

I reverted the old page, added the new example and fulfilled the requests mentioned.

If you have any other points to adjust, I am at your disposal.

@vnbaaij vnbaaij changed the title Fix DataGrid remote data calling API multiple times. [DataGrid] Provide alternate way to refresh when working with remote data Mar 3, 2025
@vnbaaij vnbaaij merged commit 8591e50 into microsoft:dev Mar 3, 2025
4 checks passed
@vnbaaij
Copy link
Collaborator

vnbaaij commented Mar 3, 2025

Thanks for a great contribution!

Just a heads-up, your SortName addition will get changed through the word done in #3460.

vnbaaij added a commit that referenced this pull request Mar 3, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants