選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

datamodel-itembinding.asciidoc 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. ---
  2. title: Creating Forms by Binding Fields to Items
  3. order: 4
  4. layout: page
  5. ---
  6. [[datamodel.itembinding]]
  7. = Creating Forms by Binding Fields to Items
  8. Most applications in existence have forms of some sort. Forms contain fields,
  9. which you want to bind to a data source, an item in the Vaadin data model.
  10. [classname]#FieldGroup# provides an easy way to bind fields to the properties of
  11. an item. You can use it by first creating a layout with some fields, and then
  12. call it to bind the fields to the data source. You can also let the
  13. [classname]#FieldGroup# create the fields using a field factory. It can also
  14. handle commits. Notice that [classname]#FieldGroup# is not a user interface
  15. component, so you can not add it to a layout.
  16. [[datamodel.itembinding.simple]]
  17. == Simple Binding
  18. Let us start with a data model that has an item with a couple of properties. The
  19. item could be any item type, as described earlier.
  20. ----
  21. // Have an item
  22. PropertysetItem item = new PropertysetItem();
  23. item.addItemProperty("name", new ObjectProperty<String>("Zaphod"));
  24. item.addItemProperty("age", new ObjectProperty<Integer>(42));
  25. ----
  26. Next, you would design a form for editing the data. The [classname]#FormLayout#
  27. (
  28. <<dummy/../../../framework/layout/layout-formlayout#layout.formlayout,"FormLayout">>
  29. is ideal for forms, but you could use any other layout as well.
  30. ----
  31. // Have some layout and create the fields
  32. FormLayout form = new FormLayout();
  33. TextField nameField = new TextField("Name");
  34. form.addComponent(nameField);
  35. TextField ageField = new TextField("Age");
  36. form.addComponent(ageField);
  37. ----
  38. Then, we can bind the fields to the data as follows:
  39. ----
  40. // Now create the binder and bind the fields
  41. FieldGroup binder = new FieldGroup(item);
  42. binder.bind(nameField, "name");
  43. binder.bind(ageField, "age");
  44. ----
  45. The above way of binding is not different from simply calling
  46. [methodname]#setPropertyDataSource()# for the fields. It does, however, register
  47. the fields in the field group, which for example enables buffering or validation
  48. of the fields using the field group, as described in
  49. <<datamodel.itembinding.buffering>>.
  50. Next, we consider more practical uses for a [classname]#FieldGroup#.
  51. [[datamodel.itembinding.fieldfactory]]
  52. == Using a [interfacename]#FieldFactory# to Build and Bind Fields
  53. Using the [methodname]#buildAndBind()# methods, [classname]#FieldGroup# can
  54. create fields for you using a [interfacename]#FieldGroupFieldFactory#, but you
  55. still have to add them to the correct position in your layout.
  56. ----
  57. // Have some layout
  58. FormLayout form = new FormLayout();
  59. // Now create a binder that can also create the fields
  60. // using the default field factory
  61. FieldGroup binder = new FieldGroup(item);
  62. form.addComponent(binder.buildAndBind("Name", "name"));
  63. form.addComponent(binder.buildAndBind("Age", "age"));
  64. ----
  65. [[datamodel.itembinding.formclass]]
  66. == Binding Member Fields
  67. The [methodname]#bindMemberFields()# method in [classname]#FieldGroup# uses
  68. reflection to bind the properties of an item to field components that are member
  69. variables of a class. Hence, if you implement a form as a class with the fields
  70. stored as member variables, you can use this method to bind them super-easy.
  71. The item properties are mapped to the members by the property ID and the name of
  72. the member variable. If you want to map a property with a different ID to a
  73. member, you can use the [literal]#++@PropertyId++# annotation for the member,
  74. with the property ID as the parameter.
  75. For example:
  76. ----
  77. // Have an item
  78. PropertysetItem item = new PropertysetItem();
  79. item.addItemProperty("name", new ObjectProperty<String>("Zaphod"));
  80. item.addItemProperty("age", new ObjectProperty<Integer>(42));
  81. // Define a form as a class that extends some layout
  82. class MyForm extends FormLayout {
  83. // Member that will bind to the "name" property
  84. TextField name = new TextField("Name");
  85. // Member that will bind to the "age" property
  86. @PropertyId("age")
  87. TextField ageField = new TextField("Age");
  88. public MyForm() {
  89. // Customize the layout a bit
  90. setSpacing(true);
  91. // Add the fields
  92. addComponent(name);
  93. addComponent(ageField);
  94. }
  95. }
  96. // Create one
  97. MyForm form = new MyForm();
  98. // Now create a binder that can also creates the fields
  99. // using the default field factory
  100. FieldGroup binder = new FieldGroup(item);
  101. binder.bindMemberFields(form);
  102. // And the form can be used in an higher-level layout
  103. layout.addComponent(form);
  104. ----
  105. See the http://demo.vaadin.com/book-examples-vaadin7/book#datamodel.itembinding.formclass.extended[on-line example, window="_blank"].
  106. [[datamodel.itembinding.formclass.customcomponent]]
  107. === Encapsulating in [classname]#CustomComponent#
  108. Using a [classname]#CustomComponent# can be better for hiding the implementation
  109. details than extending a layout. Also, the use of the [classname]#FieldGroup#
  110. can be encapsulated in the form class.
  111. Consider the following as an alternative for the form implementation presented
  112. earlier:
  113. ----
  114. // A form component that allows editing an item
  115. class MyForm extends CustomComponent {
  116. // Member that will bind to the "name" property
  117. TextField name = new TextField("Name");
  118. // Member that will bind to the "age" property
  119. @PropertyId("age")
  120. TextField ageField = new TextField("Age");
  121. public MyForm(Item item) {
  122. FormLayout layout = new FormLayout();
  123. layout.addComponent(name);
  124. layout.addComponent(ageField);
  125. // Now use a binder to bind the members
  126. FieldGroup binder = new FieldGroup(item);
  127. binder.bindMemberFields(this);
  128. setCompositionRoot(layout);
  129. }
  130. }
  131. // And the form can be used as a component
  132. layout.addComponent(new MyForm(item));
  133. ----
  134. See the http://demo.vaadin.com/book-examples-vaadin7/book#datamodel.itembinding.formclass.customcomponent[on-line example, window="_blank"].
  135. [[datamodel.itembinding.buffering]]
  136. == Buffering Forms
  137. ifdef::vaadin7[]
  138. Just like for individual fields, as described in
  139. <<dummy/../../../framework/components/components-fields#components.fields.buffering,"Field
  140. Buffering">>, a [classname]#FieldGroup# can handle buffering the form content so
  141. that it is written to the item data source only when [methodname]#commit()# is
  142. called for the group. It runs validation for all fields in the group and writes
  143. their values to the item data source only if all fields pass the validation.
  144. Edits can be discarded, so that the field values are reloaded from the data
  145. source, by calling [methodname]#discard()#. Buffering is enabled by default, but
  146. can be disabled by calling [methodname]#setBuffered(false)# for the
  147. [classname]#FieldGroup#.
  148. endif::vaadin7[]
  149. ----
  150. // Have an item of some sort
  151. final PropertysetItem item = new PropertysetItem();
  152. item.addItemProperty("name", new ObjectProperty<String>("Q"));
  153. item.addItemProperty("age", new ObjectProperty<Integer>(42));
  154. // Have some layout and create the fields
  155. Panel form = new Panel("Buffered Form");
  156. form.setContent(new FormLayout());
  157. // Build and bind the fields using the default field factory
  158. final FieldGroup binder = new FieldGroup(item);
  159. form.addComponent(binder.buildAndBind("Name", "name"));
  160. form.addComponent(binder.buildAndBind("Age", "age"));
  161. // Enable buffering (actually enabled by default)
  162. binder.setBuffered(true);
  163. // A button to commit the buffer
  164. form.addComponent(new Button("OK", new ClickListener() {
  165. @Override
  166. public void buttonClick(ClickEvent event) {
  167. try {
  168. binder.commit();
  169. Notification.show("Thanks!");
  170. } catch (CommitException e) {
  171. Notification.show("You fail!");
  172. }
  173. }
  174. }));
  175. // A button to discard the buffer
  176. form.addComponent(new Button("Discard", new ClickListener() {
  177. @Override
  178. public void buttonClick(ClickEvent event) {
  179. binder.discard();
  180. Notification.show("Discarded!");
  181. }
  182. }));
  183. ----
  184. See the http://demo.vaadin.com/book-examples-vaadin7/book#datamodel.itembinding.formclass.customcomponent[on-line example, window="_blank"].
  185. [[datamodel.itembinding.beans]]
  186. == Binding Fields to a Bean
  187. The [classname]#BeanFieldGroup# makes it easier to bind fields to a bean. It
  188. also handles binding to nested beans properties. The build a field bound to a
  189. nested bean property, identify the property with dot notation. For example, if a
  190. [classname]#Person# bean has a [literal]#++address++# property with an
  191. [classname]#Address# type, which in turn has a [literal]#++street++# property,
  192. you could build a field bound to the property with
  193. [methodname]#buildAndBind("Street", "address.street")#.
  194. The input to fields bound to a bean can be validated using the Java Bean
  195. Validation API, as described in <<datamodel.itembinding.beanvalidation>>. The
  196. [classname]#BeanFieldGroup# automatically adds a [classname]#BeanValidator# to
  197. every field if a bean validation implementation is included in the classpath.
  198. [[datamodel.itembinding.beanvalidation]]
  199. == Bean Validation
  200. Vaadin allows using the Java Bean Validation API 1.0 (JSR-303) for validating
  201. ifdef::vaadin7[]
  202. input from fields bound to bean properties before the values are committed to
  203. the bean. The validation is done based on annotations on the bean properties,
  204. which are used for creating the actual validators automatically. See
  205. <<dummy/../../../framework/components/components-fields#components.fields.validation,"Field
  206. Validation">> for general information about validation.
  207. endif::vaadin7[]
  208. Using bean validation requires an implementation of the Bean Validation API,
  209. such as Hibernate Validator ( [filename]#hibernate-validator-4.2.0.Final.jar# or
  210. later) or Apache Bean Validation. The implementation JAR must be included in the
  211. project classpath when using the bean validation, or otherwise an internal error
  212. is thrown.
  213. Bean validation is especially useful when persisting entity beans with the
  214. Vaadin JPAContainer, described in
  215. <<dummy/../../../framework/jpacontainer/jpacontainer-overview.asciidoc#jpacontainer.overview,"Vaadin
  216. JPAContainer">>.
  217. [[datamodel.itembinding.beanvalidation.annotations]]
  218. === Annotations
  219. The validation constraints are defined as annotations. For example, consider the
  220. following bean:
  221. ----
  222. // Here is a bean
  223. public class Person implements Serializable {
  224. @NotNull
  225. @javax.validation.constraints.Size(min=2, max=10)
  226. String name;
  227. @Min(1)
  228. @Max(130)
  229. int age;
  230. // ... setters and getters ...
  231. }
  232. ----
  233. For a complete list of allowed constraints for different data types, please see
  234. the link:http://docs.oracle.com/javaee/6/tutorial/doc/gircz.html[Bean Validation
  235. API documentation].
  236. [[datamodel.itembinding.beanvalidation.validating]]
  237. === Validating the Beans
  238. Validating a bean is done with a [classname]#BeanValidator#, which you
  239. initialize with the name of the bean property it should validate and add it the
  240. the editor field.
  241. In the following example, we validate a single unbuffered field:
  242. ----
  243. Person bean = new Person("Mung bean", 100);
  244. BeanItem<Person> item = new BeanItem<Person> (bean);
  245. // Create an editor bound to a bean field
  246. TextField firstName = new TextField("First Name",
  247. item.getItemProperty("name"));
  248. // Add the bean validator
  249. firstName.addValidator(new BeanValidator(Person.class, "name"));
  250. firstName.setImmediate(true);
  251. layout.addComponent(firstName);
  252. ----
  253. In this case, the validation is done immediately after focus leaves the field.
  254. You could do the same for the other field as well.
  255. Bean validators are automatically created when using a
  256. [classname]#BeanFieldGroup#.
  257. ----
  258. // Have a bean
  259. Person bean = new Person("Mung bean", 100);
  260. // Form for editing the bean
  261. final BeanFieldGroup<Person> binder =
  262. new BeanFieldGroup<Person>(Person.class);
  263. binder.setItemDataSource(bean);
  264. layout.addComponent(binder.buildAndBind("Name", "name"));
  265. layout.addComponent(binder.buildAndBind("Age", "age"));
  266. // Buffer the form content
  267. binder.setBuffered(true);
  268. layout.addComponent(new Button("OK", new ClickListener() {
  269. @Override
  270. public void buttonClick(ClickEvent event) {
  271. try {
  272. binder.commit();
  273. } catch (CommitException e) {
  274. }
  275. }
  276. }));
  277. ----
  278. [[datamodel.itembinding.beanvalidation.locale]]
  279. === Locale Setting for Bean Validation
  280. The validation error messages are defined in the bean validation implementation,
  281. in a [filename]#ValidationMessages.properties# file. The message is shown in the
  282. language specified with the locale setting for the form. The default language is
  283. English, but for example Hibernate Validator contains translations of the
  284. messages for a number of languages. If other languages are needed, you need to
  285. provide a translation of the properties file.