You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

CreatingACustomFieldForEditingTheAddressOfAPerson.asciidoc 7.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. ---
  2. title: Creating A Custom Field For Editing The Address Of A Person
  3. order: 27
  4. layout: page
  5. ---
  6. [[creating-a-customfield-for-editing-the-address-of-a-person]]
  7. = Creating a CustomField for editing the address of a person
  8. A normal use case is that you want to create a form out a bean that the
  9. user can edit. Often these beans contain references to other beans as
  10. well, and you have to create a separate editor for those. This tutorial
  11. goes through on how to edit an `Address` bean which is inside a `Person`
  12. bean with the use of `CustomField` and `FieldGroup`.
  13. Here are the `Person` and `Address` beans
  14. [source,java]
  15. ....
  16. public class Person {
  17. private String firstName;
  18. private String lastName;
  19. private Address address;
  20. private String phoneNumber;
  21. private String email;
  22. private Date dateOfBirth;
  23. private String comments;
  24. //Getters and setters
  25. }
  26. ....
  27. [source,java]
  28. ....
  29. public class Address {
  30. private String street;
  31. private String zip;
  32. private String city;
  33. private String country;
  34. // Getters and setters
  35. }
  36. ....
  37. [[creating-a-new-field]]
  38. Creating a new field
  39. ~~~~~~~~~~~~~~~~~~~~
  40. The first step is to create a new field which represents the editor for
  41. the address. In this case the field itself will be a button. The button
  42. will open a window where you have all the address fields. The address
  43. will be stored back when the user closes the window.
  44. [source,java]
  45. ....
  46. public class AddressPopup extends CustomField<Address> {
  47. @Override
  48. protected Component initContent() {
  49. return null;
  50. }
  51. @Override
  52. public Class<Address> getType() {
  53. return Address.class;
  54. }
  55. }
  56. ....
  57. CustomField requires that you implement two methods, `initContent()` and
  58. `getType()`. `initContent()` creates the actual visual representation of
  59. your field. `getType()` tells the field which type of data will be handled
  60. by the field. In our case it is an `Address` object so we return
  61. `Address.class` in the method.
  62. [[creating-the-content]]
  63. Creating the content
  64. ~~~~~~~~~~~~~~~~~~~~
  65. Next up we create the actual button that will be visible in the person
  66. editor when the CustomField is rendered. This button should open up a
  67. new window where the user can edit the address.
  68. [source,java]
  69. ....
  70. @Override
  71. protected Component initContent() {
  72. final Window window = new Window("Edit address");
  73. final Button button = new Button("Open address editor", new ClickListener() {
  74. public void buttonClick(ClickEvent event) {
  75. getUI().addWindow(window);
  76. }
  77. });
  78. return button;
  79. }
  80. ....
  81. This is enough to attach the field to the person editor, but the window
  82. will be empty and it won't modify the data in any way.
  83. [[creating-the-editable-fields]]
  84. Creating the editable fields
  85. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  86. The address object contains four strings - street, zip, city and
  87. country. For the three latter a `TextField` is good for editing, but the
  88. street address can contain multiple row so a `TextArea` is better here.
  89. All the fields have to be put into a layout and the layout has to be set
  90. as the content of the window. `FormLayout` is a good choice here to nicely
  91. align up the captions and fields of the window.
  92. [source,java]
  93. ....
  94. FormLayout layout = new FormLayout();
  95. TextArea street = new TextArea("Street address:");
  96. TextField zip = new TextField("Zip code:");
  97. TextField city = new TextField("City:");
  98. TextField country = new TextField("Country:");
  99. layout.addComponent(street);
  100. layout.addComponent(zip);
  101. layout.addComponent(city);
  102. layout.addComponent(country);
  103. window.setContent(layout);
  104. ....
  105. The field is now visually ready but it doesn't contain or affect any
  106. data. You want to also modify the sizes as well to make it look a bit
  107. nicer:
  108. [source,java]
  109. ....
  110. window.center();
  111. window.setWidth(null);
  112. layout.setWidth(null);
  113. layout.setMargin(true);
  114. ....
  115. [[binding-the-address-to-the-field]]
  116. Binding the address to the field
  117. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  118. A FieldGroup can be used to bind the data of an Address bean into the
  119. fields. We create a member variable for a FieldGroup and initialize it
  120. within the createContent() -method:
  121. [source,java]
  122. ....
  123. fieldGroup = new BeanFieldGroup<Address>(Address.class);
  124. fieldGroup.bind(street, "street");
  125. fieldGroup.bind(zip, "zip");
  126. fieldGroup.bind(city, "city");
  127. fieldGroup.bind(country, "country");
  128. ....
  129. The `FieldGroup` of the person editor will call
  130. `AddressPopup.setValue(person.getAddress())` when we start to edit our
  131. person. We need to override `setInternalValue(Address)` to get the `Address`
  132. object and pass it to the `FieldGroup` of the address editor.
  133. [source,java]
  134. ....
  135. @Override
  136. protected void setInternalValue(Address address) {
  137. super.setInternalValue(address);
  138. fieldGroup.setItemDataSource(new BeanItem<Address>(address));
  139. }
  140. ....
  141. The last thing that has to be done is save the modifications made by the
  142. user back into the `Address` bean. This is done with a `commit()` call to
  143. the `FieldGroup`, which can be made for example when the window is closed:
  144. [source,java]
  145. ....
  146. window.addCloseListener(new CloseListener() {
  147. public void windowClose(CloseEvent e) {
  148. try {
  149. fieldGroup.commit();
  150. } catch (CommitException ex) {
  151. ex.printStackTrace();
  152. }
  153. }
  154. });
  155. ....
  156. Now you need to attach the `AddressPopup` custom field into the person
  157. editor through it's `FieldGroup` and you have a working editor.
  158. [[complete-code]]
  159. Complete code
  160. ~~~~~~~~~~~~~
  161. [source,java]
  162. ....
  163. package com.example.addressforms.fields;
  164. import com.example.addressforms.data.Address;
  165. import com.vaadin.data.fieldgroup.BeanFieldGroup;
  166. import com.vaadin.data.fieldgroup.FieldGroup;
  167. import com.vaadin.data.fieldgroup.FieldGroup.CommitException;
  168. import com.vaadin.data.util.BeanItem;
  169. import com.vaadin.ui.Button;
  170. import com.vaadin.ui.Button.ClickEvent;
  171. import com.vaadin.ui.Button.ClickListener;
  172. import com.vaadin.ui.Component;
  173. import com.vaadin.ui.CustomField;
  174. import com.vaadin.ui.FormLayout;
  175. import com.vaadin.ui.TextArea;
  176. import com.vaadin.ui.TextField;
  177. import com.vaadin.ui.Window;
  178. import com.vaadin.ui.Window.CloseEvent;
  179. import com.vaadin.ui.Window.CloseListener;
  180. public class AddressPopup extends CustomField<Address> {
  181. private FieldGroup fieldGroup;
  182. @Override
  183. protected Component initContent() {
  184. FormLayout layout = new FormLayout();
  185. final Window window = new Window("Edit address", layout);
  186. TextArea street = new TextArea("Street address:");
  187. TextField zip = new TextField("Zip code:");
  188. TextField city = new TextField("City:");
  189. TextField country = new TextField("Country:");
  190. layout.addComponent(street);
  191. layout.addComponent(zip);
  192. layout.addComponent(city);
  193. layout.addComponent(country);
  194. fieldGroup = new BeanFieldGroup<Address>(Address.class);
  195. fieldGroup.bind(street, "street");
  196. fieldGroup.bind(zip, "zip");
  197. fieldGroup.bind(city, "city");
  198. fieldGroup.bind(country, "country");
  199. Button button = new Button("Open address editor", new ClickListener() {
  200. public void buttonClick(ClickEvent event) {
  201. getUI().addWindow(window);
  202. }
  203. });
  204. window.addCloseListener(new CloseListener() {
  205. public void windowClose(CloseEvent e) {
  206. try {
  207. fieldGroup.commit();
  208. } catch (CommitException ex) {
  209. ex.printStackTrace();
  210. }
  211. }
  212. });
  213. window.center();
  214. window.setWidth(null);
  215. layout.setWidth(null);
  216. layout.setMargin(true);
  217. return button;
  218. }
  219. @Override
  220. public Class<Address> getType() {
  221. return Address.class;
  222. }
  223. @Override
  224. protected void setInternalValue(Address address) {
  225. super.setInternalValue(address);
  226. fieldGroup.setItemDataSource(new BeanItem<Address>(address));
  227. }
  228. }
  229. ....
  230. image:img/person%20editor.png[Address editor]
  231. image:img/address%20editor.png[Address editor window]