-
Notifications
You must be signed in to change notification settings - Fork 160
fix(igxGrid): Fix merge cell offset when using virtual scrollbar with ratio. #16331
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
Changes from all commits
7bd92df
6e8b845
babc2b6
5dad728
30a7ecc
a361804
65a1b76
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -3719,7 +3719,7 @@ export abstract class IgxGridBaseDirective implements GridType, | |||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| protected getMergeCellOffset(rowData) { | ||||||||||||||||||||||||||||||||||||||
| const index = rowData.dataIndex; | ||||||||||||||||||||||||||||||||||||||
| let offset = this.verticalScrollContainer.scrollPosition - this.verticalScrollContainer.getScrollForIndex(index); | ||||||||||||||||||||||||||||||||||||||
| let offset = this.verticalScrollContainer._virtScrollPosition - this.verticalScrollContainer.getScrollForIndex(index); | ||||||||||||||||||||||||||||||||||||||
| if (this.hasPinnedRecords && this.isRowPinningToTop) { | ||||||||||||||||||||||||||||||||||||||
| offset -= this.pinnedRowHeight; | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
|
@@ -8251,16 +8251,16 @@ export abstract class IgxGridBaseDirective implements GridType, | |||||||||||||||||||||||||||||||||||||
| // recalc merged data | ||||||||||||||||||||||||||||||||||||||
| if (this.columnsToMerge.length > 0) { | ||||||||||||||||||||||||||||||||||||||
| const startIndex = this.verticalScrollContainer.state.startIndex; | ||||||||||||||||||||||||||||||||||||||
| const prevDataView = this.verticalScrollContainer.igxForOf?.slice(0, startIndex); | ||||||||||||||||||||||||||||||||||||||
| const data = []; | ||||||||||||||||||||||||||||||||||||||
| for (let index = 0; index < startIndex; index++) { | ||||||||||||||||||||||||||||||||||||||
| const rec = prevDataView[index]; | ||||||||||||||||||||||||||||||||||||||
| if (rec.cellMergeMeta && | ||||||||||||||||||||||||||||||||||||||
| // index + maxRowSpan is within view | ||||||||||||||||||||||||||||||||||||||
| startIndex < (index + Math.max(...rec.cellMergeMeta.values().toArray().map(x => x.rowSpan)))) { | ||||||||||||||||||||||||||||||||||||||
| const visibleIndex = this.isRowPinningToTop ? index + this.pinnedRecordsCount : index; | ||||||||||||||||||||||||||||||||||||||
| data.push({ record: rec, index: visibleIndex, dataIndex: index }); | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
| const rec = this.verticalScrollContainer.igxForOf[startIndex]; | ||||||||||||||||||||||||||||||||||||||
| if (rec && rec.cellMergeMeta) { | ||||||||||||||||||||||||||||||||||||||
| this.columnsToMerge.forEach((col) => { | ||||||||||||||||||||||||||||||||||||||
| const root = rec.cellMergeMeta?.get(col.field)?.root; | ||||||||||||||||||||||||||||||||||||||
| if (root) { | ||||||||||||||||||||||||||||||||||||||
| data.push({ record: root, index: root.index, dataIndex: root.index }); | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
| data.push({ record: root, index: root.index, dataIndex: root.index }); | |
| data.push({ | |
| record: root, | |
| index: this.getDataViewIndex(root.index, false), | |
| dataIndex: root.index | |
| }); |
Copilot
AI
Apr 6, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updateMergedData() can push the same root multiple times (once per merged column) when different merged columns share the same merge root. The templates use @for (rowData of mergedDataInView; track rowData.record;), so duplicates can lead to non-unique track keys and incorrect rendering/diffing of the merged-top overlay rows. Consider de-duplicating roots (e.g., by root reference or root.index) before assigning to _mergedDataInView.
| const rec = this.verticalScrollContainer.igxForOf[startIndex]; | |
| if (rec && rec.cellMergeMeta) { | |
| this.columnsToMerge.forEach((col) => { | |
| const root = rec.cellMergeMeta?.get(col.field)?.root; | |
| if (root) { | |
| data.push({ record: root, index: root.index, dataIndex: root.index }); | |
| } | |
| }) | |
| const addedRoots = new Set<any>(); | |
| const rec = this.verticalScrollContainer.igxForOf[startIndex]; | |
| if (rec && rec.cellMergeMeta) { | |
| this.columnsToMerge.forEach((col) => { | |
| const root = rec.cellMergeMeta?.get(col.field)?.root; | |
| if (root && !addedRoots.has(root)) { | |
| addedRoots.add(root); | |
| data.push({ record: root, index: root.index, dataIndex: root.index }); | |
| } | |
| }); |
| Original file line number | Diff line number | Diff line change | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -132,7 +132,7 @@ export class IgxGridUnmergeActivePipe implements PipeTransform { | |||||||||||
|
|
||||||||||||
| let result = cloneArray(collection) as any; | ||||||||||||
| uniqueRoots.forEach(x => { | ||||||||||||
| const index = collection.indexOf(x); | ||||||||||||
| const index = x.index; | ||||||||||||
|
||||||||||||
| const index = x.index; | |
| const index = x.index ?? collection.indexOf(x); | |
| if (index < 0 || !x.cellMergeMeta) { | |
| return; | |
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Making
_virtScrollPositionpublic exposes an underscored internal field as part of the generated typings/API surface. To avoid effectively “publishing” an internal implementation detail, consider keeping the field non-public and exposing a@hidden/@internalgetter (e.g.,get virtScrollPosition()), which also allows you to keep invariants (like ensuring it stays in sync whenresetScrollPosition()is called).