feat: Added virtual scroll component and sample implementation - #17281
Conversation
…he view when the data source changes.
Fixed several issues with virtual coordinates mapping and the scroll engine in general. The Binary Indexed Tree (BIT) is used to efficiently calculate the cumulative heights of items in the virtual scroll, which allows for faster updates and smoother scrolling experience.
…-scroll-component
…-scroll-component
…-scroll-component
…-scroll-component
…-scroll-component
…-scroll-component
…-scroll-component
…-scroll-component
…-scroll-component
There was a problem hiding this comment.
Pull request overview
This PR introduces a new IgxVirtualScrollComponent entry point to Ignite UI for Angular, providing a self-contained virtualized viewport for vertical and horizontal scrolling (including variable-size items and remote/infinite loading), and adds a demo route + sample showcasing usage.
Changes:
- Added a new
igniteui-angular/virtual-scrollentry point with a virtual scroll component, item-template directive, supporting types, and a scroll-math engine. - Added unit tests covering the engine behavior, template context, orientations (including RTL), outputs, and basic rendering.
- Added a demo/sample implementation and wired it into the demo app routing + navigation list.
Reviewed changes
Copilot reviewed 17 out of 17 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| src/app/virtual-scroll/virtual-scroll.sample.ts | Demo component showcasing vertical/horizontal + remote data scenarios. |
| src/app/virtual-scroll/virtual-scroll.sample.html | Sample template demonstrating igxVirtualItem usage for multiple scenarios. |
| src/app/virtual-scroll/virtual-scroll.sample.scss | Styling for the new demo page. |
| src/app/app.routes.ts | Adds a /virtual-scroll route for the demo. |
| src/app/app.component.ts | Adds “Virtual Scroll” to the demo navigation list. |
| projects/igniteui-angular/virtual-scroll/src/virtual-scroll/virtual-scroll.component.ts | Core virtual scroll component implementation (signals-first + view pooling). |
| projects/igniteui-angular/virtual-scroll/src/virtual-scroll/virtual-scroll.component.html | Component template for track/content positioning. |
| projects/igniteui-angular/virtual-scroll/src/virtual-scroll/virtual-scroll.component.scss | Component styles for vertical/horizontal layouts. |
| projects/igniteui-angular/virtual-scroll/src/virtual-scroll/virtual-scroll-item.directive.ts | Directive to capture ng-template[igxVirtualItem] as the item template. |
| projects/igniteui-angular/virtual-scroll/src/virtual-scroll/types.ts | Typed template context + output payload types. |
| projects/igniteui-angular/virtual-scroll/src/virtual-scroll/scroll-engine.ts | Scroll math engine (BIT-based sizing, visible range computation, coordinate compression). |
| projects/igniteui-angular/virtual-scroll/src/virtual-scroll/virtual-scroll.component.spec.ts | Unit tests for engine + component behaviors (including RTL). |
| projects/igniteui-angular/virtual-scroll/src/public_api.ts | Public exports for the new entry point. |
| projects/igniteui-angular/virtual-scroll/index.ts | Entry-point barrel export. |
| projects/igniteui-angular/virtual-scroll/ng-package.json | ng-packagr entry point config placeholder (consistent with other entry points). |
| projects/igniteui-angular/virtual-scroll/README.md | Feature documentation and usage examples for the new component. |
| projects/igniteui-angular/src/public_api.ts | Exposes igniteui-angular/virtual-scroll from the root package exports. |
Comments suppressed due to low confidence (1)
src/app/virtual-scroll/virtual-scroll.sample.html:107
- Section numbering in the sample comments labels this as section 6 even though it is the 5th sample block. Renumber to keep the sample easier to follow.
<!-- 6. Remote / infinite scrolling -->
<!-- ------------------------------------------------------------------ -->
….com/IgniteUI/igniteui-angular into rkaraivanov/virtual-scroll-component
…-scroll-component
|
@simeonoff |
… change Two regressions in IgxVirtualScrollComponent, captured as tests that fail on the current implementation: - scrollToIndex with block/inline 'nearest' start-aligns an item that is out of view. Native scrollIntoView semantics end-align an item below or past the viewport, which is what drop-down, combo and the Excel-style filter rely on for ArrowDown navigation. - _contentTransform reads the host direction through _isLTR() inside a computed(), so a runtime dir change on a horizontal list does not flip the translateX sign while the rendered range stays the same. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
Some findings during agentic testing:
Both have tests added that will fail in the latest commit. We need to fix these before merge. |
Three more regressions captured as tests that fail on the current code: - Under coordinate compression the visible range at the maximum DOM scroll offset stops short of the last items, so the tail of a very long list can never be reached. - Replacing `data` with rows of unchanged size discards their measurements but never re-measures the recycled wrappers, leaving the engine on the estimate. - navigateFirst on a remote page that starts past index 0 lands on the group header once the first page arrives. The spec now asserts the loaded page starts past 0, so it cannot pass through the local path. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
Added 3 more tests that fail due to actual issues:
|
…-scroll-component
Compressed lists could not reach their last rows: the engine scaled sizes, so the largest DOM offset landed one viewport of compressed pixels short. It now maps the scroll ranges, which is why offset conversions take the viewport size. `nearest` start-aligned every out-of-view item. It now brings the item to its nearer edge, as native scrollIntoView does. The content transform read the direction outside the signal graph, so a runtime `dir` change left the wrapper mirrored the wrong way until the window moved. Rows replaced at the same size kept the estimate after a resize dropped their measurements: an unchanged wrapper never reports on its own, so those wrappers are observed again. The drop-down skipped headers when the scroll settled, before a remote first page had rendered the focused row, and marked itself for check on every window change even when the active descendant had not moved. The Excel style search read a private ChangeDetectorRef flag through `any`; it uses the typed ViewRef like its siblings.
The navigation waits for the grid's chunkLoad with first(), yet a chunk load also fires when a chunk size changes, as the freshly created child grid's container does while it settles. When that load came before the navigation's own scroll, the callback expanded the target row while the child row was still outside the rendered chunk. The nested grid never rendered, so the lookup came back empty and the navigation ended early. This timing made the nested child grid spec flaky in CI. The navigation now scrolls the child row into the chunk when its grid is missing, and continues on the first chunk load that has it.
….com/IgniteUI/igniteui-angular into rkaraivanov/virtual-scroll-component
Closes #17607
Closes #17608
Closes #17610
Closes #17611
Closes #17615
Closes #17616
Description
Expose a new virtual scroll component for horizontal/vertical scrolling.
Motivation / Context
igxForOfrequires the developer to manually wire a separate scroll container, aVirtualHelperComponent/HVirtualHelperComponentDOM helper element, and passigxForContainerSizeexplicitly. That's 3–4 pieces of setup vs. one tag.igxForOfusesViewContainerRef.move()but always keeps a fixed chunk alive, paying create/destroy cost when chunk size changes.ChangeDetectionStrategy.OnPushthroughout the implementation.Type of Change (check all that apply):
Component(s) / Area(s) Affected:
How Has This Been Tested?
Test Configuration:
Screenshots / Recordings
Checklist:
feature/README.MDupdates for the feature docsREADME.MDCHANGELOG.MDupdates for newly added functionalityng updatemigrations for the breaking changes (migrations guidelines)