fix(grids): keep custom row selector checkbox in sync - master#17429
Open
Zneeky wants to merge 2 commits into
Open
fix(grids): keep custom row selector checkbox in sync - master#17429Zneeky wants to merge 2 commits into
Zneeky wants to merge 2 commits into
Conversation
A custom igxRowSelector template that uses a native <input type="checkbox"> kept a stale checked state when the grid recycled the row's DOM for a different record. The row now owns the selector view and re-creates it whenever it is reused for a new record, so the checkbox is always rendered against fresh DOM. Applies to igx-grid, igx-tree-grid and igx-hierarchical-grid. Also adds a dev-demo repro page (grid-row-selector-cd) for review; it is marked for testing purposes only and can be removed afterwards. Closes #17292
Contributor
There was a problem hiding this comment.
Pull request overview
Fixes a row-virtualization rendering issue where custom igxRowSelector templates containing interactive native elements (e.g. <input type="checkbox">) can display a stale checked state after rows are recycled for different records. The change moves ownership of custom row-selector rendering into the row directive, allowing it to recreate the embedded view when the row’s record key or template changes, while only refreshing context when the same record remains.
Changes:
- Render custom row selector templates via a row-owned
ViewContainerRef, recreating the embedded view on record key/template changes to avoid stale DOM state. - Update grid/hierarchical/tree row templates to use an outlet container for custom selectors while keeping the default selector path unchanged.
- Add a unit test and a demo-app manual repro page/route for #17292.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
projects/igniteui-angular/grids/core/src/row.directive.ts |
Adds custom row selector view creation/caching logic keyed by record + template. |
projects/igniteui-angular/grids/grid/src/grid-row.component.html |
Switches custom selector rendering to an outlet container (#rowSelectorOutlet). |
projects/igniteui-angular/grids/tree-grid/src/tree-grid-row.component.html |
Same outlet-based custom selector rendering for tree grid rows. |
projects/igniteui-angular/grids/hierarchical-grid/src/hierarchical-row.component.html |
Same outlet-based custom selector rendering for hierarchical grid rows. |
projects/igniteui-angular/grids/hierarchical-grid/src/hierarchical-row.component.ts |
Overrides row selector context to re-add select/deselect for hierarchical rows. |
projects/igniteui-angular/grids/grid/src/grid-row-selection.spec.ts |
Adds a regression test intended to validate checkbox state sync for custom selectors. |
src/app/grid-row-selector-cd/grid-row-selector-cd.sample.ts |
Adds a demo-app manual repro page for #17292 across grid types. |
src/app/app.routes.ts |
Wires the new manual repro page into the demo app routing. |
src/app/app.component.ts |
Adds a navigation entry for the new manual repro page. |
Comment on lines
+538
to
+548
| if (!this._rowSelectorViewRef || this._rowSelectorViewRef.destroyed | ||
| || template !== this._rowSelectorViewTemplate || this.key !== this._rowSelectorViewKey) { | ||
| outlet.clear(); | ||
| this._rowSelectorViewTemplate = template; | ||
| this._rowSelectorViewKey = this.key; | ||
| this._rowSelectorViewRef = outlet.createEmbeddedView(template, this.rowSelectorContext); | ||
| } else { | ||
| // Same record - refresh the context snapshot so selection changes are reflected. | ||
| this._rowSelectorViewRef.context.$implicit = this.rowSelectorContext.$implicit; | ||
| } | ||
| this._rowSelectorViewRef.detectChanges(); |
|
|
||
| public onSelectionChanging(event: IRowSelectionEventArgs): void { | ||
| // Keep our signal in sync with the grid selection -> re-computes & re-sorts the data. | ||
| this.selectedIds.set(event.newSelection.map((r: Person) => r.ID)); |
Comment on lines
+2389
to
+2394
| it('Should reflect the selection state in a custom row selector checkbox (#17292)', () => { | ||
| const getCheckbox = () => GridSelectionFunctions.getRowCheckboxInput(grid.gridAPI.get_row_by_index(0).nativeElement); | ||
|
|
||
| grid.selectRows(['ALFKI']); | ||
| fix.detectChanges(); | ||
| expect(getCheckbox().checked).toBe(true); |
Comment on lines
+534
to
+537
| { | ||
| path: 'gridRowSelectorCd', | ||
| component: GridRowSelectorCdSampleComponent | ||
| }, |
Comment on lines
+437
to
+441
| { | ||
| link: '/gridRowSelectorCd', | ||
| icon: 'view_column', | ||
| name: 'Grid Row Selector CD (#17292)' | ||
| }, |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
The row now owns the custom selector view and rebuilds it whenever the row
starts showing a different record (its key changes) or the template changes. A
fresh view means a fresh checkbox, so the first binding write always lands on
clean DOM and cannot be stale. When the same record stays in place, the view is
kept and only its context is refreshed, so programmatic selection changes such
as select all or cascade still show correctly.
Key points:
renders exactly as before, so grids without a custom template see no change
in behavior or performance.
it stays cheap.
covers IgxGrid, IgxTreeGrid and IgxHierarchicalGrid.
Motivation / Context
Closes #17292
Summary
When a grid uses a custom igxRowSelector template containing a native checkbox,
the checkbox could show the wrong checked state after selecting, sorting or
scrolling. The selection data was always correct; only the rendered checkbox
was stale. Fixed for IgxGrid, IgxTreeGrid and IgxHierarchicalGrid.
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)