Docs

Documentation versions (currently viewingVaadin 24)

Polymer support is deprecated. Use Lit templates instead.

Using Model Encoders

Polymer support is deprecated; use Lit templates instead.
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.

Template model and model data aren’t supported for Lit templates. You may use directly, though, component API and properties via the Element API to achieve the same functionality.

Using ready-made beans in your model can be challenging if you have no control over their properties — because, for example, they’re provided as binary class files — or their structure is inappropriate for your template model.

Encoding Property Types

You can use the @Encode annotation to encode any property type to a supported type.

A common use case is a database backend with JPA entities that have Long type identifiers. Vaadin doesn’t support the Long type because it can’t be mapped correctly to any JavaScript type.

One solution is to exclude any property of this type using the @Exclude annotation. See PolymerTemplate, Using Model Beans for an example of how to use this annotation.

Alternatively, you can use the @Encode annotation. This is useful when you need a bean property with this identifier on the client side for any reason, perhaps to reference it. In such circumstances, the @Encode annotation encodes the Long value to a String value and sends it to the client side as a string. When the client sends the value back, it’s decoded back to a Long.

The example here defines the Person JPA entity class using the @Encode annotation in the template model class:

@Entity
public class Person implements Serializable {
    @Id
    @GeneratedValue
    private Long id;

    public Long getId() {
        return id;
    }

}

public interface MyModel extends TemplateModel {
   @Encode(value = LongToStringEncoder.class, path = "id")
   void setPerson(Person person);
   Person getPerson();
}

The @Encode annotation parameter path = "id" is used to address the id sub-property of the person property. By default, the path value is "", which means that an encoder is applied to the property itself, in this case the Person.

This example uses the LongToStringEncoder encoder:

public class LongToStringEncoder implements ModelEncoder<Long, String> {

    @Override
    public String encode(Long modelValue) {
        return Optional.ofNullable(modelValue).map(Object::toString)
                .orElse(null);
    }

    @Override
    public Long decode(String presentationValue) {
        return Optional.ofNullable(presentationValue).map(Long::valueOf)
                .orElse(null);
    }

}

You can access the id property of the Person bean in your code on the client side in the usual way. It’s of the String type, instead of a number.

Using Encoders to Split Property Values

An encoder can also be used to split a single property value into several sub-properties to use them in different UI controls. For instance, you may want to have three input fields (i.e., day, month, and year) for a birth date field, instead of one.

This example is using the @Encode annotation to define the Date property in a template model:

public interface MyModel extends TemplateModel {

    Date getBirthDate();

    @Encode(DateToDateBeanEncoder.class)
    void setBirthDate(Date birthDate);
}

This next example defines the DateBean class:

public class DateBean implements Serializable {

    private String day;
    private String month;
    private String year;

    public String getDay() {
        return day;
    }

    public void setDay(String day) {
        this.day = day;
    }

    public String getMonth() {
        return month;
    }

    public void setMonth(String month) {
        this.month = month;
    }

    public String getYear() {
        return year;
    }

    public void setYear(String year) {
        this.year = year;
    }

}

This one is defining the DateToDateBeanEncoder encoder class:

public class DateToDateBeanEncoder implements ModelEncoder<Date, DateBean> {

    @Override
    public DateBean encode(Date modelValue) {
        if (modelValue == null) {
            return null;
        }
        DateBean bean = new DateBean();
        Calendar calendar = GregorianCalendar.getInstance();
        calendar.setTime(modelValue);
        bean.setDay(Integer.toString(calendar.get(Calendar.DAY_OF_MONTH)));
        bean.setMonth(Integer.toString(calendar.get(Calendar.MONTH) + 1));
        bean.setYear(Integer.toString(calendar.get(Calendar.YEAR)));
        return bean;
    }

    @Override
    public Date decode(DateBean presentationValue) {
        if (presentationValue == null) {
            return null;
        }
        int year = Integer.parseInt(presentationValue.getYear());
        int day = Integer.parseInt(presentationValue.getDay());
        int month = Integer.parseInt(presentationValue.getMonth()) - 1;
        Calendar calendar = GregorianCalendar.getInstance();
        calendar.set(year, month, day);
        return calendar.getTime();
    }

}

The Date property is encoded to three sub-properties: day, month, and year.

You can see this example is using the sub-properties in a JavaScript Polymer template (i.e., snippet only):

static get template() {
  return html`
    <div style="width: 200px;">
      <label>Birth date:</label>
      <label for="day">Enter your birthday:</label><paper-input id="day" value="{{birthDate.day}}"></paper-input>
      <label for="month">Enter the month of your birthday:</label><paper-input id="month" value="{{birthDate.month}}"></paper-input>
      <label for="year">Enter the year of your birthday:</label><paper-input id="year" value="{{birthDate.year}}"></paper-input>
      <button on-click="commit" id="commit">Commit</button>
    </div>
  `;
}

Each of the three sub-properties (day, month, and year) has its own editor. On the server side, though, it’s still one property, birthDate. You need to use your original property name (birthDate in this example — not dateBean — as a prefix to access the sub-properties.

61E9D5CF-4BBB-4EEC-A065-238749537BA3