Skip to content

Tree Specification

Teodosia Hristodorova edited this page Nov 20, 2023 · 37 revisions

IgxTree Specification

Contents

  1. Overview

  2. User Stories

  3. Functionality

    3.1 End-user Expereince

    3.2 Developer Experience

    3.3 Globalization/Localization

    3.4 Keyboard Navigation

    3.5 API

  4. Test scenarios

    4.1. Automation

    4.2. Manual tests

  5. Accessibility

  6. Assumptions and Limitations

  7. References

Owned by

Team Name

Developer Name

Stefan Ivanov

Requires approval from

  • Peer Developer Name | Date:
  • Stefan Ivanov | Date: 15 Feb 2021

Signed off by

  • Konstantin Dinev | Date: 14 Apr 2021
  • Platform Architect Name | Date:

Revision History

Version User Date Notes
1 Viktor Slavov, Stefan Ivanov Feb 15, 2021 Initial Draft
2 Viktor Slavov Feb 18, 2021 Fix Link Formatting
3 Viktor Slavov Mar 8, 2021 Rework selection events
4. Viktor Slavov Mar 29, 2021 Update TreeNode API
5. Viktor Slavov Apr 09, 2021 Update test cases, finalize API, limitations
6. Viktor Slavov Apr 19, 2021 Update outdated snippets
7. Teodosia Hristodorova Nov 20, 2023 Add toggleNodeOnClick property

Objectives

The IgxTreeComponent is a component that allows a developer to show a set of nodes in a hierarchical fashion. It allows end-users to easily navigating structured information e.g. a site map or documentation topics. The igxTreeComponent should primarily be used as a navigational component when visualizing a nested data structure.

Acceptance criteria

The tree should have the following features out-of-the-box

  1. Rendering nested nodes in a hierarchical fashion, maintaining a parent-child relationship
  2. Expanding and collapsing node, so all crucial information can be clearly visible at all times
  3. Disabled nodes which do not support any user interaction (e.g. permission based tree view)
  4. Active nodes - a note marked as "active" is highlighted w/ a specific style (e.g. the current location on a site map)
  5. Selection
    • 5.1. None - no selection through user input. API selection manipulation is still possible
    • 5.2. BiState - each node has a checkbox through which it can be selected via user input. Each node has two states - selected or not. Supports multiple selection.
    • 5.3. Cascading - selecting a node selects its child nodes. Partially selected collections mark the resp. nodes as indeterminate.
  6. Keyboard navigation, supporting all of the previously mention features
  7. Link support, when tree nodes should contain anchors (<a> tags)
  8. Accessibility features - all nodes should have proper aria roles and be fully readable and traversable via screen readers

...

End-user Stories

The tree should allow me, as an end-user, to understand the relationships between the various nodes and use it to navigate the hierarchy of content.

End-user stories:

  • Story 1: As an end-user, I want to have the nodes organized in a clear hierarchy, so that I can understand their relationship with one another.
  • Story 2: As an end-user, I want to have the nodes organized in a clear hierarchy, so that I can easily expand/collapse them and select the node I am looking for.
  • Story 3: As an end-user, I want to be able to expand/collapse nodes, so that I can create a state with the most viable information for me on my screen.
  • Story 4: As an end-user, I want to have animations when nodes are expanded/collapsed, so that their relationship with one another is more obvious.
  • Story 5: As an end-user, I want to have a clear indication of the selected (active) node, so that I have a better understanding of the information I'm looking at on the rest of my screen.

  • Story 6: As an end-user, I want to have a clear indication if some/all/none of the child nodes of a given node are selected, so that I have a clear understanding of the current selection of nodes.
  • Story 7: As an end-user, I want to select a single node, so that I navigate to the content it offers.
  • Story 8: As an end-user, I want to select multiple nodes, so that I can perform an operation on all of them at once.

  • Story 9: As an end-user, I want to have a cascading selection of a parent node implicitly selecting all of its children, grandchildren etc., so that I can perform an operation on all of them at once.

  • Story 10: As an end-user, I want to be able to quickly expand/collapse/select a node with mouse and keyboard, so that I have a variety of convenient ways to interact with the hierarchy.
  • Story 11: As an end-user, I want to change a node's parent by dragging it to another one, so that I can reorganize the hierarchy.

  • Story 12: As an end-user, I want to move a node by dragging it above/below a sibling one, so that I can reorder nodes at the same level of the hierarchy.
  • Story 13: As an end-user, I want to have a clear visual indication when dragging a node, so that I can have the right expectancy of where a node would be placed upon dropping it.

  • Story 14: As an end-user, I want to have a clear visual indication when a node is loading its information/children, so that I have expectancy in scenarios with remote data/load on demand.

Developer Stories

The tree should allow me, as a developer, to visually represent the relationship between nodes in my data and use it to provide means for my users to navigate and edit it.

Developer Stories

  • Story 1: As a developer, I want to be able to easily create a tree view declaring the node hierarchy.
  • Story 2: As a developer, I want to have full control over a node's content, as well as its child nodes (declarative approach).
  • Story 3: As a developer, I want to have an easy way to find a node inside of the control with out-of-the-box API.
  • Story 4: As a developer, I want to expand/collapse one or more nodes programmatically.
  • Story 5: As a developer, I want to enable/disable the selection of a single node.
  • Story 6: As a developer, I want to enable/disable the selection of multiple nodes.
  • Story 7: As a developer, I want to enable/disable cascading selection of nodes so that selecting a node, selects all nodes in the tree below it as well and the state of each node reflects the cumulative one of its children.
  • Story 8: As a developer, I want to set a node's selection state programmatically.
  • Story 9: As a developer, I want to set a node's selection state programmatically, even when selection through user interaction is disabled.
  • Story 10: As a developer, I want to be able to perform custom handling on user interaction - node selection, expansion/collapsing.
  • Story 11: As a developer, I want to be able to control the animation when nodes are expanded/collapsed.
  • Story 12: As a developer, I expect that manipulating the data source would update the visualized tree accordingly.
  • Story 13: As a developer, I want to be able to load data on demand to expedite initial load times.
  • Story 14: As a developer, I want to be able to ensure accessibility e.g. via proper aria roles in different cases such as node having a link.
  • Story 15: As a developer, I want to be able to mark nodes as disabled, so they are ignore in user interaction.
  • Story 16: As a developer, I want to mark a node as the tree's active node, styling it in a pre-defined way and marking it as a point of interest to the users.
  • Story 17: As a developer, I want to be able to distinguish when the active node changes through user interaction.
  • Story 18: As a developer, I want to be able to bind a node's expansion state to a data model and ensure consistency between the two.
  • Story 19: As a developer, I want to be able to bind a node's selection state to a data model and ensure consistency between the two.
  • Story 20: As a developer, I want to be able to template the expand/collapse indicators for the tree.
  • Story 21: As a developer, I want to be able to specify how many expanded sibling nodes there can be (singleBranchExpand input).
  • Story 22: As a developer, I want to be able to specify if nodes could be expanded/collapsed when clicking over them (toggleNodeOnClick input).

Describe behavior, design, look and feel of the implemented feature. Always include visual mock-up

3.1. End-User Experience

The IgxTreeComponent should support the three display densities available for other components - 'comfortable', 'cosy' and 'compact'. They come with distinct node heights and padding.

** All use cases and variants above are also available for hand-off

3.2. Developer Experience

Simple tree iterating data:

Developers are able to declare the tree and its nodes by specifying the node hierarchy and iterating through a data set:

<!-- Standard example -->
<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>

Simple tree w/ links

When a node should render a link, add igxTreeNodeLink to the a tag. This will make sure 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>

Two-way data binding node states

Nodes can be bound to a data model so that their expanded and selected states are reflected in the data.

<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>

Tree w/ hardcoded nodes

To render a tree you do not necessarily need a data set - developers can create individual nodes w/o binding them to data:

<!-- Simple example with hardcoded nodes -->
<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 [expanded]="false" [selected]="false">
		I am a parent node 3
		<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 [expanded]="false" [selected]="false" [disabled]="true">
		This area is under construction.
	</igx-tree-node>
</igx-tree>

Finding nodes

When finding nodes, you can pass a custom comparer function in order to find 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: (nodeData: any, node: IgxTreeNodeComponent) => boolean =
      (data: any, node: IgxTreeNodeComponent) => node.data.valueKey === data;
    const matchNodes: IgxTreeNode<{ [key: string]: any, valueKey: string }>[] = this.tree.findNodes(valueKey, comparer);
  }
}

3.3. Globalization/Localization

Describe any special localization requirements such as the number of localizable strings, regional formats

Resource stings for the following:

  1. Default expand/collapse icon template label when collapsed - ITreeResourceStrings.igx_expand (Default (EN): "Expand")
  2. Default expand/collapse icon template label when expanded - ITreeResourceStrings.igx_collapse (Default (EN): "Collapse")

3.4. Keyboard Navigation

The keyboard can be used to navigate through all nodes in the tree. The control distinguishes two states - focused and active. The focused node is where all events are fired and from where navigation will begin/continue. Focused nodes are marked with a distinct style. The active node, in most cases, is the last node on which user interaction took place. Active nodes also have a distinct style. Active nodes can be used to better accent a node in that tree that indicates the app's current state (e.g. a current route in the app when using a tree as a navigation component).

In most cases, moving the focused node also moves the active node.

When navigating to nodes that are outside of view, if the tree (igx-tree tag) has a scrollbar, scrolls the focused node into view. When finishing state transition animations (expand/collapse), if the target node is outside of view AND if the tree (igx-tree tag) has a scrollbar, scrolls the focused node into view. When initializing the tree and a node is marked as active, if that node is outside of view AND if the tree (igx-tree tag) has a scrollbar, scrolls the activated node into view.

FIRST and LAST node refers to the respective visible node WITHOUT expanding/collapsing any existing node.

Disabled nodes are not counted as visible nodes for the purpose of keyboard navigation.

Keys Description Activates Node
ARROW DOWN Moves to the next visible node. Does nothing if on the LAST node. true
CTRL + ARROW DOWN Performs the same as ARROW DOWN. false
ARROW UP Moves to the previous visible node. Does nothing if on the FIRST node. true
CTRL + ARROW UP Performs the same as ARROW UP. false
TAB Navigate to the next focusable element on the page, outside of the tree.* false
SHIFT + TAB Navigate to the previous focusable element on the page, outside of the tree.* false
HOME Navigates to the FIRST node. true
END Navigates to the LAST node. true
ARROW RIGHT On an expanded parent node, navigates to the first child of the node. If on a collapsed parent node, expands it. true
ARROW LEFT On an expanded parent node, collapses it. If on a child node, moves to its parent node. true
SPACE Toggles selection of the current node. Marks the node as active. true
* Expand the node and all sibling nodes on the same level w/ children true
CLICK Focuses the node true

When selection is enabled, end-user selection of nodes is only allowed through the displayed checkbox. Since both selection types allow multiple selection, the following mouse + keyboard interaction is available:

Combination Description Activates Node
SHIFT + CLICK / SPACE when multiple selection is enabled, toggles selection of all nodes between the active one and the one clicked while holding SHIFT. true

IgxTreeComponent

Accessors

Get

Name Description Type
rootNodes Returns all of the tree's nodes that are on root level IgxTreeNodeComponent[]

Properties

Name Description Type
selection The selection state of the tree "None" | "BiState" | "Cascading"
animationSettings The setting for the animation when opening / closing a node { openAnimation: AnimationMetadata, closeAnimation: AnimationMetadata }
singleBranchExpand Whether a single or multiple of a parent's child nodes can be expanded. Default is false boolean
toggleNodeOnClick Whether clicking over nodes will change their expanded state or not. Default is false boolean
expandIndicator Get\Set a reference to a custom template that should be used for rendering the expand/collapse indicators of nodes. TemplateRef<any>
displayDensity Get\Set the display density of the tree. Affects all child nodes DisplayDensity

Methods

Name Description Parameters Returns
findNodes Returns an array of nodes which match the specified data. [data] input should be specified in order to find nodes. A custom comparer function can be specified for custom search (e.g. by a specific value key). Returns null if no nodes match data: T|, comparer?: (data: T, node: IgxTreeNodeComponent<T>) => boolean IgxTreeNodeComponent<T>[] | null
deselectAll Deselects all nodes. If a nodes array is passed, deselects only the specified nodes. Does not emit nodeSelection event. nodes?: IgxTreeNodeComponent[] void
collapseAll Collapses the specified nodes. If no nodes passed, collapses all parent nodes. nodes?: IgxTreeNodeComponent[] void
expandAll Sets the specified nodes as expanded. If no nodes passed, expands all parent nodes. nodes?: IgxTreeNodeComponent[] void

Events

Name Description Cancelable Arguments
nodeSelection Emitted when item selection is changing, before the selection completes true { owner: IgxTreeComponent, newSelection: IgxTreeNodeComponent<any>[], oldSelection: IgxTreeNodeComponent<any>[], added: IgxTreeNodeComponent<any>[], removed: IgxTreeNodeComponent<any>[], cancel: true }
nodeCollapsed Emitted when node collapsing animation finishes and node is collapsed. false { node: IgxTreeNodeComponent<any>, owner: IgxTreeComponent }
nodeCollapsing Emitted when node collapsing animation starts, when node.expanded is set to transition from true to false. true { node: IgxTreeNodeComponent<any>, owner: IgxTreeComponent, cancel: boolean }
nodeExpanded Emitted when node expanding animation finishes and node is expanded. false { node: IgxTreeNodeComponent<any>, owner: IgxTreeComponent }
nodeExpanding Emitted when node expanding animation starts, when node.expanded is set to transition from false to true. true node: IgxTreeNodeComponent<any>, owner: IgxTreeComponent, cancel: boolean }
activeNodeChanged Emitted when the tree's active node changes false IgxTreeNodeComponent<any>
onDensityChanged Emitted when the display density of the tree is changed false { oldDensity: DisplayDensity, newDensity: DisplayDensity }

IgxTreeNodeComponent

Accessors

Get

Name Description Type
parentNode The parent node of the current node (if any) IgxTreeNodeComponent<any>
path The full path to the node, starting from the top-most ancestor IgxTreeNodeComponent<any>[]
level The "depth" of the node. If root node - 0, if a child of parent - parent.level + 1 number
tree A reference to the tree the node is a part of IgxTreecomponent
children A collection of child nodes. null if node does not have children IgxTreeNodeComponent<any>[] | null

Properties

Name Description Type
disabled Get/Set whether the node is disabled. Disabled nodes are ignore for user interactions. boolean
expanded The node expansion state. Does not trigger animation. boolean | null
selected The node selection state. boolean
data The data entry that the node is visualizing. Required for searching through nodes. T
active Marks the node as the tree's active node boolean
resourceStrings An accessor for the current resource strings used for the node ITreeResourceStrings
loading Specifies whether the node is loading data. Loading nodes do not render children. To be used for load-on-demand scenarios boolean

Methods

Name Description Parameters Returns
expand Expands the node, triggering animations None void
collapse Collapses the node, triggering animations None void
toggle Toggles node expansion state, triggering animations None void

Events

Name Description Cancelable Parameters
expandedChange Emitted when the node's expanded property changes false boolean
selectedChange Emitted when the node's selected property changes false boolean

Basic

  • Should render tree w/ nodes
  • Should only render nodes inside of tree (no other elements)
  • Should support multiple levels of nesting (igx-tree-node under igx-tree-node)
  • Should calculate nodes' path and level correctly, depending on data hierarchy
  • Should not render collapsed node's children
  • Should not render expand indicator if node has no children
  • Should not render expand indicator if node is loading
  • Should not render children if node is loading
  • Should not render default select indicator if selection mode is 'None'
  • Should render default indicator for expansion properly depending on node state
  • Should render default select marker properly depending on node state
  • Should accept template for expansion indicator
  • Should allow overriding animationSettings that are used for node toggle
  • Should render nodes correctly depending on displayDensity settings
  • Should support searching for node children w/ tree.findNodes(data: any), returning null if no nodes match criteria
  • Should support searching for node children w/ tree.findNodes(data: any, comparer?: () => boolean) w/ custom comparer
  • Should render links inside node w/ igxTreeNodeLink directive

Expand/Collapse

  • Should collapse nodes when user interacts w/ indicator and node.expanded === false
  • Should expand nodes when user interacts w/ indicator and node.expanded === true
  • Should emit ing and ed events when node state is toggled
  • Should collapse all child nodes when collapsing a node
  • Should collapse sibling nodes when singleBranchExpand === true
  • Should expand/collapse nodes when clicking over them if toggleNodeOnClick === true
  • Should collapse nodes w/o animation when node.expanded is set to false
  • Should expand nodes w/o animation when node.expanded is set to true
  • Should expand nodes w/ animation when node.expand() is called
  • Should collapse nodes w/ animation when node.collapse() is called
  • Should toggle node state w/ animation when node.toggle() is called
  • Should emit node's expandedChange when node.expanded changes
  • Should support two-way binding for node.expanded

Selection

  • Should be able to change selection type to all 3 options ('None' (default), 'BiState', 'Cascading')
  • Should deselect all selected nodes w/ tree.deselectNodes()
  • Should deselect only specified nodes w/ tree.deselectNodes(node: IgxTreeNodeComponent<any>[])

None

  • Should allow setting nodes as selected through API when tree.selection === 'None'
  • Should not render indicators when tree.selection === 'None'

BiState

  • Should select/deselect node by click on checkbox
  • Should emit nodeSelection event w/ correct args when a node is selected / deselected
  • Should support multiple selection (e.g. newly selected nodes do not empty selected collection)
  • Should emit node's selectedChange event when node.selected changes
  • Should support two-way binding for node.selected
  • Selecting a node should select its children
  • Selecting all children of a parent should mark the parent as selected. All direct and non-direct parents should be affected correctly.
  • Deselecting all children of a parent should mark the parent as deselected. All direct and non-direct parents should be affected correctly.
  • Selecting a single child should mark the parent as indeterminate. All direct and non-direct parent should be affected correctly.
  • Selecting the last non-selected child should mark the parent as selected and NOT indeterminate. All direct and non-direct parent should be affected correctly.
  • Set nested child, that has its own children, as initially selected. Verify that direct and indirect parents have correct state.
  • Partially selected parents should have the default indicator render as indeterminate
Tri-state Navigation
  • When selecting range of records using Shift + click key selection of parent should select all its children even if they are not in the selected range.
  • In case that that there are already selected nodes in the tree, click on parent node , that is not selected, should select only the newly clicked node and its children and deselect the rest.
  • In case that that there are already selected nodes in the tree, click on parent node that is not selected should add the node and its children to the selected rows collection even if child nodes are not in the selected range.

Basic

  • Should focus and activate the first node on Home key press
  • Should focus and activate the last visible node on End key press
  • Should not navigate when node has no parent and node is collapsed on Arrow Left key press
  • Should navigate to parent node of a node w/ expanded === true on Arrow Left key press, moving focus and active
  • Should collapsed expanded nodes on Arrow Left key press
  • Should not navigate when node has no children on Arrow Right key press
  • Should navigate to first child of an expanded on Arrow Right key press, moving focus and active
  • Should expand collapsed node w/ children on Arrow Right key press
  • Should focus and activate the next visible node on Arrow Down key press
  • Should only focus the next visible node on Arrow Down + Ctrl key press
  • Should focus and activate the previous visible node on Arrow Up key press
  • Should only focus the previous visible node on Arrow Up + Ctrl key press
  • Should expand all sibling nodes of the focused node on asterisk (*) key press
  • Should active the focused node on Enter key press
  • Should not prevent event's default behavior on Enter key press
  • Should perform nothing when tree.selection === 'None' on Space key press
  • Should select node when tree.selection !== 'None' on Space key press, moving active
  • Should select node range when tree.selection !== 'None' on Space + Shift keys press, moving active
  • Should emit tree.activeNodeChange when the active node changes
  • Should scroll to active node if tree has scrollbar and node is out of view
  • Should trigger events on links w/ igxTreeNodeLink directive instead of parent

Disabled node tests

  • Should render disabled nodes as not reachable for tab navigation (tabIndex should -1)
  • Should not count disabled nodes as traversable nodes for keyboard navigation purposes
  • If a node is expanded and all its children are disabled the focus and activation should not be moved from the node on Arrow Right key press
  • If a node is expanded and has enabled children the focus and activation should be moved to the first enabled child on Arrow Right key press
  • Pressing Arrow Up/Down should move the focus and activation to the previous/next enabled and visible node (if there is any) (skipping disabled)
  • Pressing Asterisk on focused node should expand only the enabled and expandable nodes in the same group

Animation tests

  • Should count children of collapsing nodes, transitioning from expanded === true to false as non-traversable
  • Should count children of expanding nodes, transitioning from expanded === false to true as traversable
  • Should scroll active node into view when tree.displayDensity changes, tree has scroll and node is out of view as result of change
  • Should scroll container to active node if node state toggle animation pushes node out of view and tree has scroll

Aria

See aria-support

  • Should render links in nodes
  • Should dispatch events on links w/ igxTreeNodeLink when navigating w/ keyboard
  • Should assign proper aria attributes on node when node does not have igxTreeNodeLink children
  • Should assign proper aria attributes on node when node has igxTreeNodeLink children
  • Should assign proper aria attributes on node when selection is enabled and node is selected
  • Should assign proper aria label on node's expansion indicator depending on node's expansion state
  • Should assign proper aria attributes if igxTreeNodeLink children are projected inside node's ng-content via *ngTemplateOutlet

See navigation

General

  • Check if tree is rendered correctly
  • Create nodes with igxTreeNodeLink directive. Check if events are fired on node's link
  • Create nodes with igxTreeNodeLink directive via ng-template, passing a parent node. Check if events are fired on node's link
  • Assign custom animationSettings to tree. Check if tree nodes use assigned animation when expanding / collapsing
  • Assign animationSettings w/ long ( > 2000ms) animation durations. Check if keyboard navigation on expanding / collapsing nodes respects keyboard restrictions for keyboard navigation
  • Create a node bound to async data. Trigger a request, set node's loading to true. Check if indicator renders.
  • Set tree's selection to Cascading. Check if selecting single/multiple nodes cover selection scenario from selection
  • Create tree w/ 3+ levels of depth, 5+ children for each node, each level. Check tree performance.

Tree Aria example

An igx-tree will have role="tree". aria-labelledby should be manually added if there is a label/ heading associated w/ the tree.

An igx-tree-node's child will be held in a container w/ role="group".

An igx-tree-node will have role="treeitem" if there is no link w/ igxTreeNodeLink directive specified in it. If there is such a link (a tag), the role="treeitem" will go on the link (as it is the interactable component of the node).

A node's expanded state will be properly reflected in the node's aria-expanded attribute.

Recursive template nodes

The igx-tree does not support recursively creating the igx-tree-nodes via template. This is a limitation in place because of a bug in the Angular framework. 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 igx-tree-grid

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. Link to issue

Tab navigation in FireFox

Tabbing into the tree w/ keyboard navigation, when the tree has a scrollbar, will first focus the igx-tree-node element. This is the default behavior in FireFox. It's reproducible in this simple example StackBlitz. This can be resolve by simply putting an explicit tabIndex = -1 on the tree, but since it's default browser behavior, we omit it in initial implementation.

Nodes w/ Link and ng-template

When creating an anchor (<a>) child w/ our tab stop directive ([igxTreeNodeLink]) via ng-template, the node would not normally recognize it's children. As a workaround, a ref to the parent node needs to be passed (<a [igxTreeNodeLink]="parentNode"):

<igx-tree>
    <igx-tree-node #nodeRef *ngFor="let node of data" [data]="node">
         <!-- template outlet in node content -->
         <ng-template *ngTemplateOutlet="nodeTemplate; context: { $implicit: node, node: nodeRef }">
         </ng-template>
         <igx-tree-node #nodeRef *ngFor="let childNode of node.children" [data]="childNode">
             <!-- template outlet in node content -->
             <ng-template *ngTemplateOutlet="nodeTemplate; context: { $implicit: childNode, node: nodeRef }">
             </ng-template>
             ....
         </igx-tree-node>
    </igx-tree-node>
    <!-- template is defined in the tree body -->
    <ng-template #nodeTemplate let-data let-parent="nodeRef">
         <!-- explicitly pass a reference to the parent node via `[igxTreeNodeLink]="parent"` -->
          <a [igxTreeNodeLink]="parent" [href]="data.href">{{ data.label }}</a>
    </ng-template>
</igx-tree>

IgxTree Issue

Clone this wiki locally