Skip to content

fix(cdk/tree): cdk tree with levelAccessor should only render expended nodes instead of all nodes #31039

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

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 42 additions & 2 deletions src/cdk/tree/tree-with-tree-control.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,12 @@ describe('CdkTree with TreeControl', () => {
dataSource.addChild(data[0], true);
fixture.detectChanges();

const ariaLevels = getNodes(treeElement).map(n => n.getAttribute('aria-level'));
let ariaLevels = getNodes(treeElement).map(n => n.getAttribute('aria-level'));
expect(ariaLevels).toEqual(['2', '2', '2']);

component.treeControl.expandAll();
fixture.detectChanges();
ariaLevels = getNodes(treeElement).map(n => n.getAttribute('aria-level'));
expect(ariaLevels).toEqual(['2', '3', '2', '2']);
});

Expand All @@ -143,7 +148,7 @@ describe('CdkTree with TreeControl', () => {
dataSource.addChild(data[2]);
fixture.detectChanges();
let ariaExpandedStates = getNodes(treeElement).map(n => n.getAttribute('aria-expanded'));
expect(ariaExpandedStates).toEqual([null, null, 'false', null]);
expect(ariaExpandedStates).toEqual([null, null, 'false']);

component.treeControl.expandAll();
fixture.detectChanges();
Expand Down Expand Up @@ -387,6 +392,17 @@ describe('CdkTree with TreeControl', () => {
treeElement = fixture.nativeElement.querySelector('cdk-tree');
data = dataSource.data;
expect(data.length).toBe(4);
expectFlatTreeToMatch(
treeElement,
28,
'px',
[`[topping_1] - [cheese_1] + [base_1]`],
[`[topping_2] - [cheese_2] + [base_2]`],
[`[topping_3] - [cheese_3] + [base_3]`],
);
component.treeControl.expandAll();
fixture.detectChanges();
treeElement = fixture.nativeElement.querySelector('cdk-tree');
expectFlatTreeToMatch(
treeElement,
28,
Expand Down Expand Up @@ -434,6 +450,18 @@ describe('CdkTree with TreeControl', () => {
treeElement = fixture.nativeElement.querySelector('cdk-tree');
data = dataSource.data;
expect(data.length).toBe(4);
expectFlatTreeToMatch(
treeElement,
28,
'px',
[`[topping_1] - [cheese_1] + [base_1]`],
[`[topping_2] - [cheese_2] + [base_2]`],
[`[topping_3] - [cheese_3] + [base_3]`],
);

(getNodes(treeElement)[1] as HTMLElement).click();
fixture.detectChanges();
treeElement = fixture.nativeElement.querySelector('cdk-tree');
expectFlatTreeToMatch(
treeElement,
28,
Expand Down Expand Up @@ -481,6 +509,18 @@ describe('CdkTree with TreeControl', () => {
treeElement = fixture.nativeElement.querySelector('cdk-tree');
data = dataSource.data;
expect(data.length).toBe(4);
expectFlatTreeToMatch(
treeElement,
28,
'px',
[`[topping_1] - [cheese_1] + [base_1]`],
[`[topping_2] - [cheese_2] + [base_2]`],
[`[topping_3] - [cheese_3] + [base_3]`],
);

(getNodes(treeElement)[1] as HTMLElement).click();
fixture.detectChanges();
treeElement = fixture.nativeElement.querySelector('cdk-tree');
expectFlatTreeToMatch(
treeElement,
28,
Expand Down
47 changes: 44 additions & 3 deletions src/cdk/tree/tree.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,12 @@ describe('CdkTree', () => {
dataSource.addChild(data[0], true);
fixture.detectChanges();

const ariaLevels = getNodes(treeElement).map(n => n.getAttribute('aria-level'));
let ariaLevels = getNodes(treeElement).map(n => n.getAttribute('aria-level'));
expect(ariaLevels).toEqual(['2', '2', '2']);

tree.expandAll();
fixture.detectChanges();
ariaLevels = getNodes(treeElement).map(n => n.getAttribute('aria-level'));
expect(ariaLevels).toEqual(['2', '3', '2', '2']);
});

Expand All @@ -149,7 +154,7 @@ describe('CdkTree', () => {
dataSource.addChild(data[2]);
fixture.detectChanges();
let ariaExpandedStates = getNodes(treeElement).map(n => n.getAttribute('aria-expanded'));
expect(ariaExpandedStates).toEqual([null, null, 'false', null]);
expect(ariaExpandedStates).toEqual([null, null, 'false']);

component.tree.expandAll();
fixture.detectChanges();
Expand Down Expand Up @@ -334,7 +339,7 @@ describe('CdkTree', () => {

expect(getNodes(treeElement).map(x => x.getAttribute('tabindex')))
.withContext(`Expecting parent node to be focused since it was collapsed.`)
.toEqual(['0', '-1']);
.toEqual(['0']);
});

it('should expand/collapse the node recursively', () => {
Expand Down Expand Up @@ -439,6 +444,18 @@ describe('CdkTree', () => {
treeElement = fixture.nativeElement.querySelector('cdk-tree');
data = dataSource.data;
expect(data.length).toBe(4);
expectFlatTreeToMatch(
treeElement,
28,
'px',
[`[topping_1] - [cheese_1] + [base_1]`],
[`[topping_2] - [cheese_2] + [base_2]`],
[`[topping_3] - [cheese_3] + [base_3]`],
);

tree.expandAll();
fixture.detectChanges();
treeElement = fixture.nativeElement.querySelector('cdk-tree');
expectFlatTreeToMatch(
treeElement,
28,
Expand Down Expand Up @@ -485,6 +502,18 @@ describe('CdkTree', () => {
treeElement = fixture.nativeElement.querySelector('cdk-tree');
data = dataSource.data;
expect(data.length).toBe(4);
expectFlatTreeToMatch(
treeElement,
28,
'px',
[`[topping_1] - [cheese_1] + [base_1]`],
[`[topping_2] - [cheese_2] + [base_2]`],
[`[topping_3] - [cheese_3] + [base_3]`],
);

tree.expandAll();
fixture.detectChanges();
treeElement = fixture.nativeElement.querySelector('cdk-tree');
expectFlatTreeToMatch(
treeElement,
28,
Expand Down Expand Up @@ -532,6 +561,18 @@ describe('CdkTree', () => {
treeElement = fixture.nativeElement.querySelector('cdk-tree');
data = dataSource.data;
expect(data.length).toBe(4);
expectFlatTreeToMatch(
treeElement,
28,
'px',
[`[topping_1] - [cheese_1] + [base_1]`],
[`[topping_2] - [cheese_2] + [base_2]`],
[`[topping_3] - [cheese_3] + [base_3]`],
);

tree.expandAll();
fixture.detectChanges();
treeElement = fixture.nativeElement.querySelector('cdk-tree');
expectFlatTreeToMatch(
treeElement,
28,
Expand Down
16 changes: 12 additions & 4 deletions src/cdk/tree/tree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1049,6 +1049,12 @@ export class CdkTree<T, K = T>
);
}

private _shouldFlattenNodeRender(node: T): boolean {
const key = this._getExpansionKey(node);
const parent = this._parents.get(key);
return !parent || (this.isExpanded(parent) && this._shouldFlattenNodeRender(parent));
}

/**
* Converts children for certain tree configurations.
*
Expand Down Expand Up @@ -1095,10 +1101,12 @@ export class CdkTree<T, K = T>
// with the TreeControl, and so no conversions are necessary. Otherwise,
// we've already confirmed that the data model matches up with the
// desired node type here.
return observableOf({renderNodes: nodes, flattenedNodes: nodes}).pipe(
tap(({flattenedNodes}) => {
this._calculateParents(flattenedNodes);
}),
return observableOf(nodes).pipe(
tap(nodes => this._calculateParents(nodes)),
map(nodes => ({
renderNodes: nodes.filter(node => this._shouldFlattenNodeRender(node)),
flattenedNodes: nodes,
})),
);
} else {
// clear previously generated data so we don't keep end up retaining data overtime causing
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
<cdk-tree [dataSource]="dataSource" [treeControl]="treeControl">
<!-- This is the tree node template for leaf nodes -->
<cdk-tree-node *cdkTreeNodeDef="let node" cdkTreeNodePadding
[style.display]="shouldRender(node) ? 'flex' : 'none'"
[isDisabled]="!shouldRender(node)"
class="example-tree-node">
<!-- use a disabled button to provide padding for tree leaf -->
<button matIconButton disabled></button>
Expand All @@ -12,8 +10,6 @@
<cdk-tree-node *cdkTreeNodeDef="let node; when: hasChild" cdkTreeNodePadding
cdkTreeNodeToggle
[cdkTreeNodeTypeaheadLabel]="node.name"
[style.display]="shouldRender(node) ? 'flex' : 'none'"
[isDisabled]="!shouldRender(node)"
(expandedChange)="node.isExpanded = $event"
class="example-tree-node"
tabindex="0">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -336,17 +336,6 @@ export class CdkTreeCustomKeyManagerExample {

return null;
}

shouldRender(node: ExampleFlatNode) {
let parent = this.getParentNode(node);
while (parent) {
if (!parent.isExpanded) {
return false;
}
parent = this.getParentNode(parent);
}
return true;
}
}

const EXAMPLE_DATA: ExampleFlatNode[] = [
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
<cdk-tree #tree [dataSource]="dataSource" [childrenAccessor]="childrenAccessor">
<!-- This is the tree node template for leaf nodes -->
<cdk-tree-node *cdkTreeNodeDef="let node" cdkTreeNodePadding
[style.display]="shouldRender(node) ? 'flex' : 'none'"
[isDisabled]="!shouldRender(node)"
class="example-tree-node">
<!-- use a disabled button to provide padding for tree leaf -->
<button matIconButton disabled></button>
Expand All @@ -12,8 +10,6 @@
<cdk-tree-node *cdkTreeNodeDef="let node; when: hasChild" cdkTreeNodePadding
cdkTreeNodeToggle
[cdkTreeNodeTypeaheadLabel]="node.name"
[style.display]="shouldRender(node) ? 'flex' : 'none'"
[isDisabled]="!shouldRender(node)"
[isExpandable]="true"
class="example-tree-node">
<button matIconButton cdkTreeNodeToggle [attr.aria-label]="'Toggle ' + node.name">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,17 +55,6 @@ export class CdkTreeFlatChildrenAccessorExample {

return null;
}

shouldRender(node: NestedFoodNode) {
let parent = this.getParentNode(node);
while (parent) {
if (!this.tree.isExpanded(parent)) {
return false;
}
parent = this.getParentNode(parent);
}
return true;
}
}

const EXAMPLE_DATA: NestedFoodNode[] = [
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
<cdk-tree #tree [dataSource]="dataSource" [levelAccessor]="levelAccessor">
<!-- This is the tree node template for leaf nodes -->
<cdk-tree-node *cdkTreeNodeDef="let node" cdkTreeNodePadding
[style.display]="shouldRender(node) ? 'flex' : 'none'"
[isDisabled]="!shouldRender(node)"
class="example-tree-node">
<!-- use a disabled button to provide padding for tree leaf -->
<button matIconButton disabled></button>
Expand All @@ -12,8 +10,6 @@
<cdk-tree-node *cdkTreeNodeDef="let node; when: hasChild" cdkTreeNodePadding
cdkTreeNodeToggle
[cdkTreeNodeTypeaheadLabel]="node.name"
[style.display]="shouldRender(node) ? 'flex' : 'none'"
[isDisabled]="!shouldRender(node)"
[isExpandable]="node.expandable"
class="example-tree-node">
<button matIconButton cdkTreeNodeToggle
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,6 @@ export class CdkTreeFlatLevelAccessorExample {

return null;
}

shouldRender(node: FlatFoodNode): boolean {
// This node should render if it is a root node or if all of its ancestors are expanded.
const parent = this.getParentNode(node);
return !parent || (!!this.tree?.isExpanded(parent) && this.shouldRender(parent));
}
}

const EXAMPLE_DATA: FlatFoodNode[] = [
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
<cdk-tree [dataSource]="dataSource" [treeControl]="treeControl">
<!-- This is the tree node template for leaf nodes -->
<cdk-tree-node *cdkTreeNodeDef="let node" cdkTreeNodePadding
[style.display]="shouldRender(node) ? 'flex' : 'none'"
[isDisabled]="!shouldRender(node)"
class="example-tree-node">
<!-- use a disabled button to provide padding for tree leaf -->
<button matIconButton disabled></button>
Expand All @@ -11,8 +9,6 @@
<!-- This is the tree node template for expandable nodes -->
<cdk-tree-node *cdkTreeNodeDef="let node; when: hasChild" cdkTreeNodePadding
cdkTreeNodeToggle [cdkTreeNodeTypeaheadLabel]="node.name"
[style.display]="shouldRender(node) ? 'flex' : 'none'"
[isDisabled]="!shouldRender(node)"
(expandedChange)="node.isExpanded = $event"
class="example-tree-node">
<button matIconButton cdkTreeNodeToggle
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,17 +43,6 @@ export class CdkTreeFlatExample {

return null;
}

shouldRender(node: ExampleFlatNode) {
let parent = this.getParentNode(node);
while (parent) {
if (!parent.isExpanded) {
return false;
}
parent = this.getParentNode(parent);
}
return true;
}
}

const EXAMPLE_DATA: ExampleFlatNode[] = [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,6 @@ export class CdkTreeNestedChildrenAccessorExample {

return null;
}

shouldRender(node: NestedFoodNode): boolean {
// This node should render if it is a root node or if all of its ancestors are expanded.
const parent = this.getParentNode(node);
return !parent || (!!this.tree?.isExpanded(parent) && this.shouldRender(parent));
}
}

const EXAMPLE_DATA: NestedFoodNode[] = [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,6 @@ export class CdkTreeNestedLevelAccessorExample {

return null;
}

shouldRender(node: FlatFoodNode): boolean {
// This node should render if it is a root node or if all of its ancestors are expanded.
const parent = this.getParentNode(node);
return !parent || (!!this.tree?.isExpanded(parent) && this.shouldRender(parent));
}
}

const EXAMPLE_DATA: FlatFoodNode[] = [
Expand Down
Loading