@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;
}
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".
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 embedded 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.
@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:
|
The content of the element is modifiable in the UI (default) |
|
The content of the element is not modifiable in the UI |
|
Whether the content is modifiable is controlled by the return value of the method |
Visible
The property visible
controls whether the component is visible. There are the following configuration options:
|
The UI element is visible (default) |
|
The UI element is invisible |
|
Whether the UI element is visible is controlled by the return value of the method |
Required
The property required
visually highlights required fields. The following configuration options are available:
|
The UI element requires input (a value must be entered/selected) |
|
The UI element requires input if it is |
|
Input in the UI element is optional (default) |
|
Whether the element requires input is controlled by the return value of the method |
Fields marked as required are only visually highlighted. No validation is performed.
|
Standalone Aspect 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 |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 likeDYNAMIC
(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()
. Thevalue
is ignored.
@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:
|
The component is always read-only (default). |
|
The read-only behavior of the component is determined by the return value of the method |
|
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:
|
Component is invisible in read-only mode. This type is the default value. |
|
Component is visible but disabled in read-only mode. |
|
Component remains writable in read-only mode. |
|
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()
. When annotating an entire PMO the method is isVisible()
.
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
.
Updates of child bindings are skipped if a PMO is invisible. Due to an initial update upon creation, null-/Exception-handling might however still be necessary. To address this, consider:
|
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:
|
Reacts as |
|
The caption is read from the attribute |
|
The caption is determined by the return value of the method |
|
Explicitly set the caption to |
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
:
|
Reacts as |
|
The icon is read from the attribute |
|
The icon is determined by the return value of the method |
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 a UI element.
- SuffixType
-
The following configuration options are available for
SuffixType
:
|
The text of the suffix is read from the attribute |
|
The text of the suffix is read from the attribute |
|
The text of the suffix is determined by the return value of the method |
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 a UI element when it is empty.
- PlaceholderType
-
The following configuration options are available for
PlaceholderType
:
|
The text of the placeholder is read from the attribute |
|
The text of the placeholder is read from the attribute |
|
The text of the placeholder is determined by the return value of the method |
Tables
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 remove this behavior. It is however possible to set an new placeholder in a subclass.
|
@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.
|
AutoFocus
The annotation @BindAutoFocus
can be used to set the autofocus attribute on a UI element.
This annotation should only be used on one UI element per page/dialog. The target element must be visible and editable. This annotation does not work with @UIRadioButtons .
|
When used on a @UIDateTimeField , the date input field will be autofocused.
|
@BindAutoFocus
on a text field @BindAutoFocus
@UITextField(position = 20, label = "autofocus")
public String getAutoFocusedTextField() {
return text;
}
BindAutoFocus can set the autofocus property on UI elements which implement the HasValue and HasElement interfaces. Common UI elements which support @BindAutoFocus are @UIIntegerField , @UIDoubleField , @UIDecimalField , @UITextField , @UITextArea , @UICustomField , @UIDateField , @UIDateTimeField , @UICheckBox and @UIComboBox .
|
Variant names
Vaadin components get rendered as HTML and styled via CSS. The @BindVariantNames
annotation can be used to add specific Vaadin variants to components implementing the HasTheme
interface.
It is possible to provide a single variant name (@BindVariantNames("no-border")
) or an array of variant names (@BindVariantNames({"no-row-borders", "compact"})
) as the annotation’s value.
@BindVariantNames
on TablePmo @UISection(caption = "Table with 'no row border' variant")
@BindVariantNames(value = { "no-row-borders" })
public static class BindVariantNamesTablePmoNoBorder extends SimplePlaygroundTablePmo {
public BindVariantNamesTablePmoNoBorder() {
super(IntStream.range(1, 2)
.mapToObj(TableModelObject::new)
.collect(Collectors.toList()));
}
}
Binding validation messages
In some cases, it is not practical to use model binding in all fields of a PMO (e.g. because conversion/navigation needs to be done in getters/setters), but it should still be possible to set validation messages on a field.
This can be done with the annotation @BindMessages
.
Binding labels
In some cases, the labels of UI elements as text fields for example require to be set dynamically.
This can be done by using the @BindLabel
annotation.
One use case is to avoid unnecessary additional UI elements with static labels which have to be made visible as needed in order to provide the same functionality as dynamic labels.
This binding does not work with table headers. |
The annotation has two properties:
- Value
-
This is the label text which is displayed in case of static labels.
- LabelType
-
The following configuration options are available for
LabelType
:
|
The text of the label is determined by the return value of the method |
|
The text of the label is read from the attribute |
|
The text of the label is read from the attribute |
|
No label text is displayed. |
Some UI elements already provide a property for defining static labels. This value is overwritten by the @BindLabel annotation.
|
@BindLabel
with a dynamic label @BindLabel(labelType = LabelType.DYNAMIC)
@UIButton(position = 20)
public void dynamicButton() {
// button
}
public String getDynamicButtonLabel() {
return dynamicLabel;
}
@BindLabel
with a static label @BindLabel(labelType = LabelType.STATIC, value = "Static label")
@UIButton(position = 65)
public void staticButton() {
// button
}
Binding slots
Web components are based on a layout with a fixed CSS style.
The web component often defines slots where child elements could be placed.
For example a layout component may define a header and a body section.
The @BindSlot
annotation can be used to set UI elements into these slots.
The annotation has one property:
- Value
-
This is the name of the slot the annotated component should be set into.
The annotation can be used in combination with a newly created layout or with an existing one which already defines slots.
By using @BindSlot
, UI components can be set into the available slots of the used layout.
For a Lit template which defines a left and a right sided slot, this looks as follows:
@BindSlot
with a slot on the left and on the right side@UIBindSlotLayout
public class BindSlotPmo {
private final RightSlotPmo rightSlot;
public BindSlotPmo(RightSlotPmo rightSlot) {
this.rightSlot = rightSlot;
}
@BindSlot(BindSlotLayout.SLOT_LEFT)
@UIButton(position = 10, showIcon = true, icon = VaadinIcon.ARROW_LEFT, caption = StringUtils.EMPTY)
public void leftButton() {
// click
}
@BindSlot(BindSlotLayout.SLOT_RIGHT)
@UINestedComponent(position = 20, width = "inherit")
public Object rightSlot() {
return rightSlot;
}
}