Using Binder with Polymer Templates

Note
Use Lit templates instead
Lit templates are recommended. Polymer templates are available in the next long term supported Vaadin version (LTS), but they are deprecated.

Binder is a server-side construct and you can therefore not use it in a Polymer template. It is, however, possible to create a form using the PolymerTemplate API and to connect the component to a Binder. The process is similar to using binders with declared components.

In this section, we demonstrate how to create a fully-functional template-binder view.

Creating the Polymer Template Component

The first step is to create the JavaScript Polymer template and its mapped Java class.

Example: Creating the user-form JavaScript Polymer template.

js

  1. import {PolymerElement, html} from '@polymer/polymer/polymer-element.js';
  2. import '@vaadin/vaadin-form-layout/vaadin-form-layout.js';
  3. import '@vaadin/vaadin-text-field/vaadin-text-field.js';
  4. import '@vaadin/vaadin-text-field/vaadin-text-area.js';
  5. import '@vaadin/vaadin-checkbox/vaadin-checkbox.js';
  6. import './form-buttons-bar.js'
  7. class UserForm extends PolymerElement {
  8. static get template() {
  9. return html`
  10. <style>
  11. </style>
  12. <vaadin-form-layout id="form">
  13. <vaadin-text-field id="email" label="Email (login)" colspan="2"></vaadin-text-field>
  14. <vaadin-text-field id="first-name" label="First Name"></vaadin-text-field>
  15. <vaadin-text-field id="last-name" label="Last Name"></vaadin-text-field>
  16. <vaadin-text-area id="comments" label="Comments"></vaadin-text-area>
  17. </vaadin-form-layout>
  18. <form-buttons-bar id="action-buttons"></form-buttons-bar>`;
  19. }
  20. static get is() {
  21. return 'user-form';
  22. }
  23. }
  24. customElements.define(UserForm.is, UserForm);

Example: Creating the mapped UserForm Java template class.

Java

  1. @Tag("user-form")
  2. @JsModule("./src/user-form.js")
  3. public class UserForm extends PolymerTemplate < UserForm.FormComponentModel > {
  4. @Id("email")
  5. private TextField email;
  6. @Id("first-name")
  7. private TextField firstName;
  8. @Id("last-name")
  9. private TextField lastName;
  10. @Id("comments")
  11. private TextArea comment;
  12. @Id("action-buttons")
  13. private FormButtonsBar actionButtons;

Creating and Linking the Binder

Next, we create and link the binder.

We start by declaring the binder as a class variable in the UserForm class.

Example: Declaring the binder in the UserForm class.

Java

  1. private Binder<User> binder;

Next, we create the initBinder method that initializes the binder and links it to the fields in the form.

Example: Creating the initBinder method and linking it to the form fields.

Java

  1. private void initBinder() {
  2. binder = new Binder<>();
  3. // email
  4. binder.forField(email).withValidator(
  5. new EmailValidator("This doesn't look like a valid email address")
  6. ).bind(User::getEmail, User::setEmail);
  7. // firstName
  8. binder.forField(firstName).withValidator(firstName -> firstName.length() > 1,
  9. "The first name must contains at least 2 characters").asRequired()
  10. .bind(User::getFirstName, User::setFirstName);
  11. // lastName
  12. binder.forField(lastName).asRequired("Last name can't be empty")
  13. .bind(User::getLastName, User::setLastName);
  14. // comment
  15. binder.forField(comment).bind(User::getComment, User::setComment);
  16. }

See Binding Data to Forms for more.

We can now call the initBinder method inside the constructor of the class.

Example: Calling initBinder in the UserForm class.

Java

  1. public UserForm() {
  2. initBinder();
  3. }

Declaring Methods to Get and Set User Objects

Now that the binding process is complete, we can declare methods to get and set user objects in the form.

Example: Declaring methods to set, remove and get User beans in the UserForm class.

Java

  1. /**
  2. * Connects the bean to the binder.
  3. *
  4. * @param user bean
  5. */
  6. public void setBean(User user) {
  7. binder.setBean(user);
  8. }
  9. /**
  10. * Clears the form and disconnnect any bean.
  11. */
  12. public void removeBean() {
  13. binder.removeBean();
  14. }
  15. /**
  16. * Gets the binder of the UserForm
  17. *
  18. * @return binder it binds the fields of an object to the fields shown
  19. */
  20. public Optional<User> getBean() {
  21. return Optional.of(binder.getBean());
  22. }
  • An unbuffered binding is used.
Note
  • Unbuffered binding: The binder keep a reference to the bean: every time the user changes a value, it is immediately validated and written to the bean object.

  • Buffered binding: Changes are not written to the bean until this is explicitly specified.

See Loading From and Saving To Business Objects for more.

Using the UserForm Component

The UserForm component is now ready for use in other parts of your code.

Creating the Main View

First, we create the MainView Polymer template component. This component displays a grid of users and our new UserForm component. For the grid, we use the Vaadin Grid component

Here is the result.

MainView

Example: Creating the main-view JavaScript Polymer template.

js

  1. import {PolymerElement, html} from '@polymer/polymer/polymer-element.js';
  2. import '@vaadin/vaadin-grid/vaadin-grid.js'
  3. import './user-form.js';
  4. class MainView extends PolymerElement {
  5. static get template() {
  6. return html`
  7. <style>
  8. </style>
  9. <div id="main-container">
  10. <vaadin-grid id="users-grid"></vaadin-grid>
  11. <user-form id="user-form"></user-form>
  12. </div>`;
  13. }
  14. static get is() {
  15. return 'main-view';
  16. }
  17. }
  18. customElements.define(MainView.is, MainView);

Example: Creating the mapped MainView Java template class.

Java

  1. @Tag("main-view")
  2. @JsModule("./src/main-view.js")
  3. @Route("")
  4. public class MainView extends PolymerTemplate<TemplateModel> {
  5. @Id("user-form")
  6. private UserForm userForm;
  7. @Id("users-grid")
  8. private UsersGrid usersGrid;
  9. }

Initializing the MainView Component

Next, we configure the components and binder, and initialize their listeners in the MainView class.

Example: Initializing the MainView component and its component’s listeners.

MainView.class

  1. /**
  2. * Initializes the Main view and the listeners of its components.
  3. */
  4. public MainView() {
  5. // selection listener on the rows of the grid.
  6. usersGrid.addSelectionListener(selectionEvent -> {
  7. Optional<User> optionalUser = usersGrid.getSelectedItems().stream().findAny();
  8. if (optionalUser.isPresent()) {
  9. userForm.setBean(optionalUser.get());
  10. setEditionEnabled(true);
  11. } else {
  12. userForm.removeBean();
  13. setEditionEnabled(false);
  14. }
  15. });
  16. initFormListeners();
  17. }

Implementing Save, Cancel and Delete Listeners

The final step is to implement listeners for the Save, Cancel and Delete buttons in the initFormListener.

Example: Implementing the save listener in the MainView class.

Java

  1. formButtonsBar.addSaveListener(saveEvent -> {
  2. // it checks that all validators defined in the form pass without error.
  3. if (!userForm.getBinder().validate().isOk()) {
  4. return;
  5. }
  6. Optional<User> optionalUser = userForm.getBean();
  7. if (optionalUser.isPresent()) {
  8. User user = optionalUser.get();
  9. user = UsersRepository.save(user);
  10. usersGrid.refresh(user);
  11. userForm.setBean(user); // update the data in the form
  12. }
  13. });
  • The code first checks the state of the bean.

  • If correct, it generates a user object from the userForm.

  • The user is then saved calling a method of the repository.

  • The item in the grid is refreshed to show the changes.

Note
For buffered binding, you would need to call binder.writeBean().
Note
  • Unbuffered binding: When you use the setBean method (unbuffered binding), validation is triggered automatically on all change events.

  • Buffered binding: When you use the readBean and writeBean methods (buffered binding), validation is not triggered automatically.

Example: Implementing the cancel listener in the MainView class.

MainView.initFormListeners

  1. formButtonsBar.addCancelListener(cancelEvent -> {
  2. usersGrid.deselectAll();
  3. });
  • All the elements of the grid are deselected and the form is emptied.

  • Deselection of a row triggers an event that removes the bean. See the usersGrid.addSelectionListener implementation in the previous section.

Example: Implementing the delete listener in the MainView class.

Java

  1. formButtonsBar.addDeleteListener(deleteEvent -> {
  2. Optional<User> optionalUser = usersGrid.getSelectedItems().stream().findAny();
  3. if (optionalUser.isPresent()) {
  4. UsersRepository.delete(optionalUser.get());
  5. usersGrid.deselectAll();
  6. usersGrid.refreshAll();
  7. }
  8. });
  • The user is selected from the grid, removed calling UsersRepository.delete, and the user (bean) is removed from the UserForm.

  • When a user (bean) is removed, the fields of the UserForm are cleared.

Viewing the Final Result

Note:

  • When you select a row, the user’s information displays in the form fields.

  • When you click Save, changes to the user’s information are saved.

  • When you click Delete, the user is deleted from the form and the grid.

MainView