Angular Tree Component Overview
The Angular Tree Component allows users to represent hierarchical data in a tree-view structure with parent-child relationships, as well as to define static tree-view structure without a corresponding data model. Its primary purpose is to allow end-users to visualize and navigate within hierarchical data structures. The Ignite UI for Angular Tree Component also provides load on demand capabilities, item activation, bi-state and tri-state cascading selection of items through built-in checkboxes, built-in keyboard navigation and more.
Angular Tree Example
In this basic Angular Tree example, you can see how to define an igx-tree
and its nodes by specifying the node hierarchy and iterating through a hierarchical data set.
Getting Started with Ignite UI for Angular Tree
To get started with the Ignite UI for Angular Tree component, first you need to install Ignite UI for Angular. In an existing Angular application, type the following command:
ng add igniteui-angular
For a complete introduction to the Ignite UI for Angular, read the getting started topic.
The next step is to import the IgxTreeModule
in your app.module file.
// app.module.ts
...
import { IgxTreeModule } from 'igniteui-angular';
// import { IgxTreeModule } from '@infragistics/igniteui-angular'; for licensed package
@NgModule({
...
imports: [..., IgxTreeModule],
...
})
export class AppModule {}
Alternatively, as of 16.0.0
you can import the IgxTreeComponent
as a standalone dependency, or use the IGX_TREE_DIRECTIVES
token to import the component and all of its supporting components and directives.
// home.component.ts
import { IGX_TREE_DIRECTIVES } from 'igniteui-angular';
// import { IGX_TREE_DIRECTIVES } from '@infragistics/igniteui-angular'; for licensed package
@Component({
selector: 'app-home',
template: `
<igx-tree>
<igx-tree-node>
Angular Libraries
<igx-tree-node>Ignite UI for Angular</igx-tree-node>
<igx-tree-node>Angular Material</igx-tree-node>
</igx-tree-node>
<igx-tree-node>
Web Component Libraries
<igx-tree-node>Ignite UI for Web Components</igx-tree-node>
<igx-tree-node>Open UI 5</igx-tree-node>
</igx-tree-node>
<igx-tree-node>
Blazor Libraries
<igx-tree-node>Ignite UI for Blazor</igx-tree-node>
</igx-tree-node>
</igx-tree>
`,
styleUrls: ['home.component.scss'],
standalone: true,
imports: [IGX_TREE_DIRECTIVES]
/* or imports: [IgxTreeComponent, IgxTreeNodeComponent] */
})
export class HomeComponent {}
Now that we have the Ignite UI for Angular Tree module or directives imported, let’s get started with a basic configuration of the igx-tree
and its nodes.
Using the Angular Tree
IgxTreeNodesComponent is the representation of every node that belongs to the IgxTreeComponent.
Nodes provide disabled, active, selected and expanded properties, which give you opportunity to configure the states of the node as per your requirement.
data property can be used to add a reference to the data entry the node represents. Binding [data]
is required for searching through nodes using IgxTreeComponent.findNodes().
Declaring a tree
Nodes can be declared using one of the following approaches.
- Declaring the tree and its nodes by specifying the node hierarchy and iterating through a data set
<igx-tree>
<igx-tree-node *ngFor="let node of data" [data]="node" [expanded]="isNodeExpaded(node)" [selected]="isNodeSelected(node)">
{{ node.text }}
<img [src]="node.image" [alt]="node.imageAlt" />
<igx-tree-node *ngFor="let child of node.children" [data]="child" [expanded]="isNodeExpaded(child)" [selected]="isNodeSelected(child)">
{{ child.text }}
</igx-tree-node>
</igx-tree-node>
</igx-tree>
Nodes can be bound to a data model so that their expanded and selected states are reflected in the underlying data as well.
<igx-tree (nodeSelection)="handleSelectionEvent($event)">
<igx-tree-node *ngFor="let node of data" [data]="node" [(expanded)]="node.expanded" [(selected)]="node.selected">
{{ node.text }}
<img [src]="node.image" [alt]="node.imageAlt" />
<igx-tree-node *ngFor="let child of node.children" [data]="child">
<a igxTreeNodeLink [href]="child.url" target="_blank">
{{ child.text }}
</a>
</igx-tree-node>
</igx-tree-node>
</igx-tree>
- Declaring a tree by creating static unbound nodes
In order to render a tree you do not necessarily need a data set - individual nodes can be created without an underlying data model:
<igx-tree>
<igx-tree-node [expanded]="true" [selected]="false">
I am a parent node 1
<img src="hard_coded_src.webb" alt="Alt Text" />
<igx-tree-node [expanded]="true" [selected]="false">
I am a child node 1
<igx-tree-node>
<a igxTreeNodeLink href="https://google.com" target="_blank">
I am a child node of the child
</a>
</igx-tree-node>
</igx-tree-node>
</igx-tree-node>
<igx-tree-node [expanded]="false" [selected]="false">
I am a parent node 2
<img src="hard_coded_src.webb" alt="Alt Text" />
<igx-tree-node [expanded]="false" [selected]="false">
I am a child node 1
</igx-tree-node>
</igx-tree-node>
<igx-tree-node [selected]="false" [disabled]="true">
I am a parent node 3
</igx-tree-node>
</igx-tree>
Nodes with links
When a node should render a link, the IgxTreeNodeLink
directive should be added to the <a>
tag. This will ensure the proper aria role is assigned to the node's DOM elements.
<igx-tree>
<igx-tree-node *ngFor="let node of data" [data]="node" [expanded]="isNodeExpaded(node)" [selected]="isNodeSelected(node)">
{{ node.text }}
<img [src]="node.image" [alt]="node.imageAlt" />
<igx-tree-node *ngFor="let child of node.children" [data]="child">
<a igxTreeNodeLink [href]="child.url" target="_blank">
{{ child.text }}
</a>
</igx-tree-node>
</igx-tree-node>
</igx-tree>
Node Interactions
IgxTreeNodeComponent could be expanded or collapsed:
- by clicking on the node expand indicator (default behavior).
- by clicking on the node if the
igx-tree
toggleNodeOnClick property is set totrue
.
<igx-tree [toggleNodeOnClick]="true">
<igx-tree-node *ngFor="let node of data" [data]="node">
{{ node.text }}
<igx-tree-node *ngFor="let child of node.children" [data]="child">
{{ child.text }}
</igx-tree-node>
</igx-tree-node>
</igx-tree>
By default, multiple nodes could be expanded at the same time. In order to change this behavior and allow expanding only single branch at a time, the singleBranchExpand property could be enabled. This way when a node is expanded, all of the others already expanded branches in the same level will be collapsed.
<igx-tree [singleBranchExpand]="true">
<igx-tree-node *ngFor="let node of data" [data]="node">
{{ node.text }}
<igx-tree-node *ngFor="let child of node.children" [data]="child">
{{ child.text }}
</igx-tree-node>
</igx-tree-node>
</igx-tree>
In addition, the IgxTree provides the following API methods for node interactions:
- expand - expands the node with animation.
- collapse - collapses the node with animation.
- toggle - toggles node expansion state with animation.
- collapseAll - collapses the specified nodes with animation. If no nodes are passed, collapses all parent nodes.
- expandAll - sets the specified nodes as expanded with animation. If no nodes are passed, expands all parent nodes.
- deselectAll - deselects all nodes. If a nodes array is passed, deselects only the specified nodes. Does not emit nodeSelection event.
Finding Nodes
You can find a specific node within an IgxTree by using the findNodes method. It returns an array of nodes, which match the specified data. When finding nodes in more complex data structure scenarios, like composite primary keys, you can pass a custom comparer function in order to specify the criteria for finding nodes based on the data.
<igx-tree>
<igx-tree-node *ngFor="let node of data" [data]="node" [expanded]="isNodeExpaded(node)" [selected]="isNodeSelected(node)">
{{ node.text }}
<img [src]="node.image" alt="node.imageAlt" />
<igx-tree-node *ngFor="let child of node.children" [data]="child" [expanded]="isNodeExpaded(child)" [selected]="isNodeSelected(child)">
{{ child.text }}
</igx-tree-node>
</igx-tree-node>
</igx-tree>
export class MyTreeViewComponent {
public data: { [key: string]: any, valueKey: string } = MY_DATA;
@ViewChild(IgxTreeComponent, { read: IgxTreeComponent })
public tree;
findNode(valueKey: string) {
const comparer: IgxTreeSearchResolver =
(data: any, node: IgxTreeNodeComponent) => node.data.valueKey === data;
const matchingNodes: IgxTreeNode<{ [key: string]: any, valueKey: string }>[] = this.tree.findNodes(valueKey, comparer);
}
}
Templating
To create a reusable template for your nodes, declare <ng-template>
within igx-tree
.
<igx-tree>
<igx-tree-node *ngFor="let node of data" [data]="node">
<ng-container *ngTemplateOutlet="#nodeTemplate; context: { $implicit: node }"></ng-container>
<igx-tree-node *ngFor="let child of node.ChildCompanies" [data]="child">
<ng-container *ngTemplateOutlet="#nodeTemplate; context: { $implicit: child}"></ng-container>
</igx-tree-node>
</igx-tree-node>
<ng-template #nodeTemplate let-data>
<div class="node-header company">
<igx-icon class="company__logo">{{ data.Logo }}</igx-icon>
<div class="company__name">{{ data.CompanyName }}</div>
</div>
</ng-template>
</igx-tree>
Additionally, by using the expandIndicator input you have the ability to set a custom template to be used for rendering the expand/collapse indicators of nodes.
<igx-tree>
<igx-tree-node *ngFor="let node of data" [data]="node">
</igx-tree-node>
<ng-template igxTreeExpandIndicator let-expanded>
<igx-icon>{{ expanded ? 'expand_less' : 'expand_more' }}</igx-icon>
</ng-template>
</igx-tree>
Angular Tree Selection
In order to setup node selection in the igx-tree
, you just need to set its selection property. This property accepts the following three modes: None, BiState and Cascading. Below we will take a look at each of them in more detail.
None
In the igx-tree
by default node selection is disabled. Users cannot select or deselect a node through UI interaction, but these actions can still be completed through the provided API method.
Bi-State
To enable bi-state node selection in the igx-tree
just set the selection property to BiState. This will render a checkbox for every node. Each node has two states - selected or not. This mode supports multiple selection.
<igx-tree selection="BiState">
</igx-tree>
Cascading
To enable cascading node selection in the igx-tree
, just set the selection property to Cascading. This will render a checkbox for every node.
<igx-tree selection="Cascading">
</igx-tree>
In this mode a parent's selection state entirely depends on the selection state of its children. When a parent has some selected and some deselected children, its checkbox is in an indeterminate state.
Angular Tree Checkbox
The Angular Tree component provides built-in support for checkboxes, allowing users to select more than one item.
The TreeView checkboxes also have a tri-state mode, which is applicable only for partially selected parent nodes. In this mode, a parent node will go into the indeterminate state when some but not all of the child nodes are checked.
Keyboard Navigation
Keyboard navigation in IgxTree provides a rich variety of keyboard interactions for the user. This functionality is enabled by default and allows users to navigate through the nodes.
The IgxTree navigation is compliant with W3C accesibility standards and convenient to use.
Key Combinations
- Arrow Down - navigates to the next visible node. Marks the node as active. Does nothing if on the LAST node
- Ctrl + Arrow Down - navigates to the next visible node. Does nothing if on the LAST node
- Arrow Up - navigates to the previous visible node. Marks the node as active. Does nothing if on the FIRST node
- Ctrl + Arrow Up - navigates to the previous visible node. Does nothing if on the FIRST node
- Arrow Left - on an expanded parent node, collapses it. If on a child node, moves to its parent node.
- Arrow Right - on an expanded parent node, navigates to the first child of the node. If on a collapsed parent node, expands it.
- Home - navigates to the FIRST node
- End - navigates to the LAST visible node
- Tab - navigates to the next focusable element on the page, outside of the tree
- Shift + Tab - navigates to the previous focusable element on the page, outside of the tree
- Space - toggles selection of the current node. Marks the node as active.
- Shift + Space - toggles selection of all nodes between the active one and the one pressed Space while holding Shift if selection is enabled
- Enter - activates the focused node. If the node has link in it, open the link
- * - expands the node and all sibling nodes on the same level
When selection is enabled, end-user selection of nodes is only allowed through the rendered checkbox. Since both selection types allow multiple selection, the following mouse + keyboard interactions are available:
- Click - when performed on the node checkbox, toggles selection of the node if selection is enabled. Otherwise, focuses the node
- Shift + Click - when performed on the node checkbox, toggles selection of all nodes between the active one and the one clicked while holding Shift if selection is enabled
Angular Tree Load On Demand
The Ignite UI for Angular IgxTree can be rendered in such way that it requires the minimal amount of data to be retrieved from the server so the user could see it as quickly as possible. With this dynamic data loading approach, only after the user expands a node, the children for that particular parent node will be retrieved. This mechanism, also known as Load on Demand, can be easily configured to work with any remote data.
Demo
After the user clicks the expand icon, it is replaced by a loading indicator. When the loading property resolves to false
, the loading indicator disappears and the children are loaded.
Angular Tree Styling
Using the Ignite UI for Angular Theming, we can greatly alter the tree appearance. First, in order for us to use the functions exposed by the theme engine, we need to import the index
file in our style file:
@use "igniteui-angular/theming" as *;
// IMPORTANT: Prior to Ignite UI for Angular version 13 use:
// @import '~igniteui-angular/lib/core/styles/themes/index';
Following the simplest approach, we create a new theme that extends the tree-theme and pass the parameters, which we would like to change:
$custom-tree-theme:tree-theme(
$background-selected: #ffe6cc,
$background-active: #ecaa53,
$background-active-selected: #ff8c1a
);
Using CSS Variables
The last step is to include the component's theme.
:host {
@include css-vars($custom-tree-theme);
}
Using Theme Overrides
In order to style components for older browsers, like Internet Explorer 11, we have to use a different approach, since CSS variables are not supported there.
If the component is using the Emulated ViewEncapsulation, it is necessary to penetrate
this encapsulation using ::ng-deep
. To prevent the custom theme to leak into other components, be sure to include the :host
selector before ::ng-deep
:
:host {
::ng-deep {
@include tree($custom-tree-theme);
}
}
Known Issues and Limitations
Limitation | Description |
---|---|
Recursive template nodes | The igx-tree does not support recursively creating the igx-tree-nodes via template. Learn more. All of the nodes should be declared manually, meaning if you intend to visualize a very deep hierarchy, this would impact the size of your template file. The tree is intended to be primarily used as a layout / navigational component. If a hierarchical data source with numerous levels of depth and homogenous data needs to be visualized, you could use the IgxTreeGrid |
Using IgxTreeNodes with old View Engine (pre-Ivy) | There is an issue in Angular's View Engine (pre-Ivy) that prevents the tree from being used when enableIvy: false is set in tsconfig.json |
Tab navigation in FireFox | Tabbing into the tree via keyboard navigation, when the tree has a scrollbar, will first focus the igx-tree-node element. This is the default behavior in FireFox, however it can be resolved by putting an explicit tabIndex = -1 on the tree. |