aboutsummaryrefslogtreecommitdiffstats
path: root/documentation/components/components-tree.asciidoc
blob: b95f8bd2aeb64348d2535fcd78e235cdd61979bf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
---
title: Tree
order: 22
layout: page
---

[[components.tree]]
= [classname]#Tree#

ifdef::web[]
[.sampler]
image:{live-demo-image}[alt="Live Demo", link="http://demo.vaadin.com/sampler/#ui/grids-and-trees/tree"]
endif::web[]

[NOTE]
====
[classname]#Tree# still uses the old data API from Vaadin 7.
====

The [classname]#Tree# component allows a natural way to represent data that has hierarchical relationships.
The user can drill down in the hierarchy by expanding items by clicking on the expand arrow, and likewise collapse items.
[classname]#Tree# is a selection component that allows selecting items.
It also supports drag and drop, so you can drag items to and from a tree, and drop them in the hierarchy.

A typical use of the [classname]#Tree# component is for displaying a hierarchical menu, as illustrated in <<figure.components.tree>>, or for displaying file systems or hierarchical datasets.

[[figure.components.tree]]
.A [classname]#Tree# component as a menu
image::img/tree-example1.png[width=25%, scaledwidth=50%]

The data is managed in a container implementing the [interfacename]#Hierarchical# interface, such as [classname]#HierarchicalContainer# or [classname]#FilesystemContainer#.
You can use [classname]#ContainerHierarchicalWrapper# to add hierarchical capability to any other container. [classname]#Tree# itself implements the interface and delegates operations to the underlying container.

[source, java]
----
// A menu tree
Tree menu = new Tree();

// Couple of childless root items
menu.addItem("Mercury");
menu.setChildrenAllowed("Mercury", false);
menu.addItem("Venus");
menu.setChildrenAllowed("Venus", false);

// An item with hierarchy
menu.addItem("Earth");
menu.addItem("The Moon");
menu.setChildrenAllowed("The Moon", false);
menu.setParent("The Moon", "Earth");
menu.expandItem("Earth"); // Expand programmatically
...
----

The result was shown in <<figure.components.tree>> in a practical situation, with the [classname]`Tree` wrapped inside a [classname]`Panel`.
[classname]`Tree` itself does not have scrollbar, but [classname]`Panel` can be used for the purpose.

The caption of tree items is by default the item ID.
You can define how the item captions are determined with [methodname]#setItemCaptionMode()#, as explained <<components-selection#components.selection.captions, "Selection Component Item Captions">>.

[[components.tree.selection]]
== Handling Selection and Clicks

[classname]#Tree# is a selection component, which are described in  <<components-selection#components.selection, "Selection Components">>.
You can thereby get or set the currently selected item by the value property of the tree, that is, with [methodname]#getValue()# and [methodname]#setValue()#.
When the user selects an item, the tree will receive an [classname]#ValueChangeEvent#, which you can catch with a [classname]#ValueChangeListener#.

[source, Java]
----
// Handle selection changes
menu.addValueChangeListener(event -> { // Java 8
    if (event.getProperty() != null &&
        event.getProperty().getValue() != null) {
        location.setValue("The cat is in " +
            event.getProperty().getValue());
    }
});
----

[classname]#Tree# is selectable by default; you can disallow selection with [methodname]#setSelectable(false)#.

[classname]#Tree# also emits [classname]##ItemClickEvent##s when items are clicked.
This way you can handle item clicks also when selection is not enabled or you want special user interaction specifically on clicks.

[source, Java]
----
tree.addItemClickListener(
  new ItemClickEvent.ItemClickListener() {
    public void itemClick(ItemClickEvent event) {
        // Pick only left mouse clicks
        if (event.getButton() == ItemClickEvent.BUTTON_LEFT)
            Notification.show("Left click",
                        Notification.Type.HUMANIZED_MESSAGE);
    }
  });
----

[[components.tree.expand-collapse]]
== Expanding and Collapsing Items

An item can have children only if the [propertyname]#childrenAllowed# property is set as true.
The expand indicator is shown when and only when the property is true.
The property is defined in the container and can be set with [methodname]#setChildrenAllowed()#.

Expanding an item fires an [classname]#Tree.ExpandEvent# and collapsing an [classname]#Tree.CollapseEvent#, which you can handle with respective listeners.

[source, Java]
----
tree.addExpandListener(new Tree.ExpandListener() {
    public void nodeExpand(ExpandEvent event) {
        Notification.show("Expand!");
    }
});
----

You can expand and collapse items programmatically with [methodname]#expandItem()# or [methodname]#expandItemRecursively()#.

[source, Java]
----
// Expand all items that can be
for (Object itemId: tree.getItemIds())
    tree.expandItem(itemId);
----

TIP: [classname]#Tree# itself does not support lazy loading, which makes it impractical for huge hierarchies.
You can implement one kind of lazy loading by adding items in an expand listener and removing them in a collapse listener.
For more proper lazy loading, you can use [classname]#TreeTable# or hierarchical support extension for [classname]#Grid#.

[[components.tree.css]]
== CSS Style Rules

[source, css]
----
.v-tree {}
  .v-tree-node {}            /* A node (item)           */
    .v-tree-node-caption {}  /* Caption of the node     */
    .v-tree-node-children {} /* Contains child nodes    */
  .v-tree-node-root {}       /* If node is a root node  */
  .v-tree-node-leaf {}       /* If node has no children */
----

[[components.tree.css.itemstyles]]
=== Generating Item Styles

You can style each tree item individually by generating a style name for them with a [interfacename]#Tree.ItemStyleGenerator#, which you assign to a tree with [methodname]#setItemStyleGenerator()#.
The generator should return a style name for each item or `null`.

[source, Java]
----
// Show all leaf nodes as disabled
tree.setItemStyleGenerator(new Tree.ItemStyleGenerator() {
    @Override
    public String getStyle(Tree source, Object itemId) {
        if (! tree.hasChildren(itemId))
            return "disabled";
        return null;
    }
});
----

The style names are prefixed with `v-tree-node-caption-`.
You could thereby define the item styling as follows:

[source, CSS]
----
.v-tree-node-caption-disabled {
    color: graytext;
    font-style: italic;
}
----