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
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
|
[[creating-a-customfield-for-editing-the-address-of-a-person]]
Creating a CustomField for editing the address of a person
----------------------------------------------------------
A normal use case is that you want to create a form out a bean that the
user can edit. Often these beans contain references to other beans as
well, and you have to create a separate editor for those. This tutorial
goes through on how to edit an `Address` bean which is inside a `Person`
bean with the use of `CustomField` and `FieldGroup`.
Here are the `Person` and `Address` beans
[source,java]
....
public class Person {
private String firstName;
private String lastName;
private Address address;
private String phoneNumber;
private String email;
private Date dateOfBirth;
private String comments;
//Getters and setters
}
....
[source,java]
....
public class Address {
private String street;
private String zip;
private String city;
private String country;
// Getters and setters
}
....
[[creating-a-new-field]]
Creating a new field
~~~~~~~~~~~~~~~~~~~~
The first step is to create a new field which represents the editor for
the address. In this case the field itself will be a button. The button
will open a window where you have all the address fields. The address
will be stored back when the user closes the window.
[source,java]
....
public class AddressPopup extends CustomField<Address> {
@Override
protected Component initContent() {
return null;
}
@Override
public Class<Address> getType() {
return Address.class;
}
}
....
CustomField requires that you implement two methods, `initContent()` and
`getType()`. `initContent()` creates the actual visual representation of
your field. `getType()` tells the field which type of data will be handled
by the field. In our case it is an `Address` object so we return
`Address.class` in the method.
[[creating-the-content]]
Creating the content
~~~~~~~~~~~~~~~~~~~~
Next up we create the actual button that will be visible in the person
editor when the CustomField is rendered. This button should open up a
new window where the user can edit the address.
[source,java]
....
@Override
protected Component initContent() {
final Window window = new Window("Edit address");
final Button button = new Button("Open address editor", new ClickListener() {
public void buttonClick(ClickEvent event) {
getUI().addWindow(window);
}
});
return button;
}
....
This is enough to attach the field to the person editor, but the window
will be empty and it won't modify the data in any way.
[[creating-the-editable-fields]]
Creating the editable fields
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The address object contains four strings - street, zip, city and
country. For the three latter a `TextField` is good for editing, but the
street address can contain multiple row so a `TextArea` is better here.
All the fields have to be put into a layout and the layout has to be set
as the content of the window. `FormLayout` is a good choice here to nicely
align up the captions and fields of the window.
[source,java]
....
FormLayout layout = new FormLayout();
TextArea street = new TextArea("Street address:");
TextField zip = new TextField("Zip code:");
TextField city = new TextField("City:");
TextField country = new TextField("Country:");
layout.addComponent(street);
layout.addComponent(zip);
layout.addComponent(city);
layout.addComponent(country);
window.setContent(layout);
....
The field is now visually ready but it doesn't contain or affect any
data. You want to also modify the sizes as well to make it look a bit
nicer:
[source,java]
....
window.center();
window.setWidth(null);
layout.setWidth(null);
layout.setMargin(true);
....
[[binding-the-address-to-the-field]]
Binding the address to the field
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
A FieldGroup can be used to bind the data of an Address bean into the
fields. We create a member variable for a FieldGroup and initialize it
within the createContent() -method:
[source,java]
....
fieldGroup = new BeanFieldGroup<Address>(Address.class);
fieldGroup.bind(street, "street");
fieldGroup.bind(zip, "zip");
fieldGroup.bind(city, "city");
fieldGroup.bind(country, "country");
....
The `FieldGroup` of the person editor will call
`AddressPopup.setValue(person.getAddress())` when we start to edit our
person. We need to override `setInternalValue(Address)` to get the `Address`
object and pass it to the `FieldGroup` of the address editor.
[source,java]
....
@Override
protected void setInternalValue(Address address) {
super.setInternalValue(address);
fieldGroup.setItemDataSource(new BeanItem<Address>(address));
}
....
The last thing that has to be done is save the modifications made by the
user back into the `Address` bean. This is done with a `commit()` call to
the `FieldGroup`, which can be made for example when the window is closed:
[source,java]
....
window.addCloseListener(new CloseListener() {
public void windowClose(CloseEvent e) {
try {
fieldGroup.commit();
} catch (CommitException ex) {
ex.printStackTrace();
}
}
});
....
Now you need to attach the `AddressPopup` custom field into the person
editor through it's `FieldGroup` and you have a working editor.
[[complete-code]]
Complete code
~~~~~~~~~~~~~
[source,java]
....
package com.example.addressforms.fields;
import com.example.addressforms.data.Address;
import com.vaadin.data.fieldgroup.BeanFieldGroup;
import com.vaadin.data.fieldgroup.FieldGroup;
import com.vaadin.data.fieldgroup.FieldGroup.CommitException;
import com.vaadin.data.util.BeanItem;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Button.ClickListener;
import com.vaadin.ui.Component;
import com.vaadin.ui.CustomField;
import com.vaadin.ui.FormLayout;
import com.vaadin.ui.TextArea;
import com.vaadin.ui.TextField;
import com.vaadin.ui.Window;
import com.vaadin.ui.Window.CloseEvent;
import com.vaadin.ui.Window.CloseListener;
public class AddressPopup extends CustomField<Address> {
private FieldGroup fieldGroup;
@Override
protected Component initContent() {
FormLayout layout = new FormLayout();
final Window window = new Window("Edit address", layout);
TextArea street = new TextArea("Street address:");
TextField zip = new TextField("Zip code:");
TextField city = new TextField("City:");
TextField country = new TextField("Country:");
layout.addComponent(street);
layout.addComponent(zip);
layout.addComponent(city);
layout.addComponent(country);
fieldGroup = new BeanFieldGroup<Address>(Address.class);
fieldGroup.bind(street, "street");
fieldGroup.bind(zip, "zip");
fieldGroup.bind(city, "city");
fieldGroup.bind(country, "country");
Button button = new Button("Open address editor", new ClickListener() {
public void buttonClick(ClickEvent event) {
getUI().addWindow(window);
}
});
window.addCloseListener(new CloseListener() {
public void windowClose(CloseEvent e) {
try {
fieldGroup.commit();
} catch (CommitException ex) {
ex.printStackTrace();
}
}
});
window.center();
window.setWidth(null);
layout.setWidth(null);
layout.setMargin(true);
return button;
}
@Override
public Class<Address> getType() {
return Address.class;
}
@Override
protected void setInternalValue(Address address) {
super.setInternalValue(address);
fieldGroup.setItemDataSource(new BeanItem<Address>(address));
}
}
....
image:img/person%20editor.png[Address editor]
image:img/address%20editor.png[Address editor window]
|