Vaadin
Part of tutorial series CRUD app tutorial

Forms and data binding

This part of the tutorial shows how to implement a reusable form to edit data.

Form

So far, all UI coding has been in one class, MainView. However, you can also use object-oriented composition to create reusable UI components with Vaadin. A customer form is a perfect candidate to demonstrate how to implement and use a reusable UI component.

Adding Input Fields and Buttons

  1. Start by creating a new class in IntelliJ IDEA:

    • Right-click the org.vaadin.example package and select New > Java Class.

    • In the Name field, type CustomerForm, and click OK.

  2. To make this class a Vaadin UI component, you need to extend an existing component. Extend the FormLayout component as follows:

    public class CustomerForm extends FormLayout {
    }
  3. The form needs an input field for each editable property in the Customer class. Vaadin provides different kinds of fields for editing different kinds of values. We use the TextField, ComboBox, and DatePicker components. Define the following instance variables in the CustomerForm class:

    private TextField firstName = new TextField("First name");
    private TextField lastName = new TextField("Last name");
    private ComboBox<CustomerStatus> status = new ComboBox<>("Status");
    private DatePicker birthDate = new DatePicker("Birthdate");
  4. The form also needs two buttons to save and delete Customer instances. Add the buttons to the CustomerForm class as follows:

    private Button save = new Button("Save");
    private Button delete = new Button("Delete");
  5. With the components in place, you can configure and add them to the form. A good place to do this is the constructor. Add the following constructor to the CustomerForm class:

    public CustomerForm() {
        status.setItems(CustomerStatus.values());
    
        HorizontalLayout buttons = new HorizontalLayout(save, delete);
        save.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
        add(firstName, lastName, status, birthDate, buttons);
    }
    • status.setItems adds all the enum values as options to the ComboBox.

    • addThemeVariants makes the save button prominent by decorating it with a style name.

Showing and Hiding the Form

It should be possible to show the corresponding data from a specific Customer instance in the form, and to hide the form when necessary.

  1. To display specific customer data in the form, you need to connect the properties of a given Customer instance to the input fields in the form. This is known as data binding, and Vaadin provides the Binder helper class for this purpose. To bind the data, add a new property of type Binder to the CustomerForm class and configure it in the constructor as follows:

    private Binder<Customer> binder = new Binder<>(Customer.class);
    
    public CustomerForm() {
        ...
    
        binder.bindInstanceFields(this);
    }
    • The bindInstanceFields(this) method processes all the instance variables that are input fields (for example, TextField and ComboBox) and maps them to the Java properties in the Customer class matching by name. For example, Customer::firstName is mapped to the CustomerForm::firstName input field.

    • You can override automatic mapping using the @PropertyId annotation in the CustomerForm input fields to explicitly declare the corresponding Customer instance variables.

  2. You can implement the logic to show or hide the form in a single public method. To do so, add the following code to the CustomerForm class:

    public void setCustomer(Customer customer) {
        binder.setBean(customer);
    
        if (customer == null) {
            setVisible(false);
        } else {
            setVisible(true);
            firstName.focus();
        }
    }
    • setBean connects the values in the customer object to the corresponding input fields of the form. When the user changes the value of an input field, the value is set in the corresponding instance variable of the customer object.

    • When the customer is:

      • null, the form is hidden.

      • is not null, the form is shown, and keyboard focus is placed on the First name input field to allow immediate typing.

Implementing the Save and Delete Actions

  1. To ensure the save and the delete actions update the list of customers in the MainView class, we need to add a reference to this class. You can receive this reference in the constructor of the CustomerForm as follows:

    private MainView mainView;
    
    public CustomerForm(MainView mainView) {
        this.mainView = mainView;
    
        ...
    }
  2. The save and the delete actions also need to reference the CustomerService class. Add a reference in the CustomerForm class as follows:

    private CustomerService service = CustomerService.getInstance();
  3. With the service and mainView variables in place, implement the save action as follows:

    public CustomerForm(MainView mainView) {
        ...
    
        save.addClickListener(event -> save());
    }
    
    ...
    
    private void save() {
        Customer customer = binder.getBean();
        service.save(customer);
        mainView.updateList();
        setCustomer(null);
    }
    • getBean gets the customer instance that was bound to the input fields of the form.

    • service.save(customer) performs the save action in the backend.

    • updateList updates the list of customers in the main view.

    • setCustomer(null) hides the form.

  4. Similarly, implement the delete action as follows:

    public CustomerForm(MainView mainView) {
        ...
        delete.addClickListener(event -> delete());
    }
    
    ...
    
    private void delete() {
        Customer customer = binder.getBean();
        service.delete(customer);
        mainView.updateList();
        setCustomer(null);
    }
Note
In a real-world project, you should introduce an interface to avoid coupling with the MainView class. Alternatively, you could use an event system, like CDI events, to completely decouple the components. To keep things simple, we left this out of the scope of this tutorial.

Adding the Form to the Main View

  1. To add the form to the main view, add the form as a new instance variable in the MainView class:

    public class MainView extends VerticalLayout {
    
        ...
        private CustomerForm form = new CustomerForm(this);
    
        ...
    }
  2. To display the form to the right of the Grid, in the MainView class introduce a HorizontalLayout to wrap the grid and the customerForm components. Replace the add(filterText, grid) line of code with the following:

    HorizontalLayout mainContent = new HorizontalLayout(grid, form);
    mainContent.setSizeFull();
    grid.setSizeFull();
    
    add(filterText, mainContent);
  3. Compile the project, by selecting Build > Build Project in IntelliJ IDEA, and refresh your browser to see the changes.

    From added to the application layout
    Note
    The Save and Delete buttons don’t work at this point, we’ll add this in the next part of the tutorial.
Vaadin is an open-source framework offering the fastest way to build web apps on Java backends
GET STARTED

Comments (5)

Marcus Hellberg
2 years ago Mar 11, 2020 8:33pm
Ryan Alton
2 years ago Sep 15, 2019 9:07pm