-
Notifications
You must be signed in to change notification settings - Fork 160
Tree Specification
-
3.3 Globalization/Localization
3.5 API
-
4.1. Automation
4.2. Manual tests
Team Name
Developer Name
Stefan Ivanov
- Peer Developer Name | Date:
- Stefan Ivanov | Date: 15 Feb 2021
- Product Owner Name | Date:
- Platform Architect Name | Date:
Version | User | Date | Notes |
---|---|---|---|
1 | Viktor Slavov, Stefan Ivanov | Feb 15, 2021 | Initial Draft |
2 | Viktor Slavov | Feb 18, 2021 | Fix Link Formatting |
The IgxTreeComponent
is a component allowing a developer user to show a set of nodes in a hierarchical fashion allowing his end-users to use them for easily navigating structured information e.g. a site map of a website or documentation topics.
The igxTreeComponent
should primarily be used as a navigational component when visualizing a nested data structure.
Must-have before we can consider the feature a sprint candidate
...
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.
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 OOB 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 be able to perform custom handling on user interaction - node selection, expansion/collapsing.
- Story 10: As a developer, I want to be able to control the animation when nodes are expanded/collapsed.
- Story 11: As a developer, I expect that manipulating the data source would update the visualized tree accordingly.
- Story 12: As a developer, I want to be able to load data on demand to expedite initial load times.
- Story 13: 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.
Describe behavior, design, look and feel of the implemented feature. Always include visual mock-up
The Tree component 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
<!-- Standard example -->
<igx-tree>
<igx-tree-node *ngFor="let nodes 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>
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 nodes 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>
<!-- 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-url-node [url]="https://google.com">
I am a child node of the child
</igx-tree-url-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>
When finding nodes, you can pass a custom comparer function in order to find the data
<igx-tree>
<igx-tree-node *ngFor="let nodes 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) => nodeData.valueKey === data;
this.tree.findData(valueKey, comparer);
}
}
3.3. Globalization/Localization
Describe any special localization requirements such as the number of localizable strings, regional formats
The keyboard can be used to navigate through all nodes in the tree. FIRST and LAST node refers to the respective visible node WITHOUT expanding/collapsing any existing node
Keys. | Description |
---|---|
ARROW DOWN | moves to the next visible node. Does nothing if on the LAST node. |
ARROW UP | moves to the previous visible node. Does nothing if one the FIRST node. |
TAB | moves to the next visible node. If on the LAST node, moves to the next element w/ tabIndex outside of the tree. |
SHIFT + TAB | moves to the previous visible node. If on the LAST node, moves to the next element w/ tabIndex outside of the tree. |
HOME | navigates to the FIRST node. |
END | navigates to the LAST node. |
ARROW RIGHT | on an expanded parent node, navigates to the first child of the node. If on a leaf node, moves to the next visible node. If on a collapsed parent node, expands it. |
ARROW LEFT | on an expanded parent node, collapses it. If on a child node, moves to its parent node. |
SPACE | toggles selection of the current node. |
SHIFT + CLICK | when multiple selection is enabled, toggles selection of all nodes between the active one and the one clicked while holding SHIFT. |
CTRL + CLICK | when multiple selection is enabled, add the clicked node to the selected nodes collection or remove it if already selected. |
Get
Name | Description | Type |
---|---|---|
id | The unique id of the tree node. Used for state management and selection. | string |
parentNode | The parent node of the current node (if any) | IgxTreeNodeComponent |
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 | IgxTree |
children | A collection of child nodes. null if node does not have children |
any[] | null
|
role | The role attribute assigned to the rendered igx-tree-node DOM element |
string |
Name | Description | Type |
---|---|---|
expanded | If the node is expanded |
boolean | null
|
selected | If the node is selected | boolean |
data | The data entry that the node is visualizing. Required for searching through nodes | any |
Get
Name | Description | Type |
---|---|---|
id | The unique id of tree (not bound to the id html attribute ) |
string |
Name | Description | Type |
---|---|---|
selection | The selection state of the tree | "None" |
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 |
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
|
selectAll | Sets the specified nodes as selected, clearing the previous selection. If no nodes passed, selects all nodes | nodes?: IgxTreeNodeComponent[] |
void |
expandAll | Sets the specified nodes as expanded. If no nodes passed, expands all parent nodes | nodes?: IgxTreeNodeComponent[] |
void |
Name | Description | Cancelable | Parameters |
---|---|---|---|
selection | Emitted when item selection is changing, before the selection completes | true | owner: IgxTreeComponent, selectedNodes: IgxTreeComponent[] |
nodeOpening | Emitted before the a node is opened. | true | node: IgxTreeNodeComponent, owner: IgxTreeComponent, cancel: boolean |
nodeOpened | Emitted after the a node is opened. | false | node: IgxTreeNodeComponent, owner: IgxTreeComponent |
nodeClosing | Emitted before the a node is closed. | true | node: IgxTreeNodeComponent, owner: IgxTreeComponent, cancel: boolean |
nodeClosed | Emitted after the a node is closed. | false | node: IgxTreeNodeComponent, owner: IgxTreeComponent |
nodeDragStart | Emitted when a node drag is stared | true | IDragStartEventArgs & { node: IgxTreeNodeComponent } |
nodeDragMove | Emitted when the cursor moves while a node dragged | true | IDragMoveEventArgs & { node: IgxTreeNodeComponent } |
nodeDrop | Emitted when a node is dropped | false | IDragDropEventArgs & { node: IgxTreeNodeComponent } |
- 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 not render collapsed node's children
- Should not render expand indicator if node has no children
- 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 accept template for select marker
- Should collapse nodes
- Should expand nodes
- Should collapse all child nodes when collapsing a node
- Should collapse sibling nodes when
singleBranchExpand === true
- Should be able to change selection type to all 3 options ('None' (default), 'BiState', 'Cascading')
- Should select nodes
- Should deselect nodes
- Should be able to set the node selection and clear the previous selection (
setSelection
)
- Partially selected parents should have the default indicator render as
indeterminate
- Selecting a node should select its children
- Selecting a child should mark its parent node as partially selected
- Selecting the last non-selected child should mark the parent as selected
- Deselecting a selected child under a selected parent should mark the parent as partially selected
See navigation
See aria-support
- Rendered tree and nodes have expected aria attributes
- Passing a link child in a node w/
igxTreeNodeLink
directive should change aria roles of the the node
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.
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