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

Virtualize component Placeholder has no effect #57929

Closed
1 task done
AndrewBorst opened this issue Sep 17, 2024 · 2 comments
Closed
1 task done

Virtualize component Placeholder has no effect #57929

AndrewBorst opened this issue Sep 17, 2024 · 2 comments
Assignees
Labels
area-blazor Includes: Blazor, Razor Components feature-blazor-quickgrid Needs: Attention 👋 This issue needs the attention of a contributor, typically because the OP has provided an update.

Comments

@AndrewBorst
Copy link

Is there an existing issue for this?

  • I have searched the existing issues

Describe the bug

Adding the Placeholder tag to the Virtualize component has no effect. I could not make a working example or find any code online that worked. I tried testing locally on two different machines and neither worked. I also tried the EmptyContent and that didn't work either. In older issue, somebody pointed out this only works with ItemsProvider which I am trying to use.

Expected Behavior

How it should work:

  1. When scrolling through virtualized content, instead of showing empty space for unloaded items, the Placeholder template is rendered.
  2. As actual items are loaded, they replace the placeholders.

Steps To Reproduce

So a minimal example is on the FetchData page of Repo. On the main branch, I have a working alternative for showing a message while waiting for the items to load.

Exceptions (if any)

No response

.NET Version

8.0.108

Anything else?

No response

@MackinnonBuck
Copy link
Member

Hi, @AndrewBorst.

Until the items provider returns its first ItemsProviderResult, the <Virtualize> component doesn't know how many items to render, and therefore doesn't know how many placeholders to render.

In your repro app, the first ItemsProviderResult is returned after two seconds, and it indicates that there are 10 total items, but it simultaneously returns however many items were requested in ItemsProviderRequest.Count. As long as the requested count is larger than 10, you will never see any placeholders.

If you change the totalItemCount from 10 to say, 1000, you'll notice that placeholders appear when you scroll.

When loading data asynchronously, it's not super common to know the total item count before the initial items are fetched, which is why the API is designed this way. If you want some kind of loading experience for the initial set of items, you could render a separate loading indicator until the first set of items are fetched. This is what we would recommend.


However, if you really want to render some hard-coded number of initial placeholders, despite this being possibly different from the actual item count, you could make the first ItemsProviderResult return an empty list of items and specify a totalItemCount matching the desired number of placeholders. Then, you can manually request more items via Virtualize.RefreshDataAsync. I've included an example of this below (but I've hidden it by default because I don't want to highlight it as the "answer" - I'd anticipate it's not common to need to do this).

Example
<Virtualize ItemsProvider="LoadForecastsAsync" @ref="_virtualize">
  @* ... *@
</Virtualize>

@code {
    private const int InitialPlaceholderCount = 10;

    private Virtualize<WeatherForecast> _virtualize = null!;
    private bool _hasProvidedInitialPlaceholders;

    private async ValueTask<ItemsProviderResult<WeatherForecast>> LoadForecastsAsync(ItemsProviderRequest request)
    {
        if (!_hasProvidedInitialPlaceholders)
        {
            _hasProvidedInitialPlaceholders = true;
            _ = LoadActualItemsAsync();
            return new(items: [], totalItemCount: InitialPlaceholderCount);

            async Task LoadActualItemsAsync()
            {
                await Task.Yield(); // Defer the call to 'RefreshDataAsync()` to avoid cancelling the current request
                await _virtualize.RefreshDataAsync(); // Refresh the data, which will call 'LoadForecastsAsync()' again
                StateHasChanged(); // Re-render the component
            }
        }

        // ... load the actual items ...

        return new(actualItems, actualItemCount);
    }
}

Could you please let us know if this addresses your concerns? We'll close out this issue if there's not a framework problem here. Thanks!

@MackinnonBuck MackinnonBuck added Needs: Author Feedback The author of this issue needs to respond in order for us to continue investigating this issue. and removed investigate labels Sep 18, 2024
@AndrewBorst
Copy link
Author

@MackinnonBuck Thank you for the explanation and sample code, it makes sense now that the Placeholder is at the item-level and not the component-level. Please close out the issue.

@dotnet-policy-service dotnet-policy-service bot added Needs: Attention 👋 This issue needs the attention of a contributor, typically because the OP has provided an update. and removed Needs: Author Feedback The author of this issue needs to respond in order for us to continue investigating this issue. labels Sep 19, 2024
@MackinnonBuck MackinnonBuck closed this as not planned Won't fix, can't repro, duplicate, stale Sep 19, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-blazor Includes: Blazor, Razor Components feature-blazor-quickgrid Needs: Attention 👋 This issue needs the attention of a contributor, typically because the OP has provided an update.
Projects
None yet
Development

No branches or pull requests

3 participants