Creating Template Content Dynamically Based on a List of Items

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.

Polymer allows you to generate elements based on a list of items using a template repeater (<dom-repeat> element).

Example: Using the <dom-repeat> element in a JavaScript Polymer template.

Note
We are using the <template is=”dom-repeat”> syntax here, since the template is within a <table> element. See this Polymer issue for more details.

js

  1. class EmployeesList extends PolymerElement {
  2. static get template() {
  3. return html`
  4. <table>
  5. <tr on-click="processElement">
  6. <th>Name</th><th>Title</th><th>Email</th>
  7. </tr>
  8. <template is="dom-repeat" items="[[employees]]">
  9. <tr on-click="handleClick" id="[[item.name]]">
  10. <td>{{item.name}}</td>
  11. <td>{{item.title}}</td>
  12. <td>{{item.email}}</td>
  13. </tr>
  14. </template>
  15. </table>`;
  16. }
  17. static get is() {return 'employees-list'}
  18. }
  19. customElements.define(EmployeesList.is, EmployeesList);
  • The <dom-repeat> element marks the content that is generated for each item in a list. In this example, the table row and everything inside the row element (<tr>…​</tr>) is created for each item in the list.

  • The value of the items attribute declares the items to loop.

  • The item property is set on the binding scope of each instance, and templates should bind to sub-properties of item.

The above template would look similar to this when populated with a list of employees.

NameTitleEmail

John D

Developer

jd@foo.bar

Jane D

Designer

janed@foo.bar

Mike D

Architect

mikey@foo.bar

See Element <dom-repeat> in the Polymer documentation for more.

Populating the List of Items

To set the list of beans to display, you need to declare a method in the template’s model interface. The name of the method should match the name in the dom-repeat definition, for example to set data for [[employees]] the method name should be setEmployees.

Example: Defining the setEmployees method in the template model.

Java

  1. public class EmployeesTable extends PolymerTemplate<EmployeesModel> {
  2. public interface EmployeesModel extends TemplateModel {
  3. @Include({ "name", "title", "email" })
  4. void setEmployees(List<Employee> employees);
  5. List<Employee> getEmployees();
  6. }
  7. public void setEmployees(List<Employee> employees) {
  8. getModel().setEmployees(employees);
  9. }
  10. public List<Employee> getEmployees() {
  11. return getModel().getEmployees();
  12. }
  13. }
  • The @Include annotation is used to limit the properties imported into the model. This excludes the id property that has an unsupported type. You can also use the @Exclude("id") annotation, as an alternative in this case.

The Employee bean should have getters that correspond with the properties used in the <dom-repeat> definition in the template, for example getName() for employee.name.

Example: Defining corresponding getters in the Employee class.

Java

  1. public class Employee {
  2. private String name;
  3. private String title;
  4. private String email;
  5. private long id;
  6. public Employee(String name, String title, String email, long id) {
  7. this.name = name;
  8. this.title = title;
  9. this.email = email;
  10. }
  11. public String getName() {
  12. return name;
  13. }
  14. public String getTitle() {
  15. return title;
  16. }
  17. public String getEmail() {
  18. return email;
  19. }
  20. public void setName(String name) {
  21. this.name = name;
  22. }
  23. public void setTitle(String title) {
  24. this.title = title;
  25. }
  26. public void setEmail(String email) {
  27. this.email = email;
  28. }
  29. public long getId() {
  30. return id;
  31. }
  32. public void setId(long id) {
  33. this.id = id;
  34. }
  35. }
Note
Setters are not required here. The template engine uses only the getter to fetch values from the employee beans.

List property updates are propagated only from the server to the client side. Two-way data binding does not work with the list property. This means that client side changes to the list property are not sent to the server.

Example: Defining the addItem method in a JavaScript Polymer template.

JavaScript

  1. class MyTemplate extends PolymerElement {
  2. static get properties() {
  3. return {
  4. messages: {
  5. type: Array,
  6. value: [],
  7. notify: true
  8. }
  9. };
  10. }
  11. addItem() {
  12. this.push('messages', 'foo');
  13. }
  14. }
  • An update to the messages property will NOT be sent to the server when the addItem method is called.

Updating the Items

Beans added to the model using the setEmployees() method are used to populate the model only. This means that any update to a bean does not update the model.

To update the model items, you need to use the getEmployees() method that returns bean proxies that are connected to the model. Changes made to the proxy instance are reflected to the model.

Example: Updating the title for all items.

Java

  1. public void updateTitle() {
  2. getEmployees().forEach(employee -> employee.setTitle("Mr."));
  3. }
Note
You can also use the setEmployees() method with a new list of updated beans to repopulate the model. This is not convenient if you want to update only a single item or a single property.

Accessing Item Indices

The JavaScript Polymer template (top of the page) includes the client-side on-click="processElement" event handler.

You can use the @RepeatIndex annotation in the @EventHandler annotation to define a shorthand for accessing the current item index.

Example: Using the @RepeatIndex annotation in the @EventHandler annotation.

Java

  1. @EventHandler
  2. public void processElement(@RepeatIndex int itemIndex) {
  3. System.out.println(getEmployees().get(itemIndex).getName());
  4. }
  • There is a limitation: the parameter type must be either int or Integer.

See Handling User Events in a Template for more about event handlers in Polymer templates.