UI Components

Aspects

linkki can bind more than just the value. In fact, almost every part of the UI state can be taken into account for data binding with linkki. The most common parts of the UI state are for example the enabled state or the visibility. But there are also additional features that may be bound to a component such as the tooltip, available values for selection or CSS class names. For a property, every such UI state part is a so called aspect of the property.

Some aspects are crucial for the functionality of the UI element and are thus directly embedded in the annotation. Besides those, linkki also provides some standalone aspect annotations that can be optionally applied to the UI elements.

Aspects in a PMO

The following example shows two aspects for the property "name".

Value and enabled aspect
    @UITextField(position = 1, label = "Name", enabled = DYNAMIC)
    public String getName() {
        return partner.getName();
    }

    public void setName(String name) {
        partner.setName(name);
    }

    public boolean isNameEnabled() {
        return partner.getType() == PartnerType.NATURAL_PERSON;
    }

The most important aspect is the value aspect. It is also mandatory for the data binding to function. The value aspect is dynamically determined by the getter and setter methods of the property. As the value aspect is critical for the UI element to function, it is always embeded in the UI element annotation.

The second aspect that can be seen is the enabled aspect. This state is defined by the method isNameEnabled.

Each aspect has a name. The enabled aspect has the name "enabled" whereas the value aspect has the empty String as name. In general, the state of the aspect "aspect" for property "property" is determined by the method is/get<Property><Aspect> and set<Property><Aspect>.

Aspects can also apply to the whole PMO if it is also bound to a UI component. In this case, the property name is the empty string.

Aspect on PMO class
@BindStyleNames
@UISection(caption = "Partner")
public class PartnerSectionPmo {

    public List<String> getStyleNames() {
        if (partner.getType() == PartnerType.NATURAL_PERSON) {
            return Arrays.asList("naturalperson");
        } else {
            return Collections.emptyList();
        }
    }
}

Commonly Embedded Aspects

Some aspects are so important or commonly used that they are directly packaged with the UI annotation. Many of those aspects offer configurations that can be set by attributes in the annotation. Most frequently, the attributes share the name of the aspect itself, e.g. @UITextField(enabled = …​) in case of the enabled aspect.

Below are the commonly embedded aspects.

Label

Usually there is a label text for each UI element, that describes the element. The content of the label is defined by this attribute.

Exceptions to this are elements whose main feature is their text, such as buttons, checkboxes and links. These UI elements usually do not need a preceding label. Instead, the description of a button is displayed on the button itself, the description of a link is displayed as the link text, while the description of the checkbox is commonly displayed at the right of the checkbox. This kind of describing element can be configured with the property caption in those annotations. Buttons, links and checkboxes can still be configured with a label additionally by overwriting the label property.

If no label/caption is set, the default value "derived.by.linkki" kicks in and linkki uses the default as determined by the PropertyDispatchers (usually the capitalized property name) as label/caption.

The label is used as the column caption in tables.

If an independent label is needed, the UI element UILabel can be used.
Enabled

The property enabled controls whether a component is enabled or disabled. The following configuration options are available:

Table 1. EnabledType

ENABLED

The content of the element is modifiable in the UI (default)

DISABLED

The content of the element is not modifiable in the UI

DYNAMIC

Whether the content is modifiable is controlled by the return value of the method boolean is<PropertyName>Enabled()

Some components like UILabel and UILink do not offer these options and are always enabled.
Visible

The property visible controls whether the component is visible. There are the following configuration options:

Table 2. VisibleType

VISIBLE

The UI element is visible (default)

INVISIBLE

The UI element is invisible

DYNAMIC

Whether the UI element is visible is controlled by the return value of thte method boolean is<PropertyName>Visible()

Required

The property required visually highlights required fields. The following configuration options are available:

Table 3. RequiredType

REQUIRED

The UI element requires input (a value must be entered/selected)

REQUIRED_IF_ENABLED

The UI element requires input if it is enabled

NOT_REQUIRED

Input in the UI element is optional (default)

DYNAMIC

Whether the element requires input is controlled by the return value of the method boolean is<PropertyName>Required()

UILabels, UILinks and UIButtons do not offer these options and are never required.
Fields marked as required are only visually highlighted. No validation is performed.

Standalone Apsect Annotations

Aspects can also be represented by a separate annotation. In this case, those annotations follow the naming convention @Bind[AspectName]. A standalone aspect annotation can be added to an annotated PMO property. Some standalone aspect annotation can also be added to an annotated PMO class itself. In the case of binding using the @Bind annotation, @Bind[AspectName] must be written directly in the field annotated with @Bind. Several frequently used aspects are packaged with linkki as listed below. It is also very easy to create additional custom aspect annotations.

Standalone Annotation Description

@BindTooltip

Tooltip handling, using default TooltipType.AUTO

@BindReadOnly

Bind a component’s read-only property. Exclusive to Components of type HasValue

@BindReadOnlyBehavior

Automatically change enabled or visible behavior when in read-only mode.

@BindVisible

Visiblity handling, using default VisibleType.DYNAMIC

@BindStyleNames

Provide style class names for a component

@BindCaption

Caption handling, using default CaptionType.AUTO

@BindIcon

Icon handling, using default IconType.AUTO

@BindSuffix

Suffix handling, using default SuffixType.AUTO

@BindPlaceholder

Placeholder handling, using default PlaceholderType.AUTO

Tooltips

For displaying tooltips on UI elements linkki provides the annotation @BindTooltip.

The @BindTooltip annotation has two properties:

Value

This is the text displayed on TooltipType.STATIC. Its default value is an empty string ("").

TooltipType

The following configuration options are available for TooltipType:

Table 4. TooltipType

AUTO

The text of the tooltip is read from the attribute value if it is not empty, otherwise it reacts like DYNAMIC (default)

STATIC

The text of the tooltip is read from the attribute value

DYNAMIC

The text of the tooltip is determined by the return value of the method String get<PropertyName>Tooltip(). The value is ignored.

Tooltips can only be added to fields and buttons.
    @BindTooltip("Edit")
    @UIButton(position = 30, icon = VaadinIcon.EDIT, showIcon = true, caption = "", variants = ButtonVariant.LUMO_TERTIARY_INLINE)
    public void edit() {
        editAction.accept(contact);
    }
Bind Read-Only State

To change a component’s read-only behavior, linkki provides the annotation @BindReadOnly. This annotation can be used in combination with @Bind or UI-annotations.

The @BindReadOnly annotation is evaluated after @Bind or @UI-annotations which might already have set a read-only state.
This annotation should be used only in exceptional cases, since most of the behavior is better controlled by a PropertyBehavior.

The @BindReadOnly Annotation has only one property, ReadOnlyType. Per default, ReadOnlyType#ALWAYS is selected. Following ReadOnlyTypes are available:

Table 5. ReadOnlyType

ALWAYS

The component is always read-only (default).

DYNAMIC

The read-only behavior of the component is determined by the return value of the method is<PropertyName>ReadOnly().

DERIVED

The component is read-only if no setter method exists or the property dispatcher returns read-only for this property.

If a component is supposed to be writable even though the rest of the UI is in read-only-mode, use @BindReadOnlyBehavior with value ACTIVE, e.g. an input field to filter the content of a table.
Bind Read-Only Behavior

@BindReadOnlyBehavior changes a component’s behaviour if it is set to read-only. The read-only status is determined by the property-dispatcher-chain. There is no need to define additional methods as is usually the case with dynamic aspect definitions.

The aspect has a value of type ReadOnlyBehaviorType with the following options available:

Table 6. ReadOnlyBehaviorType

INVISIBLE

Component is invisible in read-only mode. This type is the default value.

DISABLED

Component is visible but disabled in read-only mode.

WRITABLE

Component remains writable in read-only mode.

INVISIBLE_IF_WRITABLE

Component is invisible in writable mode.

INVISIBLE and DISABLED are especially useful for buttons as buttons do not have a read-only mode. The type WRITABLE is useful for components which do not change data like an input field that is used to filter the content in the user interface.
INVISIBLE_IF_WRITABLE can be used for buttons which should only be visible in read-only mode.
INVISIBLE, DISABLED, INVISIBLE_IF_WRITABLE are only supported for buttons yet. WRITABLE can only be used on UI elements which implement HasValue.
Bind Visible

@BindVisible changes a component’s visibility from the PMO by invoking a method named is[PropertyName]Visible().

The aspect has a default value of type VisibiltyType with the option DYNAMIC. Using this annotation, it is no longer necessary to specify the visible property with VisibleType.DYNAMIC in components, e.g. @UILabel.

Style Names

Vaadin components get rendered as HTML and styled via CSS. Using the @BindStyleNames annotation custom style names can be bound to a component in addition to those provided by Vaadin.

A single style name can be provided as the annotation’s value (@BindStyleNames("foo")) as well as an array of multiple style names (@BindStyleNames({"bar", "baz"})).

The value can also be omitted, leading to dynamic resolution via a get<Property>StyleNames() method that may return a String or any Collection<String>.

This aspect is an inherited aspect if it is declared on a class. Style names defined in the inheritance hierarchy are all added to the component.
Combo Box Item Style

With the @BindComboBoxItemStyle annotation it is possible to style the items in a combo box popup menu. The annotation can only be used in conjunction with the annotation @UIComboBox.

The CSS style names can be specified directly in the annotation and then apply to all items.

Alternatively, the annotation can be specified without style names, in which case a method named get<Property>ItemStyle() is called with return type Function<TYPE, String>. The type TYPE must correspond to the type of the items in the combo box. The function is called for each item in the combo box. This makes it possible to define different styles for individual items.

@BindComboBoxDynamicCaption

By default, the caption of an item is only updated if the item itself changes. If the caption of an item can change without the item itself being changed, the combo box should be additionally be annotated with @BindComboBoxDynamicCaption. This annotation makes sure that all items are updated including their caption upon updates.

The update of all items can be costly, especially if the combo box contains a large number of items.
Caption

For sections and applicable fields(e.g. UICheckbox, UIButton), the caption can be set with the separate @BindCaption annotation.

The @BindCaption annotation has two properties:

Value

This is the text displayed on CaptionType.STATIC. Its default value is an empty string ("").

CaptionType

The following configuration options are available for CaptionType:

Table 7. CaptionType

AUTO

Reacts as DYNAMIC if value is empty or STATIC if it is not empty (default)

STATIC

The caption is read from the attribute value

DYNAMIC

The caption is determined by the return value of the method String get<PropertyName>Caption(). The value is ignored.

NONE

Explicitly set the caption to null

Icon

UI elements such as @UIButton or @UILink can have an icon that is shown with the component’s caption. This can be set with the @BindIcon annotation.

The @BindIcon annotation has two properties:

Value

This is the icon displayed on IconType.STATIC. Its default value is a smiley that should alarm the user in case of unintentional usage.

IconType

The following configuration options are available for IconType:

Table 8. IconType

AUTO

Reacts as STATIC if icon is specified or DYNAMIC if not (default)

STATIC

The icon is read from the attribute value

DYNAMIC

The icon is determined by the return value of the method Resource get<PropertyName>Icon(). The value is ignored.

The class VaadinIcon contains many Icons for easy use. The Vaadin documentation includes a reference page listing all available icons as well as documentation how to Icons.
Since annotations do not support a null value and VaadinIcon do not have a "NO_ICON" we cannot really specify "no icon" to automatically use a dynamic one. Hence we decided to use a quite uncommon icon (NATIVE_BUTTON) as default. If you really need exactly this icon, use iconType=STATIC explicitly.
Suffix

The annotation @BindSuffix can be used to add a suffix on UI elements.

This can be useful to display units or currencies.

The @BindSuffix annotation has two properties:

Value

This is the content of the suffix that is set at the end of an UI element.

SuffixType

The following configuration options are available for SuffixType:

Table 9. SuffixType

AUTO

The text of the suffix is read from the attribute value if it is not empty, otherwise it reacts like DYNAMIC (default)

STATIC

The text of the suffix is read from the attribute value

DYNAMIC

The text of the suffix is determined by the return value of the method String get<PropertyName>Suffix(). The value is ignored.

BindSuffix can add a suffix to UI elements which implement the HasPrefixAndSuffix interface. Common UI elements which support @BindSuffix are @UIIntegerField, @UIDoubleField, @UIDecimalField, @UITextField, @UITextArea, @UICustomField.
Placeholder

The annotation @BindPlaceholder can be used to display a placeholder on UI elements.

The @BindPlaceholder annotation has two properties:

Value

This is the content that is displayed in an UI element when it is empty.

PlaceholderType

The following configuration options are available for PlaceholderType:

Table 10. PlaceholderType

AUTO

The text of the placeholder is read from the attribute value if it is not empty, otherwise it reacts like DYNAMIC (default)

STATIC

The text of the placeholder is read from the attribute value

DYNAMIC

The text of the placeholder is determined by the return value of the method String get<PropertyName>Placeholder(). The value is ignored.

The @BindPlaceholder annotation can also be used on table PMOs providing a placeholder text that is shown in case the table has no items. Table header and footer will also be hidden.

This aspect is an inherited aspect. If a class is annotated with @BindPlaceholder, all subclasses will hide their tables using the declared annotation in their super class. It is not possible for subclasses to override this behavior.
@BindPlaceholder on table PMO
    @BindPlaceholder("No rows present.")
    @UISection(caption = "@BindPlaceholder(\"No rows present.\")")
    public static class TableWithPlaceholderPmo extends SimplePlaygroundTablePmo {
@BindPlaceholder(value = "", placeholderType = PlaceholderType.STATIC) will hide empty tables without showing any replacement text. When using @BindPlaceholder as annotation only, providing mandatory getPlaceholder()-Method and returning empty String will do the same.