diff options
Diffstat (limited to 'documentation/datamodel/datamodel-itembinding.asciidoc')
-rw-r--r-- | documentation/datamodel/datamodel-itembinding.asciidoc | 377 |
1 files changed, 0 insertions, 377 deletions
diff --git a/documentation/datamodel/datamodel-itembinding.asciidoc b/documentation/datamodel/datamodel-itembinding.asciidoc deleted file mode 100644 index fd21b72267..0000000000 --- a/documentation/datamodel/datamodel-itembinding.asciidoc +++ /dev/null @@ -1,377 +0,0 @@ ---- -title: Creating Forms by Binding Fields to Items -order: 4 -layout: page ---- - -[[datamodel.itembinding]] -= Creating Forms by Binding Fields to Items - -Most applications in existence have forms of some sort. Forms contain fields, -which you want to bind to a data source, an item in the Vaadin data model. -[classname]#FieldGroup# provides an easy way to bind fields to the properties of -an item. You can use it by first creating a layout with some fields, and then -call it to bind the fields to the data source. You can also let the -[classname]#FieldGroup# create the fields using a field factory. It can also -handle commits. Notice that [classname]#FieldGroup# is not a user interface -component, so you can not add it to a layout. - -[[datamodel.itembinding.simple]] -== Simple Binding - -Let us start with a data model that has an item with a couple of properties. The -item could be any item type, as described earlier. - - ----- -// Have an item -PropertysetItem item = new PropertysetItem(); -item.addItemProperty("name", new ObjectProperty<String>("Zaphod")); -item.addItemProperty("age", new ObjectProperty<Integer>(42)); ----- - -Next, you would design a form for editing the data. The [classname]#FormLayout# -( -<<dummy/../../../framework/layout/layout-formlayout#layout.formlayout,"FormLayout">> -is ideal for forms, but you could use any other layout as well. - - ----- -// Have some layout and create the fields -FormLayout form = new FormLayout(); - -TextField nameField = new TextField("Name"); -form.addComponent(nameField); - -TextField ageField = new TextField("Age"); -form.addComponent(ageField); ----- - -Then, we can bind the fields to the data as follows: - - ----- -// Now create the binder and bind the fields -FieldGroup binder = new FieldGroup(item); -binder.bind(nameField, "name"); -binder.bind(ageField, "age"); ----- - -The above way of binding is not different from simply calling -[methodname]#setPropertyDataSource()# for the fields. It does, however, register -the fields in the field group, which for example enables buffering or validation -of the fields using the field group, as described in -<<datamodel.itembinding.buffering>>. - -Next, we consider more practical uses for a [classname]#FieldGroup#. - - -[[datamodel.itembinding.fieldfactory]] -== Using a [interfacename]#FieldFactory# to Build and Bind Fields - -Using the [methodname]#buildAndBind()# methods, [classname]#FieldGroup# can -create fields for you using a [interfacename]#FieldGroupFieldFactory#, but you -still have to add them to the correct position in your layout. - - ----- -// Have some layout -FormLayout form = new FormLayout(); - -// Now create a binder that can also create the fields -// using the default field factory -FieldGroup binder = new FieldGroup(item); -form.addComponent(binder.buildAndBind("Name", "name")); -form.addComponent(binder.buildAndBind("Age", "age")); ----- - - -[[datamodel.itembinding.formclass]] -== Binding Member Fields - -The [methodname]#bindMemberFields()# method in [classname]#FieldGroup# uses -reflection to bind the properties of an item to field components that are member -variables of a class. Hence, if you implement a form as a class with the fields -stored as member variables, you can use this method to bind them super-easy. - -The item properties are mapped to the members by the property ID and the name of -the member variable. If you want to map a property with a different ID to a -member, you can use the [literal]#++@PropertyId++# annotation for the member, -with the property ID as the parameter. - -For example: - - ----- -// Have an item -PropertysetItem item = new PropertysetItem(); -item.addItemProperty("name", new ObjectProperty<String>("Zaphod")); -item.addItemProperty("age", new ObjectProperty<Integer>(42)); - -// Define a form as a class that extends some layout -class MyForm extends FormLayout { - // Member that will bind to the "name" property - TextField name = new TextField("Name"); - - // Member that will bind to the "age" property - @PropertyId("age") - TextField ageField = new TextField("Age"); - - public MyForm() { - // Customize the layout a bit - setSpacing(true); - - // Add the fields - addComponent(name); - addComponent(ageField); - } -} - -// Create one -MyForm form = new MyForm(); - -// Now create a binder that can also creates the fields -// using the default field factory -FieldGroup binder = new FieldGroup(item); -binder.bindMemberFields(form); - -// And the form can be used in an higher-level layout -layout.addComponent(form); ----- -See the http://demo.vaadin.com/book-examples-vaadin7/book#datamodel.itembinding.formclass.extended[on-line example, window="_blank"]. - -[[datamodel.itembinding.formclass.customcomponent]] -=== Encapsulating in [classname]#CustomComponent# - -Using a [classname]#CustomComponent# can be better for hiding the implementation -details than extending a layout. Also, the use of the [classname]#FieldGroup# -can be encapsulated in the form class. - -Consider the following as an alternative for the form implementation presented -earlier: - - ----- -// A form component that allows editing an item -class MyForm extends CustomComponent { - // Member that will bind to the "name" property - TextField name = new TextField("Name"); - - // Member that will bind to the "age" property - @PropertyId("age") - TextField ageField = new TextField("Age"); - - public MyForm(Item item) { - FormLayout layout = new FormLayout(); - layout.addComponent(name); - layout.addComponent(ageField); - - // Now use a binder to bind the members - FieldGroup binder = new FieldGroup(item); - binder.bindMemberFields(this); - - setCompositionRoot(layout); - } -} - -// And the form can be used as a component -layout.addComponent(new MyForm(item)); ----- -See the http://demo.vaadin.com/book-examples-vaadin7/book#datamodel.itembinding.formclass.customcomponent[on-line example, window="_blank"]. - - - -[[datamodel.itembinding.buffering]] -== Buffering Forms - -Just like for individual fields, as described in -<<dummy/../../../framework/components/components-fields#components.fields.buffering,"Field -Buffering">>, a [classname]#FieldGroup# can handle buffering the form content so -that it is written to the item data source only when [methodname]#commit()# is -called for the group. It runs validation for all fields in the group and writes -their values to the item data source only if all fields pass the validation. -Edits can be discarded, so that the field values are reloaded from the data -source, by calling [methodname]#discard()#. Buffering is enabled by default, but -can be disabled by calling [methodname]#setBuffered(false)# for the -[classname]#FieldGroup#. - - ----- -// Have an item of some sort -final PropertysetItem item = new PropertysetItem(); -item.addItemProperty("name", new ObjectProperty<String>("Q")); -item.addItemProperty("age", new ObjectProperty<Integer>(42)); - -// Have some layout and create the fields -Panel form = new Panel("Buffered Form"); -form.setContent(new FormLayout()); - -// Build and bind the fields using the default field factory -final FieldGroup binder = new FieldGroup(item); -form.addComponent(binder.buildAndBind("Name", "name")); -form.addComponent(binder.buildAndBind("Age", "age")); - -// Enable buffering (actually enabled by default) -binder.setBuffered(true); - -// A button to commit the buffer -form.addComponent(new Button("OK", new ClickListener() { - @Override - public void buttonClick(ClickEvent event) { - try { - binder.commit(); - Notification.show("Thanks!"); - } catch (CommitException e) { - Notification.show("You fail!"); - } - } -})); - -// A button to discard the buffer -form.addComponent(new Button("Discard", new ClickListener() { - @Override - public void buttonClick(ClickEvent event) { - binder.discard(); - Notification.show("Discarded!"); - } -})); ----- -See the http://demo.vaadin.com/book-examples-vaadin7/book#datamodel.itembinding.formclass.customcomponent[on-line example, window="_blank"]. - - -[[datamodel.itembinding.beans]] -== Binding Fields to a Bean - -The [classname]#BeanFieldGroup# makes it easier to bind fields to a bean. It -also handles binding to nested beans properties. The build a field bound to a -nested bean property, identify the property with dot notation. For example, if a -[classname]#Person# bean has a [literal]#++address++# property with an -[classname]#Address# type, which in turn has a [literal]#++street++# property, -you could build a field bound to the property with -[methodname]#buildAndBind("Street", "address.street")#. - -The input to fields bound to a bean can be validated using the Java Bean -Validation API, as described in <<datamodel.itembinding.beanvalidation>>. The -[classname]#BeanFieldGroup# automatically adds a [classname]#BeanValidator# to -every field if a bean validation implementation is included in the classpath. - - -[[datamodel.itembinding.beanvalidation]] -== Bean Validation - -Vaadin allows using the Java Bean Validation API 1.0 (JSR-303) for validating -input from fields bound to bean properties before the values are committed to -the bean. The validation is done based on annotations on the bean properties, -which are used for creating the actual validators automatically. See -<<dummy/../../../framework/components/components-fields#components.fields.validation,"Field -Validation">> for general information about validation. - -Using bean validation requires an implementation of the Bean Validation API, -such as Hibernate Validator ( [filename]#hibernate-validator-4.2.0.Final.jar# or -later) or Apache Bean Validation. The implementation JAR must be included in the -project classpath when using the bean validation, or otherwise an internal error -is thrown. - -Bean validation is especially useful when persisting entity beans with the -Vaadin JPAContainer, described in -<<dummy/../../../framework/jpacontainer/jpacontainer-overview.asciidoc#jpacontainer.overview,"Vaadin -JPAContainer">>. - -[[datamodel.itembinding.beanvalidation.annotations]] -=== Annotations - -The validation constraints are defined as annotations. For example, consider the -following bean: - - ----- -// Here is a bean -public class Person implements Serializable { - @NotNull - @javax.validation.constraints.Size(min=2, max=10) - String name; - - @Min(1) - @Max(130) - int age; - - // ... setters and getters ... -} ----- - -For a complete list of allowed constraints for different data types, please see -the link:http://docs.oracle.com/javaee/6/tutorial/doc/gircz.html[Bean Validation -API documentation]. - - -[[datamodel.itembinding.beanvalidation.validating]] -=== Validating the Beans - -Validating a bean is done with a [classname]#BeanValidator#, which you -initialize with the name of the bean property it should validate and add it the -the editor field. - -In the following example, we validate a single unbuffered field: - - ----- -Person bean = new Person("Mung bean", 100); -BeanItem<Person> item = new BeanItem<Person> (bean); - -// Create an editor bound to a bean field -TextField firstName = new TextField("First Name", - item.getItemProperty("name")); - -// Add the bean validator -firstName.addValidator(new BeanValidator(Person.class, "name")); - -firstName.setImmediate(true); -layout.addComponent(firstName); ----- - -In this case, the validation is done immediately after focus leaves the field. -You could do the same for the other field as well. - -Bean validators are automatically created when using a -[classname]#BeanFieldGroup#. - - ----- -// Have a bean -Person bean = new Person("Mung bean", 100); - -// Form for editing the bean -final BeanFieldGroup<Person> binder = - new BeanFieldGroup<Person>(Person.class); -binder.setItemDataSource(bean); -layout.addComponent(binder.buildAndBind("Name", "name")); -layout.addComponent(binder.buildAndBind("Age", "age")); - -// Buffer the form content -binder.setBuffered(true); -layout.addComponent(new Button("OK", new ClickListener() { - @Override - public void buttonClick(ClickEvent event) { - try { - binder.commit(); - } catch (CommitException e) { - } - } -})); ----- - - -[[datamodel.itembinding.beanvalidation.locale]] -=== Locale Setting for Bean Validation - -The validation error messages are defined in the bean validation implementation, -in a [filename]#ValidationMessages.properties# file. The message is shown in the -language specified with the locale setting for the form. The default language is -English, but for example Hibernate Validator contains translations of the -messages for a number of languages. If other languages are needed, you need to -provide a translation of the properties file. - - - - - |