123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271 |
- ---
- title: Creating A Custom Field For Editing The Address Of A Person
- order: 27
- layout: page
- ---
-
- [[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]
|