55 * Use of this source code is governed by an MIT-style license that can be
66 * found in the LICENSE file at https://angular.io/license
77 */
8+ import { FocusableOption } from '@angular/cdk/a11y' ;
89import { CollectionViewer , DataSource } from '@angular/cdk/collections' ;
910import {
1011 ChangeDetectionStrategy ,
1112 ChangeDetectorRef ,
1213 Component ,
1314 ContentChildren ,
15+ Directive ,
16+ ElementRef ,
1417 Input ,
1518 IterableDiffers ,
1619 IterableDiffer ,
@@ -26,15 +29,91 @@ import {BehaviorSubject} from 'rxjs/BehaviorSubject';
2629import { takeUntil } from 'rxjs/operators/takeUntil' ;
2730import { Subject } from 'rxjs/Subject' ;
2831import { Subscription } from 'rxjs/Subscription' ;
29- import { CdkTreeNodeDef , CdkTreeNode , CdkTreeNodeOutletContext } from './node' ;
32+ import { CdkTreeNodeDef , CdkTreeNodeOutletContext } from './node' ;
3033import { CdkTreeNodeOutlet } from './outlet' ;
3134import { TreeControl } from './control/tree-control' ;
3235import {
3336 getTreeControlMissingError ,
3437 getTreeMissingMatchingNodeDefError ,
35- getTreeMultipleDefaultNodeDefsError
38+ getTreeMultipleDefaultNodeDefsError ,
39+ getTreeControlFunctionsMissingError
3640} from './tree-errors' ;
3741
42+ /**
43+ * Tree node for CdkTree. It contains the data in the tree node.
44+ */
45+ @Directive ( {
46+ selector : 'cdk-tree-node' ,
47+ exportAs : 'cdkTreeNode' ,
48+ host : {
49+ '[attr.aria-expanded]' : 'isExpanded' ,
50+ '[attr.aria-level]' : 'level' ,
51+ '[attr.role]' : 'role' ,
52+ 'class' : 'cdk-tree-node' ,
53+ } ,
54+ } )
55+ export class CdkTreeNode < T > implements FocusableOption , OnDestroy {
56+ /**
57+ * The most recently created `CdkTreeNode`. We save it in static variable so we can retrieve it
58+ * in `CdkTree` and set the data to it.
59+ */
60+ static mostRecentTreeNode : CdkTreeNode < any > | null = null ;
61+
62+ /** Subject that emits when the component has been destroyed. */
63+ protected _destroyed = new Subject < void > ( ) ;
64+
65+ /** The tree node's data. */
66+ get data ( ) : T { return this . _data ; }
67+ set data ( value : T ) {
68+ this . _data = value ;
69+ this . _setRoleFromData ( ) ;
70+ }
71+ protected _data : T ;
72+
73+ get isExpanded ( ) : boolean {
74+ return this . _tree . treeControl . isExpanded ( this . _data ) ;
75+ }
76+
77+ get level ( ) : number {
78+ return this . _tree . treeControl . getLevel ? this . _tree . treeControl . getLevel ( this . _data ) : 0 ;
79+ }
80+
81+ /**
82+ * The role of the node should be 'group' if it's an internal node,
83+ * and 'treeitem' if it's a leaf node.
84+ */
85+ @Input ( ) role : 'treeitem' | 'group' = 'treeitem' ;
86+
87+ constructor ( protected _elementRef : ElementRef ,
88+ protected _tree : CdkTree < T > ) {
89+ CdkTreeNode . mostRecentTreeNode = this ;
90+ }
91+
92+ ngOnDestroy ( ) {
93+ this . _destroyed . next ( ) ;
94+ this . _destroyed . complete ( ) ;
95+ }
96+
97+ /** Focuses the menu item. Implements for FocusableOption. */
98+ focus ( ) : void {
99+ this . _elementRef . nativeElement . focus ( ) ;
100+ }
101+
102+ private _setRoleFromData ( ) : void {
103+ if ( this . _tree . treeControl . isExpandable ) {
104+ this . role = this . _tree . treeControl . isExpandable ( this . _data ) ? 'group' : 'treeitem' ;
105+ } else {
106+ if ( ! this . _tree . treeControl . getChildren ) {
107+ throw getTreeControlFunctionsMissingError ( ) ;
108+ }
109+ this . _tree . treeControl . getChildren ( this . _data ) . pipe ( takeUntil ( this . _destroyed ) )
110+ . subscribe ( children => {
111+ this . role = children && children . length ? 'group' : 'treeitem' ;
112+ } ) ;
113+ }
114+ }
115+ }
116+
38117
39118/**
40119 * CDK tree component that connects with a data source to retrieve data of type `T` and renders
@@ -67,7 +146,7 @@ export class CdkTree<T> implements CollectionViewer, OnInit, OnDestroy {
67146 private _defaultNodeDef : CdkTreeNodeDef < T > | null ;
68147
69148 /** Data subscription */
70- private _dataSubscription : Subscription | null ;
149+ private _dataSubscription : Subscription | null ;
71150
72151 /**
73152 * Provides a stream containing the latest data array to render. Influenced by the tree's
@@ -91,9 +170,6 @@ export class CdkTree<T> implements CollectionViewer, OnInit, OnDestroy {
91170 /** The tree node template for the tree */
92171 @ContentChildren ( CdkTreeNodeDef ) _nodeDefs : QueryList < CdkTreeNodeDef < T > > ;
93172
94- /** The tree node inside the tree */
95- @ContentChildren ( CdkTreeNode , { descendants : true } ) items : QueryList < CdkTreeNode < T > > ;
96-
97173 // TODO(tinayuangao): Setup a listener for scrolling, emit the calculated view to viewChange.
98174 // Remove the MAX_VALUE in viewChange
99175 /**
0 commit comments