Skip to content

Commit

Permalink
fix(cdk/tree): fix template context not updating with trackBy
Browse files Browse the repository at this point in the history
  • Loading branch information
BobobUnicorn committed Jul 3, 2024
1 parent dcf1c6c commit 830e8c4
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 1 deletion.
19 changes: 19 additions & 0 deletions src/cdk/tree/tree.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -564,6 +564,15 @@ describe('CdkTree', () => {
component.dataSource.addData();
}

function mutateProperties() {
const copiedData = component.dataSource.data.slice();
copiedData[0] = new TestData('topping_something_new');
copiedData[1] = new TestData('topping_something_new_1');
component.dataSource.data = copiedData;
fixture.changeDetectorRef.markForCheck();
fixture.detectChanges();
}

it('should add/remove/move nodes with reference-based trackBy', () => {
createTrackByTestComponent('reference');
mutateData();
Expand Down Expand Up @@ -613,6 +622,16 @@ describe('CdkTree', () => {
expect(changedNodes[1].getAttribute('initialIndex')).toBe('1');
expect(changedNodes[2].getAttribute('initialIndex')).toBe(null);
});

it('should update templated data if object changes', () => {
createTrackByTestComponent('index');
mutateProperties();

const changedNodes = getNodes(treeElement);
expect(changedNodes.length).toBe(3);
expect(changedNodes[0].textContent).toContain('topping_something_new');
expect(changedNodes[1].textContent).toContain('topping_something_new_1');
});
});

it('should pick up indirect descendant node definitions', () => {
Expand Down
11 changes: 11 additions & 0 deletions src/cdk/tree/tree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import {
Directive,
ElementRef,
EventEmitter,
EmbeddedViewRef,
Input,
IterableChangeRecord,
IterableDiffer,
Expand Down Expand Up @@ -538,6 +539,16 @@ export class CdkTree<T, K = T>
},
);

// If the data itself changes, but keeps the same trackBy, we need to update the templates'
// context to reflect the new object.
changes?.forEachIdentityChange((record: IterableChangeRecord<T>) => {
const newData = record.item;
if (record.currentIndex != undefined) {
const view = viewContainer.get(record.currentIndex);
(view as EmbeddedViewRef<any>).context.$implicit = newData;
}
});

// TODO: change to `this._changeDetectorRef.markForCheck()`, or just switch this component to
// use signals.
this._changeDetectorRef.detectChanges();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
(expandedChange)="onExpand(node, $event)">
<!-- Spinner when node is loading children; this replaces the expand button. -->
@if (node.areChildrenLoading()) {
<mat-spinner mode="indeterminate"></mat-spinner>
<mat-spinner diameter="48" mode="indeterminate"></mat-spinner>
}

@if (!node.areChildrenLoading() && node.isExpandable()) {
Expand Down

0 comments on commit 830e8c4

Please sign in to comment.