src/treeview/treeview.component.ts
Get started with importing the module:
Example :import { TreeviewModule } from 'carbon-components-angular';
AfterViewInit
OnInit
OnDestroy
providers |
TreeViewService
|
selector | cds-tree-view |
template |
|
Properties |
|
Methods |
|
Inputs |
Outputs |
Accessors |
constructor(document: Document, treeViewService: TreeViewService, elementRef: ElementRef)
|
||||||||||||
Defined in src/treeview/treeview.component.ts:110
|
||||||||||||
Parameters :
|
id | |
Type : string
|
|
Default value : `tree-view-${TreeViewComponent.treeViewCount++}`
|
|
Defined in src/treeview/treeview.component.ts:84
|
isMultiSelect | |
Type : boolean
|
|
Defined in src/treeview/treeview.component.ts:100
|
|
Experimental - Enable to select multiple nodes |
label | |
Type : string | TemplateRef<any>
|
|
Defined in src/treeview/treeview.component.ts:88
|
|
Tree view label |
labelContext | |
Type : any
|
|
Defined in src/treeview/treeview.component.ts:92
|
|
Optional context for label if it's a template |
size | |
Type : "xs" | "sm"
|
|
Default value : "sm"
|
|
Defined in src/treeview/treeview.component.ts:96
|
|
Specify the size of the list items in the tree |
tree | |
Type : Node[]
|
|
Defined in src/treeview/treeview.component.ts:73
|
|
Pass |
select | |
Type : EventEmitter
|
|
Defined in src/treeview/treeview.component.ts:104
|
toggle | |
Type : EventEmitter
|
|
Defined in src/treeview/treeview.component.ts:105
|
Private copyNode | ||||||
copyNode(node: Node)
|
||||||
Defined in src/treeview/treeview.component.ts:199
|
||||||
Parameters :
Returns :
Node
|
Public isProjected |
isProjected()
|
Defined in src/treeview/treeview.component.ts:195
|
Returns :
any
|
Public isTemplate | ||||
isTemplate(value)
|
||||
Defined in src/treeview/treeview.component.ts:191
|
||||
Parameters :
Returns :
boolean
|
navigateTree | ||||||||
navigateTree(event: KeyboardEvent)
|
||||||||
Defined in src/treeview/treeview.component.ts:156
|
||||||||
Navigate tree using tree walker
Parameters :
Returns :
void
|
ngAfterViewInit |
ngAfterViewInit()
|
Defined in src/treeview/treeview.component.ts:138
|
Initialize tree walker to support keyboard navigation
Returns :
void
|
ngOnDestroy |
ngOnDestroy()
|
Defined in src/treeview/treeview.component.ts:131
|
Returns :
void
|
ngOnInit |
ngOnInit()
|
Defined in src/treeview/treeview.component.ts:121
|
Subscribe for node selection
Returns :
void
|
onNodeFocusChange | ||||||||
onNodeFocusChange(node: Node)
|
||||||||
Defined in src/treeview/treeview.component.ts:181
|
||||||||
Node focus change
Parameters :
Returns :
void
|
onNodeToggle | ||||||||
onNodeToggle(eventOnNode: EventOnNode)
|
||||||||
Defined in src/treeview/treeview.component.ts:170
|
||||||||
Propagate node toggle event
Parameters :
Returns :
void
|
Private _tree |
Type : Node[]
|
Default value : []
|
Defined in src/treeview/treeview.component.ts:109
|
root |
Type : ElementRef
|
Decorators :
@ViewChild('treeWrapper')
|
Defined in src/treeview/treeview.component.ts:106
|
Private subscription |
Type : Subscription
|
Defined in src/treeview/treeview.component.ts:110
|
Static treeViewCount |
Type : number
|
Default value : 0
|
Defined in src/treeview/treeview.component.ts:82
|
Public treeViewService |
Type : TreeViewService
|
Defined in src/treeview/treeview.component.ts:114
|
Private treeWalker |
Type : TreeWalker
|
Defined in src/treeview/treeview.component.ts:108
|
tree | ||||||
gettree()
|
||||||
Defined in src/treeview/treeview.component.ts:78
|
||||||
settree(treeNodes: Node[])
|
||||||
Defined in src/treeview/treeview.component.ts:73
|
||||||
Pass
Parameters :
Returns :
void
|
isMultiSelect | ||||||
setisMultiSelect(isMulti: boolean)
|
||||||
Defined in src/treeview/treeview.component.ts:100
|
||||||
Experimental - Enable to select multiple nodes
Parameters :
Returns :
void
|
import { DOCUMENT } from "@angular/common";
import {
Component,
Input,
Output,
TemplateRef,
EventEmitter,
AfterViewInit,
Inject,
ViewChild,
ElementRef,
OnInit,
OnDestroy
} from "@angular/core";
import { Subscription } from "rxjs";
import { EventOnNode, Node } from "./tree-node.types";
import { TreeViewService } from "./treeview.service";
/**
* Get started with importing the module:
*
* ```typescript
* import { TreeviewModule } from 'carbon-components-angular';
* ```
*
* [See demo](../../?path=/story/components-tree-view--basic)
*/
@Component({
selector: "cds-tree-view",
template: `
<label
*ngIf="label"
[id]="id"
class="cds--label">
<ng-container *ngIf="!isTemplate(label)">{{label}}</ng-container>
<ng-template
*ngIf="isTemplate(label)"
[ngTemplateOutlet]="label"
[ngTemplateOutletContext]="{ $implicit: labelContext }">
</ng-template>
</label>
<div
class="cds--tree"
[ngClass]="{
'cds--tree--sm': size === 'sm',
'cds--tree--xs': size === 'xs'
}"
[attr.aria-label]="label ? label : null"
[attr.aria-labelledby]="!label ? id : null"
[attr.aria-multiselectable]="isMultiSelect || null"
role="tree"
(keydown)="navigateTree($event)"
#treeWrapper>
<ng-container *ngIf="isProjected(); else notProjected">
<ng-content></ng-content>
</ng-container>
<ng-template #notProjected>
<cds-tree-node
*ngFor="let node of tree"
[node]="node"
(nodetoggle)="onNodeToggle($event)">
</cds-tree-node>
</ng-template>
</div>
`,
providers: [TreeViewService]
})
export class TreeViewComponent implements AfterViewInit, OnInit, OnDestroy {
/**
* Pass `Node[]` array to have tree view render the nodes
* Passing value will disregard projected content
*/
@Input() set tree(treeNodes: Node[]) {
this._tree = treeNodes.map((node) => this.copyNode(node));
this.treeViewService.contentProjected = false;
}
get tree() {
return this._tree;
}
static treeViewCount = 0;
@Input() id = `tree-view-${TreeViewComponent.treeViewCount++}`;
/**
* Tree view label
*/
@Input() label: string | TemplateRef<any>;
/**
* Optional context for label if it's a template
*/
@Input() labelContext: any;
/**
* Specify the size of the list items in the tree
*/
@Input() size: "xs" | "sm" = "sm";
/**
* **Experimental** - Enable to select multiple nodes
*/
@Input() set isMultiSelect(isMulti: boolean) {
this.treeViewService.isMultiSelect = isMulti;
}
@Output() select = new EventEmitter<Node | Node[]>();
@Output() toggle = new EventEmitter<Node>();
@ViewChild("treeWrapper") root: ElementRef;
private treeWalker: TreeWalker;
private _tree: Node[] = [];
private subscription: Subscription;
constructor(
@Inject(DOCUMENT) private document: Document,
public treeViewService: TreeViewService,
private elementRef: ElementRef
) {}
/**
* Subscribe for node selection
*/
ngOnInit(): void {
this.subscription = this.treeViewService.selectionObservable.subscribe((nodesMap: Map<string, Node>) => {
// Get all values from the map to emit
const nodes = [...nodesMap.values()];
this.select.emit(this.treeViewService.isMultiSelect ? nodes : nodes[0]);
});
this.subscription.add(this.treeViewService.focusNodeObservable.subscribe(node => this.onNodeFocusChange(node)));
}
ngOnDestroy(): void {
this.subscription.unsubscribe();
}
/**
* Initialize tree walker to support keyboard navigation
*/
ngAfterViewInit(): void {
this.treeWalker = this.document.createTreeWalker(this.root.nativeElement, NodeFilter.SHOW_ELEMENT, {
acceptNode: function (node: HTMLElement) {
if (node.classList.contains(`cds--tree-node--disabled`)) {
return NodeFilter.FILTER_REJECT;
}
if (node.matches(`div.cds--tree-node`)) {
return NodeFilter.FILTER_ACCEPT;
}
return NodeFilter.FILTER_SKIP;
}
});
}
/**
* Navigate tree using tree walker
* @param event - KeyboardEvent
*/
navigateTree(event: KeyboardEvent) {
if (event.key === "ArrowUp") {
(this.treeWalker.previousNode() as HTMLElement)?.focus();
}
if (event.key === "ArrowDown") {
(this.treeWalker.nextNode() as HTMLElement)?.focus();
}
}
/**
* Propagate node toggle event
* @param eventOnNode - EventOnNode
*/
onNodeToggle(eventOnNode: EventOnNode) {
if (!eventOnNode) {
return;
}
this.toggle.emit(eventOnNode.node);
}
/**
* Node focus change
* @param node - Node
*/
onNodeFocusChange(node: Node) {
if (!node) {
// if for some reason the focused node is not defined we fallback on the root element of the treeview
this.treeWalker.currentNode = this.treeWalker.root;
return;
}
// Update current node based on focus change to have a better keyboard navigation experience
this.treeWalker.currentNode = this.elementRef.nativeElement.querySelector(`#${CSS.escape(node.id)}`);
}
public isTemplate(value) {
return value instanceof TemplateRef;
}
public isProjected() {
return this.treeViewService.contentProjected;
}
private copyNode(node: Node): Node {
// making a recursive shallow copy to avoid performance issues when deeply cloning templateRefs if defined in the node
const copiedNode = Object.assign({}, node);
if (node.children) {
copiedNode.children = node.children.map(child => this.copyNode(child));
}
return copiedNode;
}
}