TreeTree is used to display hierarchical data.

Tree - 图1

Documentation

Import

  1. import {TreeModule} from 'primeng/tree';
  2. import {TreeNode} from 'primeng/api';
  3.  

Getting Started

Tree component requires an array of TreeNode objects as its value. Let's begin with the TreeNode api. Note that all of the properties are optional.

NameTypeDefaultDescription
labelstringnullLabel of the node.
dataanynullData represented by the node.
iconstringnullIcon of the node to display next to content.
expandedIconstringnullIcon to use in expanded state.
collapsedIconstringnullIcon to use in collapsed state.
childrenTreeNode[]nullAn array of treenodes as children.
leafbooleannullSpecifies if the node has children. Used in lazy loading.
stylestringnullInline style of the node.
styleClassstringnullStyle class of the node.
expandedbooleannullWhether the node is in an expanded or collapsed state.
typestringnullType of the node to match ng-template type.
parentTreeNodenullParent of the node.
draggablebooleannullWhether to disable dragging for a particular node even if draggableNodes is enabled.
droppablebooleannullWhether to disable dropping for a particular node even if droppableNodes is enabled.
selectablebooleannullUsed to disable selection of a particular node.
keystringnullUnique key of the node.(more)
emptyMessagestringNo records found.Text to display when there is no data.

Most of the time, nodes will be loaded from a remote datasoure, here is an example NodeService that fetches the data from a json file.

  1. @Injectable()
  2. export class NodeService {
  3. constructor(private http: Http) {}
  4. getFiles() {
  5. return this.http.get('showcase/resources/data/files.json')
  6. .toPromise()
  7. .then(res => <TreeNode[]> res.json().data);
  8. }
  9. }
  10.  

The files.json file consists of sample data. In a real application, this should be a dynamic response generated from the remote call.

  1. {
  2. "data":
  3. [
  4. {
  5. "label": "Documents",
  6. "data": "Documents Folder",
  7. "expandedIcon": "fa fa-folder-open",
  8. "collapsedIcon": "fa fa-folder",
  9. "children": [{
  10. "label": "Work",
  11. "data": "Work Folder",
  12. "expandedIcon": "fa fa-folder-open",
  13. "collapsedIcon": "fa fa-folder",
  14. "children": [{"label": "Expenses.doc", "icon": "fa fa-file-word-o", "data": "Expenses Document"}, {"label": "Resume.doc", "icon": "fa fa-file-word-o", "data": "Resume Document"}]
  15. },
  16. {
  17. "label": "Home",
  18. "data": "Home Folder",
  19. "expandedIcon": "fa fa-folder-open",
  20. "collapsedIcon": "fa fa-folder",
  21. "children": [{"label": "Invoices.txt", "icon": "fa fa-file-word-o", "data": "Invoices for this month"}]
  22. }]
  23. },
  24. {
  25. "label": "Pictures",
  26. "data": "Pictures Folder",
  27. "expandedIcon": "fa fa-folder-open",
  28. "collapsedIcon": "fa fa-folder",
  29. "children": [
  30. {"label": "barcelona.jpg", "icon": "fa fa-file-image-o", "data": "Barcelona Photo"},
  31. {"label": "logo.jpg", "icon": "fa fa-file-image-o", "data": "PrimeFaces Logo"},
  32. {"label": "primeui.png", "icon": "fa fa-file-image-o", "data": "PrimeUI Logo"}]
  33. },
  34. {
  35. "label": "Movies",
  36. "data": "Movies Folder",
  37. "expandedIcon": "fa fa-folder-open",
  38. "collapsedIcon": "fa fa-folder",
  39. "children": [{
  40. "label": "Al Pacino",
  41. "data": "Pacino Movies",
  42. "children": [{"label": "Scarface", "icon": "fa fa-file-video-o", "data": "Scarface Movie"}, {"label": "Serpico", "icon": "fa fa-file-video-o", "data": "Serpico Movie"}]
  43. },
  44. {
  45. "label": "Robert De Niro",
  46. "data": "De Niro Movies",
  47. "children": [{"label": "Goodfellas", "icon": "fa fa-file-video-o", "data": "Goodfellas Movie"}, {"label": "Untouchables", "icon": "fa fa-file-video-o", "data": "Untouchables Movie"}]
  48. }]
  49. }
  50. ]
  51. }
  52.  

The component that uses this service makes a call to getFiles() and assigns them back to files property that is bound to the tree.

  1. export class TreeDemoComponent implements OnInit {
  2. files: TreeNode[];
  3. constructor(private nodeService: NodeService) {}
  4. ngOnInit() {
  5. this.nodeService.getFiles().then(files => this.files = files);
  6. }
  7. }
  8.  
  1. <p-tree [value]="files"></p-tree>
  2.  

Selection

Tree supports 3 selection methods, single, multiple and checkbox. Selection is enabled by setting selectionMode property and providing a single TreeNode or an array of TreeNodes to reference the selections depending on the selection mode.

  1. export class TreeDemoComponent implements OnInit {
  2. files: TreeNode[];
  3. selectedFile: TreeNode;
  4. constructor(private nodeService: NodeService) {}
  5. ngOnInit() {
  6. this.nodeService.getFiles().then(files => this.files = files);
  7. }
  8. }
  9.  
  1. <p-tree [value]="files" selectionMode="single" [(selection)]="selectedFile"></p-tree>
  2.  

In multiple mode or checkbox mode, selection property should be an array. In multiple mode, items can either be selected using metaKey or toggled individually depending on the value of metaKeySelection property value which is true by default. On touch enabled devices metaKeySelection is turned off automatically. In checkbox mode, when inititing a tree with preselections, also set partialSelected property on node so that minus icon can be displayed when necessary.

  1. export class TreeDemoComponent implements OnInit {
  2. files: TreeNode[];
  3. selectedFiles: TreeNode[];
  4. constructor(private nodeService: NodeService) {}
  5. ngOnInit() {
  6. this.nodeService.getFiles().then(files => this.files = files);
  7. }
  8. }
  9.  
  1. <p-tree [value]="files" selectionMode="single" [(selection)]="selectedFiles"></p-tree>
  2.  

In checkbox mode, selections propagate up and down, if you prefer not to do so, propagation can be turned off by propagateSelectionDown and propagateSelectionUp properties.

  1. <p-tree [value]="files" selectionMode="checkbox" [(selection)]="selectedFiles"
  2. [propagateSelectionUp]="false" [propagateSelectionDown]="false"></p-tree>
  3.  

Tree provides onNodeSelect and onNodeUnselect options as callbacks for selection feature.

  1. <p-tree [value]="files" selectionMode="single" [(selection)]="selectedFiles" (onNodeSelect)="nodeSelect($event)"></p-tree>
  2.  
  1. export class TreeDemoComponent implements OnInit {
  2. files: TreeNode[];
  3. selectedFiles: TreeNode[];
  4. constructor(private nodeService: NodeService) {}
  5. ngOnInit() {
  6. this.nodeService.getFiles().then(files => this.files = files);
  7. }
  8. nodeSelect(event) {
  9. //event.node = selected node
  10. }
  11. }
  12.  

Selection of a particular node can be disabled by setting the selectable property of the node to false.

Icons

Icon of a treenode is defined using the icon property, if you need an icon depending on the expand or collapse state, use expandedIcon and collapsedIcon instead.

Templating

By default label of a treenode is displayed inside a tree node, in case you need to place custom content define a pTemplate that gets the treenode as an implicit variable. Example below places an input field to create editable treenodes.

  1. <p-tree [value]="files">
  2. <ng-template let-node pTemplate="default">
  3. <input [(ngModel)]="node.label" type="text" style="width:100%">
  4. </ng-template>
  5. </p-tree>
  6.  

Multiple templates are supported by matching the type property of the TreeNode with the type of pTemplate. If a node has no type, then default ng-template is used.

  1. <p-tree [value]="files">
  2. <ng-template let-node pTemplate="picture">
  3. <img [attrs.src]="picture.path">
  4. </ng-template>
  5. <ng-template let-node pTemplate="default">
  6. <input [(ngModel)]="node.label" type="text" style="width:100%">
  7. </ng-template>
  8. </p-tree>
  9.  

Filtering

Filtering is enabled by setting the filter property to true, by default label property of a node is used to compare against the value in the text field, in order to customize which field(s) should be used during search define filterBy property.

In addition filterMode specifies the filtering strategy. In lenient mode when the query matches a node, children of the node are not searched further as all descendants of the node are included. On the other hand, in strict mode when the query matches a node, filtering continues on all descendants.

  1. <p-tree [value]="filesTree11" [filter]="true"></p-tree>
  2. <p-tree [value]="filesTree12" [filter]="true" filterMode="strict"></p-tree>
  3.  

ContextMenu

Tree has exclusive integration with context menu created by binding a menu instance to the tree.

  1. <p-tree [value]="files" selectionMode="single" [(selection)]="selectedFile2" [contextMenu]="cm"></p-tree>
  2. <p-contextMenu #cm [model]="items"></p-contextMenu>
  3.  

Lazy Loading

Lazy loading is handy to deal with large datasets. Instead of loading the whole tree, nodes can be loaded at onNodeExpand event. Important part of implementing lazy loading is defining leaf property of a node as false, this will instruct tree to display an arrow icon to indicate there are children of this node although they are not loaded yet. When the lazy node is expanded, onNodeExpand is called and a remote call can be made to add the children to the expanded node.

  1. <p-tree [value]="files" (onNodeExpand)="loadNode($event)"></p-tree>
  2.  
  1. export class TreeDemoComponent implements OnInit {
  2. files: TreeNode[];
  3. selectedFiles: TreeNode[];
  4. constructor(private nodeService: NodeService) {}
  5. ngOnInit() {
  6. //initial nodes
  7. this.nodeService.getFiles().then(files => this.files = files);
  8. }
  9. loadNode(event) {
  10. if(event.node) {
  11. //in a real application, make a call to a remote url to load children of the current node and add the new nodes as children
  12. this.nodeService.getLazyFiles().then(nodes => event.node.children = nodes);
  13. }
  14. }
  15. }
  16.  

Assume at ngOnInit tree is initialized with a data like below that has nodes having no actual children but leaf property is set false.

  1. {
  2. "data":
  3. [
  4. {
  5. "label": "Lazy Node 0",
  6. "data": "Node 0",
  7. "expandedIcon": "fa fa-folder-open",
  8. "collapsedIcon": "fa fa-folder",
  9. "leaf": false
  10. },
  11. {
  12. "label": "Lazy Node 1",
  13. "data": "Node 1",
  14. "expandedIcon": "fa fa-folder-open",
  15. "collapsedIcon": "fa fa-folder",
  16. "leaf": false
  17. },
  18. {
  19. "label": "Lazy Node 1",
  20. "data": "Node 2",
  21. "expandedIcon": "fa fa-folder-open",
  22. "collapsedIcon": "fa fa-folder",
  23. "leaf": false
  24. }
  25. ]
  26. }
  27.  

Drag and Drop

Nodes can be reordered within a tree and also can be transferred between multiple trees. To enable dragging from a tree set draggableNodes to true and to allow dropping enable droppableNodes property. In addition, import TreeDragDropService and configure it as a provider at your component or module.

  1. import {TreeDragDropService} from 'primeng/api';
  2.  
  1. <p-tree [value]="files" draggableNodes="true" droppableNodes="true"></p-tree>
  2.  

Multiple trees can be used in a drag drop operation, in order to add constraints like rejecting drags from a certain tree but allow from another use draggableScope and droppableScope properties which can be a string or an array. Following example uses 3 trees where second one only accepts drags from first tree and second one only accepts from second tree whereas first tree accepts drops from 3rd tree.

  1. <p-tree [value]="files" draggableNodes="true" droppableNodes="true" draggableScope="a" droppableScope="c"></p-tree>
  2. <p-tree [value]="files" draggableNodes="true" droppableNodes="true" draggableScope="b" droppableScope="a"></p-tree>
  3. <p-tree [value]="files" draggableNodes="true" droppableNodes="true" draggableScope="c" droppableScope="b"></p-tree>
  4.  

In case, a drop should be accepted based on a condition, enable validateDrop property, define an event handler for onNodeDrop where the passed event and call the accept callback of the event to accept a drop. Simply omitting the call of accept() will reject the drop.

  1. <p-tree [value]="files" draggableNodes="true" droppableNodes="true" [validateDrop]="true" (onNodeDrop)="onDrop($event)"></p-tree>
  2.  
  1. onDrop(event) {
  2. if (condition) {
  3. event.accept();
  4. }
  5. }
  6.  

Loading Status

Tree has a loading property, when enabled a spinner icon is displayed to indicate data load.

An optional loadingIcon property can be passed in case you prefer a different icon.

  1. <p-tree [value]="files" [loading]="loading"></p-tree>
  2.  

Horizontal Orientation

Horizontal mode is the alternative option for orientation.

  1. <p-tree [value]="files" layout="horizontal"></p-tree>
  2.  

Properties

NameTypeDefaultDescription
valuearraynullAn array of treenodes.
selectionModestringnullDefines the selection mode, valid values "single", "multiple", and "checkbox".
selectionanynullA single treenode instance or an array to refer to the selections.
stylestringnullInline style of the component.
styleClassstringnullStyle class of the component.
contextMenuContextMenunullContext menu instance.
layoutstringverticalDefines the orientation of the tree, valid values are 'vertical' and 'horizontal'.
metaKeySelectionbooleantrueDefines how multiple items can be selected, when true metaKey needs to be pressed to select or unselect an item and when set to false selection of each item can be toggled individually. On touch enabled devices, metaKeySelection is turned off automatically.
propagateSelectionUpbooleantrueWhether checkbox selections propagate to ancestor nodes.
propagateSelectionDownbooleantrueWhether checkbox selections propagate to descendant nodes.
loadingbooleanfalseDisplays a loader to indicate data load is in progress.
loadingIconstringfa-circle-o-notchThe icon to show while indicating data load is in progress.
validateDropbooleanfalseWhen enabled, drop can be accepted or rejected based on condition defined at onNodeDrop.
filterbooleanfalseWhen specified, displays an input field to filter the items.
filterBystringlabelWhen filtering is enabled, filterBy decides which field or fields (comma separated) to search against.
filterModestringlenientMode for filtering valid values are "lenient" and "strict". Default is lenient.
filterPlaceholderstringnullPlaceholder text to show when filter input is empty.

Events

NameParametersDescription
onNodeSelectevent.originalEvent: browser event event.node: Selected node instance.Callback to invoke when a node is selected.
onNodeUnselectevent.originalEvent: browser event event.node: Unselected node instance.Callback to invoke when a node is unselected.
onNodeExpandevent.originalEvent: browser event event.node: Expanded node instance.Callback to invoke when a node is expanded.
onNodeCollapseevent.originalEvent: browser event event.node: Collapsed node instance.Callback to invoke when a node is collapsed.
onNodeContextMenuSelectevent.originalEvent: browser event event.node: Selected node instance.Callback to invoke when a node is selected with right click.
onNodeDropevent.originalEvent: browser event event.dragNode: Dragged node instance event.dropNode: Dropped node instance. event.index: Index of the dropped node within siblings.Callback to invoke when a node is dropped.

Styling

Following is the list of structural style classes, for theming classes visit theming page.

NameElement
ui-treeMain container element
ui-tree-horizontalMain container element in horizontal mode
ui-tree-containerContainer of nodes
ui-treenodeA treenode element
ui-treenode-contentContent of a treenode
ui-treenode-togglerToggle icon
ui-treenode-iconIcon of a treenode
ui-treenode-labelLabel of a treenode
ui-treenode-childrenContainer element for node children
ui-treenode-content-selectedContent of a selected node.

Dependencies

None.

Source

View on GitHub

  1. <p-toast [style]="{marginTop: '80px'}"></p-toast>
  2. <h3 class="first">Basic</h3>
  3. <p-tree [value]="filesTree0"></p-tree>
  4. <h3>Loader</h3>
  5. <p-tree [value]="filesTree1" [loading]="loading"></p-tree>
  6. <h3>Single Selection</h3>
  7. <p-tree [value]="filesTree2" selectionMode="single" [(selection)]="selectedFile"
  8. (onNodeSelect)="nodeSelect($event)" (onNodeUnselect)="nodeUnselect($event)"></p-tree>
  9. <div style="margin-top:8px">Selected Node: {selectedFile ? selectedFile.label : 'none'}</div>
  10. <h3>Multiple Selection with Metakey</h3>
  11. <p-tree [value]="filesTree3" selectionMode="multiple" [(selection)]="selectedFiles"
  12. (onNodeSelect)="nodeSelect($event)" (onNodeUnselect)="nodeUnselect($event)"></p-tree>
  13. <div>Selected Nodes: <span *ngFor="let file of selectedFiles">{file.label} </span></div>
  14. <h3>Multiple Selection with Checkbox</h3>
  15. <p-tree [value]="filesTree4" selectionMode="checkbox" [(selection)]="selectedFiles2"></p-tree>
  16. <div>Selected Nodes: <span *ngFor="let file of selectedFiles2">{file.label} </span></div>
  17. <h3>Lazy Loading</h3>
  18. <p-tree [value]="lazyFiles" (onNodeExpand)="nodeExpand($event)" [style]="{'max-height':'200px','overflow':'auto'}"></p-tree>
  19. <h3>Template</h3>
  20. <p-tree [value]="filesTree5">
  21. <ng-template let-node pTemplate="default">
  22. <input [(ngModel)]="node.label" type="text" style="width:100%" class="ui-inputtext">
  23. </ng-template>
  24. </p-tree>
  25. <h3>Context Menu</h3>
  26. <p-tree [value]="filesTree6" selectionMode="single" [(selection)]="selectedFile2" [contextMenu]="cm"></p-tree>
  27. <p-contextMenu #cm [model]="items"></p-contextMenu>
  28. <h3>DragDrop</h3>
  29. <div class="ui-g ui-fluid">
  30. <div class="ui-g-12 ui-md-3">
  31. <h4>Files</h4>
  32. <p-tree [value]="filesTree7" draggableNodes="true" droppableNodes="true" droppableScope="files" draggableScope="server2"></p-tree>
  33. </div>
  34. <div class="ui-g-12 ui-md-1" style="text-align:center">
  35. <i class="fa fa-exchange" style="font-size:36px;margin-top: 28px;"></i>
  36. </div>
  37. <div class="ui-g-12 ui-md-3">
  38. <h4>Server 1</h4>
  39. <p-tree [value]="filesTree8" draggableNodes="true" droppableNodes="true" droppableScope="server1" draggableScope="files"></p-tree>
  40. </div>
  41. <div class="ui-g-12 ui-md-1" style="text-align:center">
  42. <i class="fa fa-exchange" style="font-size:36px;margin-top: 28px;"></i>
  43. </div>
  44. <div class="ui-g-12 ui-md-3">
  45. <h4>Server 2</h4>
  46. <p-tree [value]="filesTree9" draggableNodes="true" droppableNodes="true" droppableScope="server2" draggableScope="server1"></p-tree>
  47. </div>
  48. <div class="ui-g-12 ui-md-1">
  49. </div>
  50. </div>
  51. <h3>Programatic Tree Expansion</h3>
  52. <p-tree #expandingTree [value]="filesTree10"></p-tree>
  53. <div style="margin-top: 8px">
  54. <button pButton type="button" label="Expand all" (click)="expandAll()" style="margin-right: .25em"></button>
  55. <button pButton type="button" label="Collapse all" (click)="collapseAll()"></button>
  56. </div>
  57. <h3>Lenient Filter Mode</h3>
  58. <p-tree [value]="filesTree11" [filter]="true"></p-tree>
  59. <h3>Strict Filter Mode</h3>
  60. <p-tree [value]="filesTree12" [filter]="true" filterMode="strict"></p-tree>
  61. <h3>Horizontal Tree</h3>
  62. <p-tree [value]="filesTree11" layout="horizontal" selectionMode="single" [(selection)]="selectedFile3" ></p-tree>
  63. <div style="margin-top:8px">Selected Node: {selectedFile3 ? selectedFile3.label : 'none'}</div>
  64.  
  1. export class TreeDemo implements OnInit {
  2. @ViewChild('expandingTree')
  3. expandingTree: Tree;
  4. filesTree1: TreeNode[];
  5. filesTree2: TreeNode[];
  6. filesTree3: TreeNode[];
  7. filesTree4: TreeNode[];
  8. filesTree5: TreeNode[];
  9. filesTree6: TreeNode[];
  10. filesTree7: TreeNode[];
  11. filesTree8: TreeNode[];
  12. filesTree9: TreeNode[];
  13. filesTree10: TreeNode[];
  14. filesTree11: TreeNode[];
  15. lazyFiles: TreeNode[];
  16. selectedFile: TreeNode;
  17. selectedFile2: TreeNode;
  18. selectedFile3: TreeNode;
  19. selectedFiles: TreeNode[];
  20. selectedFiles2: TreeNode[];
  21. items: MenuItem[];
  22. loading: boolean;
  23. constructor(private nodeService: NodeService, private messageService: MessageService) { }
  24. ngOnInit() {
  25. this.loading = true;
  26. this.nodeService.getFiles().then(files => this.filesTree0 = files);
  27. setTimeout(() => {
  28. this.nodeService.getFiles().then(files => this.filesTree1 = files);
  29. this.loading = false;
  30. }, 3000);
  31. this.nodeService.getFiles().then(files => this.filesTree2 = files);
  32. this.nodeService.getFiles().then(files => this.filesTree3 = files);
  33. this.nodeService.getFiles().then(files => this.filesTree4 = files);
  34. this.nodeService.getFiles().then(files => this.filesTree5 = files);
  35. this.nodeService.getFiles().then(files => this.filesTree6 = files);
  36. this.nodeService.getFiles().then(files => this.filesTree7 = files);
  37. this.filesTree8 = [
  38. {
  39. label: "Backup",
  40. data: "Backup Folder",
  41. expandedIcon: "fa fa-folder-open",
  42. collapsedIcon: "fa fa-folder"
  43. }
  44. ];
  45. this.filesTree9 = [
  46. {
  47. label: "Storage",
  48. data: "Storage Folder",
  49. expandedIcon: "fa fa-folder-open",
  50. collapsedIcon: "fa fa-folder"
  51. }
  52. ];
  53. this.nodeService.getFiles().then(files => this.filesTree10 = files);
  54. this.nodeService.getFiles().then(files => {
  55. this.filesTree11 = [{
  56. label: 'Root',
  57. children: files
  58. }];
  59. });
  60. this.nodeService.getLazyFiles().then(files => this.lazyFiles = files);
  61. this.items = [
  62. {label: 'View', icon: 'fa fa-search', command: (event) => this.viewFile(this.selectedFile2)},
  63. {label: 'Unselect', icon: 'fa fa-close', command: (event) => this.unselectFile()}
  64. ];
  65. }
  66. nodeSelect(event) {
  67. this.messageService.add({severity: 'info', summary: 'Node Selected', detail: event.node.label});
  68. }
  69. nodeUnselect(event) {
  70. this.messageService.add({severity: 'info', summary: 'Node Unselected', detail: event.node.label});
  71. }
  72. nodeExpandMessage(event) {
  73. this.messageService.add({severity: 'info', summary: 'Node Expanded', detail: event.node.label});
  74. }
  75. nodeExpand(event) {
  76. if(event.node) {
  77. //in a real application, make a call to a remote url to load children of the current node and add the new nodes as children
  78. this.nodeService.getLazyFiles().then(nodes => event.node.children = nodes);
  79. }
  80. }
  81. viewFile(file: TreeNode) {
  82. this.messageService.add({severity: 'info', summary: 'Node Selected with Right Click', detail: file.label});
  83. }
  84. unselectFile() {
  85. this.selectedFile2 = null;
  86. }
  87. expandAll(){
  88. this.filesTree6.forEach( node => {
  89. this.expandRecursive(node, true);
  90. } );
  91. }
  92. collapseAll(){
  93. this.filesTree6.forEach( node => {
  94. this.expandRecursive(node, false);
  95. } );
  96. }
  97. private expandRecursive(node:TreeNode, isExpand:boolean){
  98. node.expanded = isExpand;
  99. if(node.children){
  100. node.children.forEach( childNode => {
  101. this.expandRecursive(childNode, isExpand);
  102. } );
  103. }
  104. }
  105. }
  106.