@@ -17,6 +17,7 @@ import {
17
17
ElementRef ,
18
18
HostBinding ,
19
19
Input ,
20
+ isDevMode ,
20
21
IterableChangeRecord ,
21
22
IterableDiffer ,
22
23
IterableDiffers ,
@@ -56,6 +57,10 @@ import {
56
57
selector : 'cdk-tree' ,
57
58
exportAs : 'cdkTree' ,
58
59
template : `<ng-container cdkTreeNodeOutlet></ng-container>` ,
60
+ host : {
61
+ 'class' : 'cdk-tree' ,
62
+ 'role' : 'tree' ,
63
+ } ,
59
64
encapsulation : ViewEncapsulation . None ,
60
65
61
66
// The "OnPush" status for the `CdkTree` component is effectively a noop, so we are removing it.
@@ -65,9 +70,6 @@ import {
65
70
changeDetection : ChangeDetectionStrategy . Default
66
71
} )
67
72
export class CdkTree < T > implements AfterContentChecked , CollectionViewer , OnDestroy , OnInit {
68
- // tslint:disable:no-host-decorator-in-concrete
69
- @HostBinding ( 'attr.role' ) _role = 'tree' ;
70
-
71
73
/** Subject that emits when the component has been destroyed. */
72
74
private _onDestroy = new Subject < void > ( ) ;
73
75
@@ -128,10 +130,7 @@ export class CdkTree<T> implements AfterContentChecked, CollectionViewer, OnDest
128
130
new BehaviorSubject < { start : number , end : number } > ( { start : 0 , end : Number . MAX_VALUE } ) ;
129
131
130
132
constructor ( private _differs : IterableDiffers ,
131
- private _changeDetectorRef : ChangeDetectorRef ,
132
- private _elementRef : ElementRef < HTMLElement > ) {
133
- this . _elementRef . nativeElement . classList . add ( 'cdk-tree' ) ;
134
- }
133
+ private _changeDetectorRef : ChangeDetectorRef ) { }
135
134
136
135
ngOnInit ( ) {
137
136
this . _dataDiffer = this . _differs . find ( [ ] ) . create ( this . trackBy ) ;
@@ -302,12 +301,13 @@ export class CdkTree<T> implements AfterContentChecked, CollectionViewer, OnDest
302
301
exportAs : 'cdkTreeNode' ,
303
302
} )
304
303
export class CdkTreeNode < T > implements FocusableOption , OnDestroy , OnInit {
304
+ // TODO: mark as deprecated
305
+ // tslint:disable:no-host-decorator-in-concrete
305
306
/**
306
- * The role of the node should always be 'treeitem' .
307
+ * The role of the tree node .
307
308
*/
308
- // TODO: mark as deprecated
309
- // tslint:disable:no-host-decorator-in-concrete
310
309
@HostBinding ( 'attr.role' ) @Input ( ) role : 'treeitem' | 'group' = 'treeitem' ;
310
+ // tslint:enable:no-host-decorator-in-concrete
311
311
312
312
/**
313
313
* The most recently created `CdkTreeNode`. We save it in static variable so we can retrieve it
@@ -334,7 +334,7 @@ export class CdkTreeNode<T> implements FocusableOption, OnDestroy, OnInit {
334
334
}
335
335
protected _data : T ;
336
336
337
- // tslint:disable:no-host-decorator-in-concrete
337
+ // tslint:disable-next-line :no-host-decorator-in-concrete
338
338
@HostBinding ( 'attr.aria-expanded' ) get isExpanded ( ) : boolean {
339
339
return this . _tree . treeControl . isExpanded ( this . _data ) ;
340
340
}
@@ -354,7 +354,7 @@ export class CdkTreeNode<T> implements FocusableOption, OnDestroy, OnInit {
354
354
}
355
355
356
356
ngOnInit ( ) : void {
357
- this . _parentNodeAriaLevel = this . _getParentNodeAriaLevel ( ) ;
357
+ this . _parentNodeAriaLevel = getParentNodeAriaLevel ( this . _elementRef . nativeElement ) ;
358
358
this . _elementRef . nativeElement . setAttribute ( 'aria-level' , String ( this . level + 1 ) ) ;
359
359
}
360
360
@@ -382,20 +382,29 @@ export class CdkTreeNode<T> implements FocusableOption, OnDestroy, OnInit {
382
382
}
383
383
this . role = 'treeitem' ;
384
384
}
385
+ }
385
386
386
- private _getParentNodeAriaLevel ( ) : number {
387
- let parent = this . _elementRef . nativeElement . parentElement ;
388
- while ( parent &&
389
- ! ( parent . classList . contains ( 'cdk-nested-tree-node' ) || parent . classList . contains ( 'cdk-tree' ) ) ) {
390
- parent = parent . parentElement ;
391
- }
392
- if ( ! parent ) {
387
+ function getParentNodeAriaLevel ( nodeElement : HTMLElement ) : number {
388
+ debugger ;
389
+ let parent = nodeElement . parentElement ;
390
+ while ( parent && isNodeElement ( parent ) ) {
391
+ parent = parent . parentElement ;
392
+ }
393
+ if ( ! parent ) {
394
+ if ( isDevMode ( ) ) {
393
395
throw Error ( 'Incorrect tree structure containing detached node.' ) ;
394
- } else if ( parent . classList . contains ( 'cdk-nested-tree-node' ) ) {
395
- return parseInt ( parent . getAttribute ( 'aria-level' ) ! ) ;
396
396
} else {
397
- // parent.classList.contains('cdk-tree')
398
- return 0 ;
397
+ return - 1 ;
399
398
}
399
+ } else if ( parent . classList . contains ( 'cdk-nested-tree-node' ) ) {
400
+ return Number ( parent . getAttribute ( 'aria-level' ) ! ) ;
401
+ } else {
402
+ // The ancestor element is the cdk-tree itself
403
+ return 0 ;
400
404
}
401
405
}
406
+
407
+ function isNodeElement ( element : HTMLElement ) {
408
+ const classList = element ?. classList ;
409
+ return ! ( classList ?. contains ( 'cdk-nested-tree-node' ) || classList ?. contains ( 'cdk-tree' ) ) ;
410
+ }
0 commit comments