Docs

Documentation versions (currently viewingVaadin 14)
You are viewing documentation for an older Vaadin version. View latest documentation

Connecting Main View to Java

When you build a view with Designer, there are two main files for each view:

  • main-view.ts: This is the template file where you lay out the components and define everything that is static.

  • MainView.java: This is the Java class that uses the template, adds UI logic, and configures all parts that are dynamic. We refer to this file as the companion file for the template.

When we created the views earlier in the tutorial, we checked the Create Java Companion file option in the New Vaadin 10+ Design dialog. This is why the MainView.java and ContactForm.java files were generated automatically. Adding Java code to your views is not visible in the template in Designer, but it is used when you run your application.

For the main view, in the companion file, we need to

  1. Load data to the grid.

  2. Filter data based on the text field.

  3. Populate the contact form when the user selects a row in the grid.

  4. Enable adding new contacts using the Add contact button.

In the contact form, we need to

  1. Bind fields with a contact object given by the main view.

  2. Implement the save, delete and close buttons.

We start with loading data into the grid.

Exporting Components to Java

First, we export the components which require data or interaction logic to Java. To do this, we need to tell Designer which components should be available from Java code. For the main view, we need the grid to display data, the text field to filter data and the button to add new contacts.

  1. In Designer, open main-view.ts.

  2. Select the "Filter by name…​" text field.

  3. In the properties view, go to the attributes panel, find the id attribute and give the text field the "filterText" id. This is what the component will be called in the Java companion file.

  4. In the outline, hover over the selected vaadin-text-field and click the icon that appears in the row on the right. This allows you to connect the component to Java and makes the field available from your Java code.

  5. Repeat this process (steps 2 - 4) for the:

    1. vaadin-button: id attribute = "addContactButton".

    2. vaadin-grid: id attribute = "grid".

    3. contact-form: id attribute = "contactForm".

All the fields should now be available from your Java code. To check this, open the src/main/java/com.example.application.MainView class.

@Tag("main-view")
@JsModule("./src/views/main-view.ts")
@Route("")
public class MainView extends LitTemplate {

    @Id("filterText") 1
    private TextField filterText; 2
    @Id("addContactButton")
    private Button addContactButton; 3
    @Id("grid")
    private Grid grid; 4
    @Id("contactForm")
    private ContactForm contactForm; 5

    public MainView() {
    }

}
  1. The fields are now connected to the template in the @Id("identifier") annotations.

  2. The text field uses the filterText id.

  3. The button uses the addContactButton id.

  4. The grid uses the grid id.

  5. The contact form uses the contactForm id.

Warning
Unfortunately, there is currently a bug that prevents contact-form (which is itself a template) from being correctly embbeded inside the main-view template. Until the issue is fixed, we can use the workaround detailed below. Without this running the application will produce an error.

To work around the bug:

  1. In Designer, open contact-form.ts.

  2. To see the design’s source code, click on the Source mode button that is highlighted in the following screenshot:app-name:

  3. Remove the createRenderRoot() method from the template and save the file.

  4. Click on the Edit mode button (located to the left-side of the Source mode button) in order to see the Design again.

Add Data to the Grid

Next, we want to load data from the backend and show it inside the grid. The first task is to configure the columns. For each contact we want to show its first name, last name, email, company, and status.

We take advantage of Spring’s dependency injection to get hold of the backend service, by adding it as a parameter in the constructor. Spring passes it in when MainView is created.

Modify MainView as follows:

@Tag("main-view")
@JsModule("./src/views/main-view.ts")
@Route("")
public class MainView extends LitTemplate {

    @Id("filterText")
    private TextField filterText;
    @Id("addContactButton")
    private Button addContactButton;
    @Id("grid")
    private Grid<Contact> grid; 1
    @Id("contactForm")
    private ContactForm contactForm;

    ContactRepository contactRepository; 2

    public MainView(ContactRepository contactRepository) {  3
        this.contactRepository = contactRepository;

        grid.addColumn(Contact::getFirstName).setHeader("First name"); 4
        grid.addColumn(Contact::getLastName).setHeader("Last name");
        grid.addColumn(Contact::getEmail).setHeader("Email");
        grid.addColumn(Contact::getCompany).setHeader("Company");
        grid.addColumn(Contact::getStatus).setHeader("Status");
        grid.getColumns().forEach(col -> col.setAutoWidth(true)); 5
        updateList();
    }

    private void updateList() {
        grid.setItems(contactRepository.findAll());  6
    }

}
  1. Adds the bean type as a type parameter to the grid.

  2. Creates a field for storing the service for future access.

  3. Spring passes in the service when the view is created using autowiring.

  4. Adds and configures columns in the grid.

  5. Configures column sizing: all columns are sized based on their content.

  6. Fetches items from the service and passes them to the grid.

Next, run the application, or restart if it is already running.

Refresh the http://localhost:8080/ browser tab. The grid now shows the contacts from the service.

Enabling Filtering

We would like to filter the grid based on the first name and last name when the user types a value in the filter text field. For this, we add a value-change listener to the filtering text field so that we pass the value to the contact service.

@Tag("main-view")
@JsModule("./src/views/main-view.ts")
@Route("")
public class MainView extends LitTemplate {

    // Fields omitted
    ...

    public MainView(ContactRepository contactRepository) {
        this.contactRepository = contactRepository;

        grid.addColumn(Contact::getFirstName).setHeader("First name");
        grid.addColumn(Contact::getLastName).setHeader("Last name");
        grid.addColumn(Contact::getEmail).setHeader("Email");
        grid.addColumn(Contact::getCompany).setHeader("Company");
        grid.addColumn(Contact::getStatus).setHeader("Status");
        grid.getColumns().forEach(col -> col.setAutoWidth(true));
        updateList();

        filterText.setValueChangeMode(ValueChangeMode.LAZY); 1
        filterText.addValueChangeListener(e -> updateList()); 2
    }

    private void updateList() {
        String filterValue = filterText.getValue();
        if (filterValue == null || filterValue.isBlank()) {
            grid.setItems(contactRepository.findAll());
        } else {
            grid.setItems(contactRepository.findByFirstNameOrLastNameContainsIgnoreCase(filterValue, filterValue)); 3
        }
    }
}
  1. Puts text field value changes in lazy mode, so that the database is not queried on each keystroke.

  2. Adds a value-change listener to the text field which tells the grid to update items.

  3. If the filtering value is present, call findByFirstNameOrLastNameContainsIgnoreCase() to fetch the records with first or last name containing the passed string.

Run the application. The grid is now searchable based on the name entered in the text field.

Proceed to the next chapter to connect your Contact Form to Java: Connect your Contact Form.