Creating Content Dynamically Based on Item List
Warning
|
Polymer support has been deprecated since Vaadin 18 (released in November 2020), in favor of faster and simpler Lit templates. The built-in support for Polymer templates has been removed and is only available as a commercial add-on. However, a free conversion tool is available to assist in converting Polymer templates to Lit. Read more about setting up the commercial Polymer templates addon in the Upgrade Guide. |
Polymer allows you to generate elements based on a list of items using a template repeater (i.e., <dom-repeat>
element).
Below is an example using the <dom-repeat>
element in a JavaScript Polymer template:
class EmployeesList extends PolymerElement {
static get template() {
return html`
<table>
<tr on-click="processElement">
<th>Name</th><th>Title</th><th>Email</th>
</tr>
<dom-repeat items="[[employees]]">
<template>
<tr on-click="handleClick" id="[[item.name]]">
<td>[[item.name]]</td>
<td>[[item.title]]</td>
<td>[[item.email]]</td>
</tr>
</template>
</dom-repeat>
</table>
`;
}
static get is() {
return 'employees-list';
}
}
customElements.define(EmployeesList.is, EmployeesList);
The <dom-repeat>
element marks the content that’s generated for each item in a list. In this example, the table row, and everything inside the row element (i.e., <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 template given earlier would look similar to this when populated with a list of employees.
Name | Title | |
---|---|---|
John D |
| jd@foo.bar |
Jane D |
| janed@foo.bar |
Mike D |
| mikey@foo.bar |
See Element <dom-repeat>
in the Polymer documentation for more information on this.
Populating 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()
.
The example here defines the setEmployees()
method in the template model:
public class EmployeesTable extends PolymerTemplate<EmployeesModel> {
public interface EmployeesModel extends TemplateModel {
@Include({ "name", "title", "email" })
void setEmployees(List<Employee> employees);
List<Employee> getEmployees();
}
public void setEmployees(List<Employee> employees) {
getModel().setEmployees(employees);
}
public List<Employee> getEmployees() {
return getModel().getEmployees();
}
}
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
.
This example shows how to define corresponding getters in the Employee
class:
public class Employee {
private String name;
private String title;
private String email;
private long id;
public Employee(String name, String title, String email, long id) {
this.name = name;
this.title = title;
this.email = email;
}
public String getName() {
return name;
}
public String getTitle() {
return title;
}
public String getEmail() {
return email;
}
public void setName(String name) {
this.name = name;
}
public void setTitle(String title) {
this.title = title;
}
public void setEmail(String email) {
this.email = email;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
}
Note
| Setters aren’t 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 doesn’t work with the list property. This means that client-side changes to the list property aren’t sent to the server.
This next example shows how to define the addItem()
method in a JavaScript Polymer template:
class MyTemplate extends PolymerElement {
static get properties() {
return {
messages: {
type: Array,
value: () => [],
notify: true
}
};
}
addItem() {
this.push('messages', 'foo');
}
}
An update to the messages
property is not sent to the server when the addItem()
method is called.
Updating 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 doesn’t update the model.
To update the model items, you need to use the getEmployees()
method, which returns bean proxies that are connected to the model. Changes made to the proxy instance are reflected to the model.
You can see an example of updating the title for all items here:
public void updateTitle() {
getEmployees().forEach(employee -> employee.setTitle("Mr."));
}
Note
|
You can also use the setEmployees() method with a new list of updated beans to repopulate the model. This isn’t 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 to access the current item index.
The example here is using the @RepeatIndex
annotation in the @EventHandler
annotation:
@EventHandler
public void processElement(@RepeatIndex int itemIndex) {
System.out.println(getEmployees().get(itemIndex).getName());
}
There’s a limitation: The parameter type must be either int
or Integer
. See PolymerTemplate, Handling User Events for more about event handlers in Polymer templates.
04D34CDF-CF9E-4F63-B108-32B3100FB9C6