feat(Table): support virtualize on dynamic datatable mode#7938
Conversation
Reviewer's guide (collapsed on small PRs)Reviewer's GuideEnables table virtualization when using dynamic data loading via OnQueryAsync, and adjusts the non-dynamic path to use precomputed Rows instead of Items, with tests updated to reflect that placeholders only apply in the dynamic/virtualized scenario. Sequence diagram for virtualized dynamic datatable mode using OnQueryAsyncsequenceDiagram
actor User
participant Table
participant Virtualize
participant LoadItems
participant OnQueryAsync
User->>Table: Scrolls table (ScrollMode Virtual)
activate Table
Table->>Virtualize: Initialize with ItemsProvider LoadItems
deactivate Table
loop As user scrolls
Virtualize->>LoadItems: Request items(startIndex, count)
activate LoadItems
LoadItems->>OnQueryAsync: Invoke with queryOptions
activate OnQueryAsync
OnQueryAsync-->>LoadItems: QueryData(resultItems, totalCount)
deactivate OnQueryAsync
LoadItems-->>Virtualize: Items segment
deactivate LoadItems
Virtualize->>Table: RenderRow(item) for visible items
Virtualize->>Table: RenderPlaceholderRow() for not yet loaded items
end
Sequence diagram for virtualized static datatable mode using precomputed RowssequenceDiagram
actor User
participant Table
participant Virtualize
User->>Table: Scrolls table (ScrollMode Virtual)
activate Table
Table->>Virtualize: Initialize with Items Rows and ChildContent RenderRow
deactivate Table
loop As user scrolls
Virtualize->>Virtualize: Calculate visible row range
Virtualize->>Table: RenderRow(row) for each visible row from Rows
end
Updated class diagram for Table virtualization modesclassDiagram
class Table {
+ScrollMode ScrollMode
+IEnumerable~object~ Items
+IEnumerable~object~ Rows
+Func~QueryOptions, Task~ OnQueryAsync
+Virtualize~object~ _virtualizeElement
+int RowHeight
+int OverscanCount
+RenderFragment~object~ RenderRow
+RenderFragment RenderPlaceholderRow
+ValueTask~ItemsProviderResult~ LoadItems(int startIndex, int count)
}
class Virtualize~TItem~ {
+double ItemSize
+int OverscanCount
+IEnumerable~TItem~ Items
+ItemsProviderDelegate~TItem~ ItemsProvider
+RenderFragment~TItem~ ItemContent
+RenderFragment Placeholder
}
class ItemsProviderResult~TItem~ {
+IReadOnlyList~TItem~ Items
+int TotalItemCount
}
class QueryOptions {
+int StartIndex
+int Count
+object AdditionalData
}
Table o-- Virtualize~object~ : uses
Virtualize~object~ --> ItemsProviderResult~object~ : returns
Table --> ItemsProviderResult~object~ : creates via LoadItems
Table --> QueryOptions : passes to OnQueryAsync
class DynamicVirtualization {
+Uses OnQueryAsync
+Virtualize.ItemsProvider = LoadItems
+Virtualize.ItemContent = RenderRow
+Virtualize.Placeholder = RenderPlaceholderRow
}
class StaticVirtualization {
+Uses Rows
+Virtualize.Items = Rows
+Virtualize.ChildContent = RenderRow
}
Table ..> DynamicVirtualization : when OnQueryAsync != null
Table ..> StaticVirtualization : when OnQueryAsync == null
File-Level Changes
Assessment against linked issues
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey - I've left some high level feedback:
- The virtualized rendering condition has switched from
Items != nulltoOnQueryAsync != null; consider clarifying or guarding the behavior when both are set or when neither is set to avoid unexpected mode selection for existing consumers. - In the non-
OnQueryAsyncbranch you now bindVirtualizetoRowsinstead ofItems.ToList(); ifRowshas different filtering/sorting semantics thanItems, it may be worth confirming this is the intended data source for virtualized rendering in dynamic table mode.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The virtualized rendering condition has switched from `Items != null` to `OnQueryAsync != null`; consider clarifying or guarding the behavior when both are set or when neither is set to avoid unexpected mode selection for existing consumers.
- In the non-`OnQueryAsync` branch you now bind `Virtualize` to `Rows` instead of `Items.ToList()`; if `Rows` has different filtering/sorting semantics than `Items`, it may be worth confirming this is the intended data source for virtualized rendering in dynamic table mode.Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #7938 +/- ##
=========================================
Coverage 100.00% 100.00%
=========================================
Files 766 766
Lines 34272 34272
Branches 4723 4723
=========================================
Hits 34272 34272
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
Adds virtual scrolling support adjustments for Table when used in dynamic DataTable mode (fixes #7937), and updates unit tests accordingly.
Changes:
- Updates
Table.razorvirtual scroll rendering to switch virtualization strategy based on the data source mode. - Adjusts the placeholder-related unit test to run under
OnQueryAsync-driven virtualization. - Bumps package version to
10.6.1-beta03.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| test/UnitTest/Components/TableTest.cs | Updates the placeholder test setup to include OnQueryAsync so virtualization placeholder behavior can be exercised. |
| src/BootstrapBlazor/Components/Table/Table.razor | Changes virtual scroll rendering logic between ItemsProvider and Items modes. |
| src/BootstrapBlazor/BootstrapBlazor.csproj | Version bump to beta03. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| @if (ScrollMode == ScrollMode.Virtual) | ||
| { | ||
| @if (Items != null) | ||
| @if (OnQueryAsync != null) | ||
| { | ||
| <Virtualize ItemSize="RowHeight" OverscanCount="@OverscanCount" Items="@Items.ToList()" | ||
| ChildContent="RenderRow"> | ||
| <Virtualize @ref="_virtualizeElement" | ||
| ItemSize="RowHeight" OverscanCount="@OverscanCount" ItemsProvider="LoadItems" | ||
| ItemContent="RenderRow" Placeholder="RenderPlaceholderRow"> | ||
| </Virtualize> | ||
| } | ||
| else | ||
| { | ||
| <Virtualize @ref="_virtualizeElement" | ||
| ItemSize="RowHeight" OverscanCount="@OverscanCount" Placeholder="RenderPlaceholderRow" | ||
| ItemsProvider="LoadItems" ItemContent="RenderRow"> | ||
| <Virtualize ItemSize="RowHeight" OverscanCount="@OverscanCount" Items="@Rows" | ||
| ChildContent="RenderRow"> | ||
| </Virtualize> | ||
| } |
There was a problem hiding this comment.
The virtual scroll branch switches between ItemsProvider=LoadItems and Items=@Rows based solely on OnQueryAsync != null. This breaks virtual scrolling when the table is backed by DataService/injected IDataService<TItem> (i.e., Items == null and OnQueryAsync == null), because Virtualize won’t call LoadItems and scrolling won’t fetch additional ranges. Consider basing this decision on whether the table is in query-driven mode (Items == null) and only special-casing the DataTable dynamic context scenario (e.g., DynamicContext is DataTableDynamicContext with no external query) to use Items=@Rows; otherwise keep using ItemsProvider=LoadItems so StartIndex/PageItems work for DataService as well.
| @@ -8438,6 +8440,7 @@ public void PlaceHolder_Ok() | |||
| builder.AddAttribute(2, "FieldExpression", Utility.GenerateValueExpression(foo, "Name", typeof(string))); | |||
| builder.CloseComponent(); | |||
| }); | |||
| pb.Add(a => a.OnQueryAsync, OnQueryAsync(localizer)); | |||
There was a problem hiding this comment.
The updated placeholder test only exercises the OnQueryAsync path for virtual scrolling. Since the production code also supports query-driven tables via DataService/injected IDataService<TItem>, it would be good to add coverage for ScrollMode.Virtual + DataService to ensure virtualized loading (and placeholder rendering, if expected) still works when OnQueryAsync is not set.
Link issues
fixes #7937
Summary By Copilot
Regression?
Risk
Verification
Packaging changes reviewed?
☑️ Self Check before Merge
Summary by Sourcery
Adjust table virtualization behavior to correctly support virtual scrolling in dynamic (OnQueryAsync) data mode and update tests accordingly.
New Features:
Bug Fixes:
Tests: