Skip to content

Commit e7a5b31

Browse files
committed
docs(material/tree): fix demos where keyboard navigates to hidden nodes
Fix an issue in the tree demos where the keyboard can navigate to nodes that are not rendered to the screen. This happend because nodes where hidden using CSS and the TreeKeyManager did not know to skip over them. Fix this issue by disabled nodes that are hidden so that the TreeKeyManager will skip them. Steps to reproduce issue 1. Go to CDK Flat tree (levelAccessor) demo 2. Tab onto Fruit 3. Press down the up 4. (Expands the collapses) 5. Press down 6. (Expecting Vegetables to be focused but focus ring is still around Fruit) 7. Press down five times. 8. (Focus ring is around Fruit). With this commit applied, above issue no longer reproduces. This commit message is only for code reviewers and can be deleted when landing this change in main.
1 parent 2098b41 commit e7a5b31

File tree

4 files changed

+30
-2
lines changed

4 files changed

+30
-2
lines changed

src/components-examples/cdk/tree/cdk-tree-flat-children-accessor/cdk-tree-flat-children-accessor-example.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
<!-- This is the tree node template for leaf nodes -->
33
<cdk-tree-node *cdkTreeNodeDef="let node" cdkTreeNodePadding
44
[style.display]="shouldRender(node) ? 'flex' : 'none'"
5+
[isDisabled]="!shouldRender(node)"
56
class="example-tree-node">
67
<!-- use a disabled button to provide padding for tree leaf -->
78
<button mat-icon-button disabled></button>
@@ -10,6 +11,7 @@
1011
<!-- This is the tree node template for expandable nodes -->
1112
<cdk-tree-node *cdkTreeNodeDef="let node; when: hasChild" cdkTreeNodePadding
1213
[style.display]="shouldRender(node) ? 'flex' : 'none'"
14+
[isDisabled]="!shouldRender(node)"
1315
[isExpandable]="true"
1416
class="example-tree-node">
1517
<button mat-icon-button cdkTreeNodeToggle [attr.aria-label]="'Toggle ' + node.name">

src/components-examples/cdk/tree/cdk-tree-flat-level-accessor/cdk-tree-flat-level-accessor-example.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
<!-- This is the tree node template for leaf nodes -->
33
<cdk-tree-node *cdkTreeNodeDef="let node" cdkTreeNodePadding
44
[style.display]="shouldRender(node) ? 'flex' : 'none'"
5+
[isDisabled]="!shouldRender(node)"
56
class="example-tree-node">
67
<!-- use a disabled button to provide padding for tree leaf -->
78
<button mat-icon-button disabled></button>
@@ -10,6 +11,7 @@
1011
<!-- This is the tree node template for expandable nodes -->
1112
<cdk-tree-node *cdkTreeNodeDef="let node; when: hasChild" cdkTreeNodePadding
1213
[style.display]="shouldRender(node) ? 'flex' : 'none'"
14+
[isDisabled]="!shouldRender(node)"
1315
[isExpandable]="node.expandable"
1416
class="example-tree-node">
1517
<button mat-icon-button cdkTreeNodeToggle

src/components-examples/cdk/tree/cdk-tree-nested-level-accessor/cdk-tree-nested-level-accessor-example.html

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
<cdk-tree #tree [dataSource]="dataSource" [levelAccessor]="levelAccessor">
22
<!-- This is the tree node template for leaf nodes -->
3-
<cdk-nested-tree-node *cdkTreeNodeDef="let node" class="example-tree-node">
3+
<cdk-nested-tree-node *cdkTreeNodeDef="let node" class="example-tree-node"
4+
[isDisabled]="!shouldRender(node)">
45
{{node.name}}
56
</cdk-nested-tree-node>
67
<!-- This is the tree node template for expandable nodes -->
78
<cdk-nested-tree-node *cdkTreeNodeDef="let node; when: hasChild"
89
[isExpandable]="node.expandable"
10+
[isDisabled]="!shouldRender(node)"
911
class="example-tree-node example-expandable">
1012
<button mat-icon-button cdkTreeNodeToggle
1113
[attr.aria-label]="'Toggle ' + node.name"

src/components-examples/cdk/tree/cdk-tree-nested-level-accessor/cdk-tree-nested-level-accessor-example.ts

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {ArrayDataSource} from '@angular/cdk/collections';
2-
import {CdkTreeModule} from '@angular/cdk/tree';
2+
import {CdkTree, CdkTreeModule} from '@angular/cdk/tree';
33
import {Component} from '@angular/core';
44
import {MatButtonModule} from '@angular/material/button';
55
import {MatIconModule} from '@angular/material/icon';
@@ -16,9 +16,31 @@ import {FLAT_DATA, FlatFoodNode} from '../tree-data';
1616
imports: [CdkTreeModule, MatButtonModule, MatIconModule],
1717
})
1818
export class CdkTreeNestedLevelAccessorExample {
19+
tree: CdkTree<FlatFoodNode>;
20+
1921
levelAccessor = (dataNode: FlatFoodNode) => dataNode.level;
2022

2123
dataSource = new ArrayDataSource(FLAT_DATA);
2224

2325
hasChild = (_: number, node: FlatFoodNode) => node.expandable;
26+
27+
getParentNode(node: FlatFoodNode) {
28+
const nodeIndex = FLAT_DATA.indexOf(node);
29+
30+
// Determine the node's parent by finding the first preceding node that's
31+
// one level shallower.
32+
for (let i = nodeIndex - 1; i >= 0; i--) {
33+
if (FLAT_DATA[i].level === node.level - 1) {
34+
return FLAT_DATA[i];
35+
}
36+
}
37+
38+
return null;
39+
}
40+
41+
shouldRender(node: FlatFoodNode): boolean {
42+
// This node should render if it is a root node or if all of its ancestors are expanded.
43+
const parent = this.getParentNode(node);
44+
return !parent || (!!this.tree?.isExpanded(parent) && this.shouldRender(parent));
45+
}
2446
}

0 commit comments

Comments
 (0)