File

src/treeview/treeview.component.ts

Description

Get started with importing the module:

Example :
import { TreeviewModule } from 'carbon-components-angular';

See demo

Implements

AfterViewInit OnInit OnDestroy

Metadata

Index

Properties
Methods
Inputs
Outputs
Accessors

Constructor

constructor(document: Document, treeViewService: TreeViewService, elementRef: ElementRef)
Parameters :
Name Type Optional
document Document No
treeViewService TreeViewService No
elementRef ElementRef No

Inputs

id
Type : string
Default value : `tree-view-${TreeViewComponent.treeViewCount++}`
isMultiSelect
Type : boolean

Experimental - Enable to select multiple nodes

label
Type : string | TemplateRef<any>

Tree view label

labelContext
Type : any

Optional context for label if it's a template

size
Type : "xs" | "sm"
Default value : "sm"

Specify the size of the list items in the tree

tree
Type : Node[]

Pass Node[] array to have tree view render the nodes Passing value will disregard projected content

Outputs

select
Type : EventEmitter
toggle
Type : EventEmitter

Methods

Private copyNode
copyNode(node: Node)
Parameters :
Name Type Optional
node Node No
Returns : Node
Public isProjected
isProjected()
Returns : any
Public isTemplate
isTemplate(value)
Parameters :
Name Optional
value No
Returns : boolean
navigateTree
navigateTree(event: KeyboardEvent)

Navigate tree using tree walker

Parameters :
Name Type Optional Description
event KeyboardEvent No
  • KeyboardEvent
Returns : void
ngAfterViewInit
ngAfterViewInit()

Initialize tree walker to support keyboard navigation

Returns : void
ngOnDestroy
ngOnDestroy()
Returns : void
ngOnInit
ngOnInit()

Subscribe for node selection

Returns : void
onNodeFocusChange
onNodeFocusChange(node: Node)

Node focus change

Parameters :
Name Type Optional Description
node Node No
  • Node
Returns : void
onNodeToggle
onNodeToggle(eventOnNode: EventOnNode)

Propagate node toggle event

Parameters :
Name Type Optional Description
eventOnNode EventOnNode No
  • EventOnNode
Returns : void

Properties

Private _tree
Type : Node[]
Default value : []
root
Type : ElementRef
Decorators :
@ViewChild('treeWrapper')
Private subscription
Type : Subscription
Static treeViewCount
Type : number
Default value : 0
Public treeViewService
Type : TreeViewService
Private treeWalker
Type : TreeWalker

Accessors

tree
gettree()
settree(treeNodes: Node[])

Pass Node[] array to have tree view render the nodes Passing value will disregard projected content

Parameters :
Name Type Optional
treeNodes Node[] No
Returns : void
isMultiSelect
setisMultiSelect(isMulti: boolean)

Experimental - Enable to select multiple nodes

Parameters :
Name Type Optional
isMulti boolean No
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;
	}
}
Legend
Html element
Component
Html element with directive

results matching ""

    No results matching ""