Creation of a UI with linkki

Create a UI from the Presentation Model Object (PMO)

A UI is built using different component containers, in HTML typically represented by a <div>. In linkki as in Vaadin we call these component containers layouts. Every layout is represented by a PMO, short for presentation model object. A PMO is primarily a simple POJO that is annotated with special linkki annotations. For every component in the layout, a bean property (represented by a getter and setter method) is defined within this PMO.

When a class is annotated with a layout annotation like @UISection, linkki takes control over the creation and arrangement of the defined components. Using annotations for the UI elements, certain aspects can be defined or controlled. The layouts are created using the VaadinUiCreator.

The UI elements are bound either to the 'properties' of a ModelObject or a PMO. A detailed description can be found in the chapter Data on Multiple Layers.

In all cases, if the ModelObject or PMO doesn’t have a corresponding setter, the field is readOnly.

The following examples describe how to create a standard forms section, followed by an example of how to create a table section. There are some more available layout annotations and it is quite easy to write a custom layout annotation.

Creating a Form Section

Binding with @ModelObject
@UISection
public class ContactSectionPmo {

    private Contact contact;
    @ModelObject
    public Contact getContact() {
        return contact;
    }

    @BindTooltip(tooltipType = TooltipType.DYNAMIC)
    @UITextField(position = 10, label = "Firstname", required = RequiredType.REQUIRED, modelAttribute = Contact.PROPERTY_FIRSTNAME)
    public void firstname() {
        /* model binding only */
    }

    public String getFirstnameTooltip() {
        return "First name";
    }

    @BindTooltip(tooltipType = TooltipType.DYNAMIC)
    @UITextField(position = 20, label = "Lastname", required = RequiredType.REQUIRED, modelAttribute = Contact.PROPERTY_LASTNAME)
    public void lastname() {
        /* model binding only */
    }

    public String getLastnameTooltip() {
        return "Last name";
    }

    @UIRadioButtonGroup(position = 30, label = "Gender", buttonAlignment = AlignmentType.HORIZONTAL, content = AvailableValuesType.ENUM_VALUES_EXCL_NULL, //
            itemCaptionProvider = GenderCaptionProvider.class, modelAttribute = Contact.PROPERTY_GENDER)
    public void gender() {
        /* model binding only */
    }

    @UIComboBox(position = 40, label = "Country of Birth", //
            content = AvailableValuesType.DYNAMIC, itemCaptionProvider = ToStringCaptionProvider.class, //
            modelAttribute = Contact.PROPERTY_COUNTRY_OF_BIRTH)
    public void countryOfBirth() {
        /* model binding only */
    }

    public List<String> getCountryOfBirthAvailableValues() {
        return Arrays.asList(Locale.getAvailableLocales()).stream()
                .map(l -> l.getDisplayCountry(UiFramework.getLocale()))
                .distinct()
                .sorted()
                .collect(Collectors.toList());
    }

    @UICheckBox(position = 50, caption = "Add to favorites", modelAttribute = Contact.PROPERTY_FAVORITE)
    public void favorite() {
        /* model binding only */
    }

}
The definition of modelAttribute is optional if the property name in the ModelObject and the name of the annotated method are equal. But it is recommended to specify the modelAttribute to make it explicit. The value should be externalized to a constant in the target model object as seen for the lastname property.

Creating a Table Section

To create a section with a table the PMO class must implement org.linkki.core.defaults.columnbased.pmo.ContainerPmo<ROW>. The generic parameter ROW represents the type of the PMO to create a row in this table.

public class ContactTablePmo implements ContainerPmo<ContactRowPmo> {

The method getItems() returns the rows of the table in the form of the previously defined ROW 'row PMOs'.

    @Override
    public List<ContactRowPmo> getItems() {
        return items.get();
    }

In the interface ContainerPmo<ROW> additional default methods are defined. A detailed description can be found in the section about ContainerPmo.

The so called 'Row PMO' is a regular PMO as described in the first section. The only difference is that the UI elements may optionally be annotated with @UITableColumn.

    @UITableColumn(expandRatio = 1F)
    @UILabel(position = 10, label = "Name")
    public String getName() {
        return contact.getName();
    }

All UI elements can be used in tables. The binding of a @UIButton looks as follows:

    @UITableColumn(width = 50)
    @BindTooltip("Edit")
    @UIButton(position = 30, icon = VaadinIcons.EDIT, showIcon = true)
    public void edit() {
        editAction.accept(contact);
    }
In our example the elements of the table shall be presented as read-only. Therefore no direct binding of the ModelObject via the @ModelObject annotation is done. If the items of your table are provided from a model object you may consider to use org.linkki.core.defaults.columnbased.pmo.SimpleTablePmo<MO, ROW> which is described in chapter Tables in detail.