In Vaadin CRM demo (https://vaadin.com/docs/latest/flow/tutorials/in-depth-course), I try to create a abstract form class for ContactForm to inheritance from. Here is the code:
public abstract class AbstractForm<T> extends FormLayout {
public T entity;
Binder<T> binder;
Button save = new Button("Save");
Button delete = new Button("Delete");
Button close = new Button("Cancel");
protected Component createButtonsLayout() {
save.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
delete.addThemeVariants(ButtonVariant.LUMO_ERROR);
close.addThemeVariants(ButtonVariant.LUMO_TERTIARY);
save.addClickShortcut(Key.ENTER);
close.addClickShortcut(Key.ESCAPE);
save.addClickListener(event -> validateAndSave());
delete.addClickListener(event -> fireEvent(new DeleteEvent(this, entity)));
close.addClickListener(event -> fireEvent(new CloseEvent(this)));
binder.addStatusChangeListener(e -> save.setEnabled(binder.isValid()));
return new HorizontalLayout(save, delete, close);
}
protected void validateAndSave() {
try {
binder.writeBean(entity);
fireEvent(new SaveEvent(this, entity));
} catch (ValidationException e) {
e.printStackTrace();
}
}
public <E extends ComponentEvent<?>> Registration addListener(Class<E> eventType, ComponentEventListener<E> listener) {
return getEventBus().addListener(eventType, listener);
}
public void setEntity(T entity) {
this.entity = entity;
binder.readBean(entity);
}
public abstract class EntityFormEvent extends ComponentEvent<AbstractForm<T>> {
private final T entity;
protected EntityFormEvent(AbstractForm source, T entity) {
super(source, false);
this.entity = entity;
}
public T getEntity() {
return entity;
}
}
public class SaveEvent extends EntityFormEvent {
SaveEvent(AbstractForm source, T entity) {
super(source, entity);
}
}
public class DeleteEvent extends EntityFormEvent {
DeleteEvent(AbstractForm source, T entity) {
super(source, entity);
}
}
public class CloseEvent extends EntityFormEvent {
CloseEvent(AbstractForm source) {
super(source, null);
}
}
}
public class ContactForm extends AbstractForm<Contact> {
TextField firstName = new TextField("First name");
TextField lastName = new TextField("Last name");
EmailField email = new EmailField("Email");
ComboBox<Status> status = new ComboBox<>("Status");
ComboBox<Company> company = new ComboBox<>("Company");
Binder<Contact> binder = new BeanValidationBinder<>(Contact.class);
public ContactForm(List<Company> companies, List<Status> statuses) {
addClassName("contact-form");
binder.bindInstanceFields(this);
company.setItems(companies);
company.setItemLabelGenerator(Company::getName);
status.setItems(statuses);
status.setItemLabelGenerator(Status::getName);
add(firstName,
lastName,
email,
company,
status,
createButtonsLayout());
}
}
@Component
@Scope("prototype")
@Route(value="", layout = MainLayout.class)
@PageTitle("Contacts | Vaadin CRM")
@PermitAll
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();
form = new ContactForm(service.findAllCompanies(), service.findAllStatuses());
form.setWidth("25em");
form.addListener(ContactForm.SaveEvent.class, this::saveContact);
form.addListener(ContactForm.DeleteEvent.class, this::deleteContact);
form.addListener(ContactForm.CloseEvent.class, e -> closeEditor());
FlexLayout content = new FlexLayout(grid, form);
content.setFlexGrow(2, grid);
content.setFlexGrow(1, form);
content.setFlexShrink(0, form);
content.addClassNames("content", "gap-m");
content.setSizeFull();
add(getToolbar(), content);
updateList();
closeEditor();
grid.asSingleSelect().addValueChangeListener(event ->
editContact(event.getValue()));
}
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));
}
private HorizontalLayout 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());
HorizontalLayout toolbar = new HorizontalLayout(filterText, addContactButton);
toolbar.addClassName("toolbar");
return toolbar;
}
private void saveContact(ContactForm.SaveEvent event) {
service.saveContact(event.getEntity());
updateList();
closeEditor();
}
private void deleteContact(ContactForm.DeleteEvent event) {
service.deleteContact(event.getEntity());
updateList();
closeEditor();
}
public void editContact(Contact contact) {
if (contact == null) {
closeEditor();
} else {
form.setEntity(contact);
form.setVisible(true);
addClassName("editing");
}
}
void addContact() {
grid.asSingleSelect().clear();
editContact(new Contact());
}
private void closeEditor() {
form.setEntity(null);
form.setVisible(false);
removeClassName("editing");
}
private void updateList() {
grid.setItems(service.findAllContacts(filterText.getValue()));
}
}
I keep getting "incompatible types: cannot infer functional interface descriptor for com.vaadin.flow.component.ComponentEventListener" on build error.