Skip to content

feat(Table): support virtualize on dynamic datatable mode#7938

Merged
ArgoZhang merged 3 commits into
mainfrom
feat-table-dv
Apr 30, 2026
Merged

feat(Table): support virtualize on dynamic datatable mode#7938
ArgoZhang merged 3 commits into
mainfrom
feat-table-dv

Conversation

@ArgoZhang

@ArgoZhang ArgoZhang commented Apr 30, 2026

Copy link
Copy Markdown
Member

Link issues

fixes #7937

Summary By Copilot

Regression?

  • Yes
  • No

Risk

  • High
  • Medium
  • Low

Verification

  • Manual (required)
  • Automated

Packaging changes reviewed?

  • Yes
  • No
  • N/A

☑️ Self Check before Merge

⚠️ Please check all items below before review. ⚠️

  • Doc is updated/provided or not needed
  • Demo is updated/provided or not needed
  • Merge the latest code from the main branch

Summary by Sourcery

Adjust table virtualization behavior to correctly support virtual scrolling in dynamic (OnQueryAsync) data mode and update tests accordingly.

New Features:

  • Enable virtualized scrolling when the table is in dynamic data mode driven by OnQueryAsync.

Bug Fixes:

  • Ensure placeholders are only used during virtualization when OnQueryAsync is configured, preventing incorrect placeholder behavior with static data.

Tests:

  • Update the table placeholder unit test to cover virtualization behavior when OnQueryAsync is set.

Copilot AI review requested due to automatic review settings April 30, 2026 05:37
@bb-auto bb-auto Bot added the enhancement New feature or request label Apr 30, 2026
@bb-auto bb-auto Bot added this to the v10.6.0 milestone Apr 30, 2026
@sourcery-ai

sourcery-ai Bot commented Apr 30, 2026

Copy link
Copy Markdown
Contributor
Reviewer's guide (collapsed on small PRs)

Reviewer's Guide

Enables 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 OnQueryAsync

sequenceDiagram
    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
Loading

Sequence diagram for virtualized static datatable mode using precomputed Rows

sequenceDiagram
    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
Loading

Updated class diagram for Table virtualization modes

classDiagram
    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
Loading

File-Level Changes

Change Details Files
Change virtualization behavior to use ItemsProvider when OnQueryAsync is set and use precomputed Rows otherwise.
  • In virtual scroll mode, switch the condition to check OnQueryAsync instead of Items to determine which Virtualize configuration to use.
  • When OnQueryAsync is not null, configure the Virtualize component with a reference, ItemsProvider bound to LoadItems, ItemContent bound to RenderRow, and Placeholder bound to RenderPlaceholderRow.
  • When OnQueryAsync is null, configure the Virtualize component to use the Rows collection with ChildContent bound to RenderRow, removing ItemsProvider and Placeholder from this path.
src/BootstrapBlazor/Components/Table/Table.razor
Update the placeholder-related unit test to run in the dynamic OnQueryAsync scenario.
  • Retrieve an IStringLocalizer from the test DI context for use in query callbacks.
  • Bind the table's OnQueryAsync parameter to OnQueryAsync(localizer) so that virtualization uses the ItemsProvider path where placeholders are active.
  • Clarify via comment that the placeholder is only effective when OnQueryAsync is non-null.
test/UnitTest/Components/TableTest.cs

Assessment against linked issues

Issue Objective Addressed Explanation
#7937 Enable the Table component to support Blazor Virtualize when using dynamic data table mode (i.e., data loaded via OnQueryAsync / ItemsProvider).

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@ArgoZhang ArgoZhang merged commit f5c3066 into main Apr 30, 2026
6 checks passed
@ArgoZhang ArgoZhang deleted the feat-table-dv branch April 30, 2026 05:38

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hey - I've left some high level feedback:

  • 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.
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.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@codecov

codecov Bot commented Apr 30, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (51adc34) to head (e0afe12).
⚠️ Report is 1 commits behind head on main.

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           
Flag Coverage Δ
BB 100.00% <100.00%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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.razor virtual 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.

Comment on lines 398 to 412
@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>
}

Copilot AI Apr 30, 2026

Copy link

Choose a reason for hiding this comment

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

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.

Copilot uses AI. Check for mistakes.
Comment on lines 8425 to +8443
@@ -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));

Copilot AI Apr 30, 2026

Copy link

Choose a reason for hiding this comment

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

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.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(Table): support virtualize on dynamic datatable mode

2 participants