Passing Data & Events among Vaadin Components
On the previous part of this tutorial, you created a reusable form component to edit contacts. Now you’ll connect it to the rest of the view and manage the view state.
The form shows the selected contact in the grid. It’s hidden when no contact is selected. It also saves and deletes contacts in the database.
Show Selected Contact in Form
The first step is to show the selected grid row in the form. To do this, update ListView
as follows:
package com.example.application.views.list;
import com.example.application.data.Contact;
import com.example.application.services.CrmService;
import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.grid.Grid;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.data.value.ValueChangeMode;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;
@Route(value = "")
@PageTitle("Contacts | Vaadin CRM")
public class ListView extends VerticalLayout {
Grid<Contact> grid = new Grid<>(Contact.class);
TextField filterText = new TextField();
ContactForm form;
CrmService service;
public ListView(CrmService service) {
this.service = service;
addClassName("list-view");
setSizeFull();
configureGrid();
configureForm();
add(getToolbar(), getContent());
updateList();
closeEditor(); // (1)
}
private HorizontalLayout getContent() {
HorizontalLayout content = new HorizontalLayout(grid, form);
content.setFlexGrow(2, grid);
content.setFlexGrow(1, form);
content.addClassNames("content");
content.setSizeFull();
return content;
}
private void configureForm() {
form = new ContactForm(service.findAllCompanies(), service.findAllStatuses());
form.setWidth("25em");
}
private void configureGrid() {
grid.addClassNames("contact-grid");
grid.setSizeFull();
grid.setColumns("firstName", "lastName", "email");
grid.addColumn(contact -> contact.getStatus().getName()).setHeader("Status");
grid.addColumn(contact -> contact.getCompany().getName()).setHeader("Company");
grid.getColumns().forEach(col -> col.setAutoWidth(true));
grid.asSingleSelect().addValueChangeListener(event ->
editContact(event.getValue())); // (2)
}
private Component getToolbar() {
filterText.setPlaceholder("Filter by name...");
filterText.setClearButtonVisible(true);
filterText.setValueChangeMode(ValueChangeMode.LAZY);
filterText.addValueChangeListener(e -> updateList());
Button addContactButton = new Button("Add contact");
addContactButton.addClickListener(click -> addContact()); // (3)
var toolbar = new HorizontalLayout(filterText, addContactButton);
toolbar.addClassName("toolbar");
return toolbar;
}
public void editContact(Contact contact) { // (4)
if (contact == null) {
closeEditor();
} else {
form.setContact(contact);
form.setVisible(true);
addClassName("editing");
}
}
private void closeEditor() { // (1)
form.setContact(null);
form.setVisible(false);
removeClassName("editing");
}
private void addContact() { // (5)
grid.asSingleSelect().clear();
editContact(new Contact());
}
private void updateList() {
grid.setItems(service.findAllContacts(filterText.getValue()));
}
}
-
The
closeEditor()
call at the end of the constructor: sets the form contact tonull
, clearing out old values; hides the form; and removes the"editing"
CSS class from the view. -
addValueChangeListener()
adds a listener to the grid. TheGrid
component supports multi- and single-selection modes. You only need to select a singleContact
, so you can use theasSingleSelect()
method. ThegetValue()
method returns theContact
in the selected row, or null if there is no selection. -
Call
addContact()
when the user clicks on the "Add contact" button. -
editContact()
sets the selected contact in theContactForm
and hides or shows the form, depending on the selection. It also sets the"editing"
CSS class name when editing. -
addContact()
clears the grid selection and creates a newContact
.
Next, you’ll build the application. You should be able to select contacts in the grid and see them in the form. However, none of the buttons work yet.
Form Events
The ContactForm
API is designed to be reusable; it’s configurable through properties and it fires the necessary events. So far, you’ve passed a list of companies, the status, and the contact to the form. However, you need the application to listen for the events to complete the integration.
To handle event listeners, update configureForm()
and add saveContact()
and deleteContact()
methods.
private void configureForm() {
form = new ContactForm(service.findAllCompanies(), service.findAllStatuses());
form.setWidth("25em");
form.addSaveListener(this::saveContact); // (1)
form.addDeleteListener(this::deleteContact); // (2)
form.addCloseListener(e -> closeEditor()); // (3)
}
private void saveContact(ContactForm.SaveEvent event) { (1)
service.saveContact(event.getContact());
updateList();
closeEditor();
}
private void deleteContact(ContactForm.DeleteEvent event) { (2)
service.deleteContact(event.getContact());
updateList();
closeEditor();
}
-
The save event listener calls
saveContact()
. It usescontactService
to save the contact in the event to the database, updates the list, and closes the editor. -
The delete event listener calls
deleteContact()
. In the process, it also usescontactService
to delete the contact from the database, updates the list, and closes the editor. -
The close event listener closes the editor.
Build the application now and verify that you’re able to select, add, update, and delete contacts.
Making the Layout Responsive
Now if you try the UI with a mobile device or make your desktop browser really narrow, you see that the UI is not currently well optimized for small screens. It usually makes sense to hide certain UI elements for smaller screens. You can accomplish this using Java code or with CSS media queries.
This example uses CSS and utilize the class names previously assigned to the components. Add the following CSS to frontend/themes/flowcrmtutorial/styles.css
:
@media all and (max-width: 1100px) {
.list-view.editing .toolbar,
.list-view.editing .contact-grid {
display: none;
}
}
The CSS media query hides the grid and the toolbar when you are editing contacts on a narrow screen.
7ADFAE2F-44BD-4EE2-A8E1-E8B49581856B