@UILabel(position = 10, label = "Label with HtmlContent")
@BindIcon(value = VaadinIcon.ACCORDION_MENU)
@BindSuffix("%")
public HtmlContent getHtmlContentLabel() {
return HtmlContent.builder()
.styledTag("i", "color: red;", "HTML")
.text(" ")
.tag("b", "Content")
.build();
}
UI Components
UI Elements
Both fields and buttons are "UI elements". The following types are provided:
Displaying of text |
|
Hyperlink |
|
Field for single line text entry |
|
Area for multiline text entry |
|
Field for numbers |
|
Control for boolean input |
|
Field for date entry with date picker |
|
Field for time entry with time picker |
|
Field for date and time entry with date time picker |
|
Dropdown field with predefined options |
|
Dropdown field with predefined options for selecting multiple options |
|
Dropdown field for boolean choices |
|
Radio buttons for selecting a single choice |
A button that triggers an action when clicked |
The type of a field can be determined dynamically. This mechanism is called dynamic field.
Annotations for fields and buttons must exist on methods in a PMO class. The main difference between fields and buttons is that fields are used for displaying and editing of values and thus are bound to a value via data binding. Therefore annotations for fields must exist on a getter method of a PMO property. Only if domain model binding is used the method can be named differently.
Buttons are not bound to a value, but to an annotated method. It represents an executable action which is called by the button click.
Properties
All UI elements have the position
property. In addition, many of the annotations have some aspects embedded, such as
-
enabled: boolean
(not configurable for all elements) -
required: boolean
(not configurable for all elements)
Fields have additional properties that are required for the domain model binding:
position must always be specified. For most annotations, label is also mandatory. All other properties have default values.
|
- Position
-
The "position" property defines the order of elements in the UI. The relative size of the value is deciding. Elements with smaller
position
are added to a section first.Gaps in the position numbering are allowed and common, to allow adding new UI elements at a later moment without needing to renumber all elements.
- ModelObject and -Attribute
-
A field can be bound to an attribute of an existing model object using domain model binding. For this the properties
modelAttribute
and possiblymodelObject
are required. The function is described in the section names of model attributes.
UILabel
The annotation @UILabel
generates an independent UI element displaying String
content. In contrast to a deactivated UITextField, its text is not framed by an input field.
The annotated method must return a value that is convertable to String
. This can either be achieved by a registered converter at LinkkiConverterRegistry
, or by a ItemCaptionProvider
that can be provided to the UILabel
annotation.
If the Faktor-IPS linkki extension is used, the FormattedStringToDecimalConverter
should be registered to LinkkiConverterRegistry
in order to display Faktor-IPS Decimal values property.
A @UILabel also has the additional property label . If a value is set to it the text would appear beside or on top of the UILabel .When used in a table, the label is used as the column name while the caption is displayed in the table cell.
|
- HTML Content
-
The label’s content can be enhanced with HTML when the annotated method returns an
HtmlContent
object. TheHtmlContent
class provides access to a builder for creating HTML content. For common use cases, static methods are available to simplifyHtmlContent
creation. If HTML content from the model needs to be displayed, theHtmlContent.sanitize(String)
method can be used to generate a sanitized HtmlContent instance based on the model’s value. An example below illustrates how to create multicolored text.
A common usecase is to display a string split accross multiple lines. This can be achieved by using the HtmlContent.multilineText(String …)
method.
If you are building an extendable PMO and it may be reasonable for subclasses to use HTMLContent
, make sure that the method returns HtmlContent
.
- Styles
-
To style labels the property
styleNames
can be used to specify a list (actually aString[]
) of CSS class names. - Icon position
-
The icon position can be set with the property
iconPosition
. An icon can be placed to the left (default) or to the right of the label.
UILink
The annotation @UILink
creates a hyperlink. In comparison to a button styled as a link, a link in Vaadin has the advantage that the user can use the context menu to follow the link in a separate browser tab or to copy the link. The caption can also be easily copied.
The annotated method should return the link URL as a string.
The annotation has the following attributes:
-
target: String
: Defines where to open the link as specified by HTML. The four predefined targetsBLANK
,SELF
,PARENT
andTOP
can be found in the constant classLinkTarget
as well as the empty String constantLinkTarget.DYNAMIC
, which leads to dynamic target resolution via aget<PropertyName>Target
method.
A @UILink also has the additional property label . If a value is set to it the text would appear beside the link.When used in a table, the label is used as the column name while the caption is displayed as the link text in the table cell.
|
- Icon position
-
The icon position can be set with the property
iconPosition
. An icon can be placed to the left or to the right (default) of the link.
UICheckbox
The annotation @UICheckbox
creates a com.vaadin.flow.component.checkbox.Checkbox
that is bound to a boolean
property.
Instead of a label on the left side of the UI element, checkboxes usually have a caption on the right. This caption must be set with the property caption
. If no caption is desired, an empty String must be set.
The usual label property is still available if any display text is needed on the left side additionally.When used in a table, the label is used as the column name while the caption is displayed next to the checkbox in the table cell.
|
UITextField
The annotation UITextfield
corresponds to a com.vaadin.flow.component.textfield.TextField
for text entry. It has two additional properties:
-
maxLength: int
-
width: String
maxLength
defines the maximum number of characters that can be entered or displayed in the field while width
defines the visible width of the field using a number and a CSS unit, for example "5em" or "50%". The width is set to "100%" by default which means it grabs all available space.
UITextArea
The annotation UITextArea
corresponds to a com.vaadin.flow.component.textfield.TextArea
. It is used for entering or displaying text that has more than one line. UITextArea
has all the properties of the annotation UITextfield
. In addition, it also has:
-
height: String
The property height
defines the height of the UITextArea
, not how many rows can be entered. It returns a String
using a number and a CSS unit, for example "5em". Its default value is 3em
.
UIIntegerField and UIDoubleField
The annotations @UIIntegerfield
and @UIDoubleField
are text fields for displaying formatted numbers. Like @UITextField
these annotations have the property maxLength
.
The format can be defined with the property format: String
, using the notation from java.text.NumberFormat
.
If no format is specified for a UIIntegerField
, linkki uses the default Java Integer NumberFormat (java.text.NumberFormat#getIntegerInstance(java.util.Locale)
). In the case of UIDoubleField
the format #,##0.00##
is used by default. This format means that at least one digit is displayed before the decimal separator and two after, and the thousands separator is displayed as well. The documentation for the format definition can be looked up in the class java.text.DecimalFormat
.
UIDateField
The @UIDateField
annotation creates a date input field and is equivalent to com.vaadin.flow.component.datepicker.DatePicker
.
The date is formatted according to the language preference set in the user’s browser. For example, using the German Locale
will format the date as dd.mm.yyyy
.
The UIDateField
allows multiple date formats to be set, and by default uses the same date format as the standard Vaadin date field, but also allows dates to be entered without punctuation, so for example 010420
becomes 01.04.2020
.
UITimeField
The annotation @UITimeField
generates a time input field and corresponds to com.vaadin.flow.component.datepicker.TimePicker
.
Values typed into the time field will automatically be converted to the format matching the Locale
setting. E.g. 15:00
becomes 3:00 PM
when the Locale
is English.
It has one additional property:
-
step: long
This property defines the time interval in minutes between the items displayed in the time picker overlay. It also specifies the amount by which the time increases/decreases using the Up/Down arrow keys when the overlays are disabled. Its default value is 60
.
-
precision: ChronoUnit
The precision
property specifies the unit of granularity for the time value, such as minutes
or seconds
. By default, this is set to minutes
.
It is noted that the overlay for time selection is disabled when precision
is configured with a step
size resulting in intervals smaller than 15 minutes. This is to prevent an impractical number of choices from being displayed. Manual entry of time, including seconds, is permitted and processed accordingly. It is also possible to adjust the time using the up and down arrow keys.
The step must divide an hour or day evenly. For example, 15 , 30 and 60 are valid steps, while 42 and 300 are not. If an invalid value is used, an exception will be thrown by Vaadin.
|
UIDateTimeField
The annotation @UIDateTimeField
generates a date and time input field and corresponds to com.vaadin.flow.component.datetimepicker.DateTimePicker
. It is used for selecting both a date and a time of day. UIDateTimeField
has all the properties of the annotations UIDateField and UITimeField.
UIComboBox
The annotation @UIComboBox
allows selection of a value from a list and corresponds to com.vaadin.flow.component.combobox.ComboBox
. It has three additional properties:
@UIComboBox(position = 20,
label = "Model",
modelAttribute = Car.PROPERTY_MODEL,
required = RequiredType.REQUIRED_IF_ENABLED,
content = AvailableValuesType.DYNAMIC,
itemCaptionProvider = ToStringCaptionProvider.class)
public void model() {
/* model binding */
}
To style items in the combo box popup menu the annotation @BindComboBoxItemStyle can be used. To handle refresh of items when using dynamic captions @BindComboBoxDynamicCaption can be applied.
- Content
-
The attribute
content
defines which values are available:Table 3. AvailableValuesType ENUM_VALUES_INCL_NULL
the values of the combobox correspond to the values of the enum data type of the property, extended by the value
null
(default). It can also be used for boolean.ENUM_VALUES_EXCL_NULL
the values of the combobox correspond to the values of the enum data type of the property. It can also be used for boolean.
DYNAMIC
the values of the combobox are defined dynamically through the method
Collection<T> get<PropertyName>AvailableValues()
NO_VALUES
this combobox has no selectable values
- Width
-
The property
width
can be used to define the width of the combobox using CSS syntax (e.g."25em"
or"100%"
). The default value is-1px
, corresponding to the standard size given by Vaadin.
- ItemCaptionProvider
-
A
org.linkki.core.defaults.ui.element.ItemCaptionProvider<T>
is used to display the individual values in the combobox. By default, it is aDefaultCaptionProvider
which determines the caption by trying to call the methodsgetName(Locale)
,getName
,toString
in that order. Boolean values are translated to German or English depending on the locale of the UI.An alternative implementation class can be specified via the property
itemCaptionProvider
. linkki offers two additional ones:-
ToStringCaptionProvider
: uses the `toString()`method of the elements -
IdAndNameCaptionProvider
in linkki-ips: displays name and ID in the format"name [ID]"
using the methodsgetName()
andgetId()
.
-
- TextAlign
-
The property
textAlign
specifies the text alignment of the value inside the combo box, and the values in the drop-down menu.RIGHT
is recommended for numeric values. If custom styles are used via@BindComboBoxItemStyle
, thetextAlignment
will not affect the drop-down list. Instead, an appropriate CSS class has to be set by@BindComboBoxItemStyle
.
- Automatically focus first applicable item
-
By default, a Vaadin ComboBox only accepts text input that exactly matches an item. For example, in a combo box with the options "aa", "bb", typing in "a" would not select "aa", although it is the only one that matches the input.
To improve this behavior, linkki provides Javascripts that can be used to enhance the usability. If application framework is used, these scripts are executed automatically. Otherwise, these need to be imported by using@JsModule
. Ideally on a parent route layout that is used by all routes.@JsModule("./src/focus-first-item-combo-box-mixin.js") @JsModule("./src/focus-first-item-combo-box-scroller.js") @Route("my") public class MyView extends Div {}
UIMultiSelect
The annotation @UIMultiSelect
allows selection of multiple values from a list and corresponds to com.vaadin.flow.component.combobox.MultiSelectComboBox
. It has two properties known from the UIComboBox
:
The getter and setter for the selected values have to be of type Set<T>
. This implies that there is no guaranteed order of the selected values.
In contrast to a combobox, the values of the multi select box are always defined dynamically through the method Collection<T> get<PropertyName>AvailableValues()
. Be aware that some subtypes of Collection
have no guaranteed order of elements and should not be used. Otherwise, the list of available values of this component may have a different order in the UI which is not very user-friendly.
UIYesNoComboBox
This annotation is deprecated since 2.6.0. Use UIComboBox directly instead.
|
The annotation @UIYesNoComboBox
allows selection of a boolean value from a dropdown list like a UIComboBox
. The difference is that the values are not a generic enumeration or list but the well known boolean values true
and false
(and for Boolean
, the option null
). It has two properties known from the UIComboBox
:
-
itemCaptionProvider: Class<? extends ItemCaptionProvider<?
>> with a default implementationBooleanCaptionProvider
that uses common names in the current locale like "Yes"/"No" or "Ja"/"Nein".
UIRadioButtons
The annotation @UIRadioButtons
allows selection of a single value using a group of buttons and corresponds to com.vaadin.flow.component.radiobutton.RadioButtonGroup
. Multiple values cannot be selected at the same time.
-
itemCaptionProvider: Class<? extends ItemCaptionProvider<?
>> with a default implementationRadioButtonsCaptionProvider
that delegates togetName
ortoString
. In addition, boolean values are translated to German or English depending on the locale of the UI. -
buttonAlignment: AlignmentType
UICustomField
Other controls can also easily be generated and bound by linkki. For this the annotation @UICustomField
is used.
The control class is specified with the property uiControl: Class<? extends Field<?>>
. If the control implements com.vaadin.flow.data.provider.HasListDataView<T, V>
the values can be defined by content: AvailableValuesType
like with UIComboBox.
@UICustomField only supports controls with a parameter-less constructor.
|
@UICustomField(position = 0, label = "Secret", uiControl = PasswordField.class)
public String getSecret() {
return secret;
}
public void setSecret(String secret) {
this.secret = secret;
}
Dynamic Field
linkki allows for dynamic typing of an input field. In the following example Retention
should only be freely writable if CarType
is set to STANDARD
. Otherwise, the user can only select values from a list:
@UIDoubleField(position = 30,
label = "Retention",
modelAttribute = Car.PROPERTY_RETENTION,
required = RequiredType.REQUIRED_IF_ENABLED)
@UIComboBox(position = 30,
label = "Retention",
modelAttribute = Car.PROPERTY_RETENTION,
required = RequiredType.REQUIRED_IF_ENABLED,
content = AvailableValuesType.DYNAMIC,
itemCaptionProvider = RetentionCaptionProvider.class)
public void retention() {
/* model binding */
}
public List<Double> getRetentionAvailableValues() {
return Arrays.asList(2_000.0, 5_000.0, 10_000.0);
}
public Class<?> getRetentionComponentType() {
return car.getCarType() == CarType.STANDARD ? UIDoubleField.class : UIComboBox.class;
}
The selectable UI elements are defined via annotations on the method, as is customary. They must, however, fulfill the following requirements, to allow the type to be determined dynamically:
-
the
position
in the UI* annotations must match -
the
label
must have the same value
If the position
values are identical but the label
values differ, an exception is thrown.
Which UI element is displayed for each PMO instance is determined by the method Class<?> get<PropertyName>ComponentType()
. It returns the class of the UI*-Annotation for the UI control to be rendered.
UIButton
The annotation @UIButton
is used to mark the method that should be executed when the button is clicked. It corresponds to com.vaadin.flow.component.button.Button
.
Since buttons are not bound to values and therefore have no corresponding PMO property, the name of the annotated method is used to determine the associated methods. The behavior is similar to the domain model binding, although buttons have no property modelAttribute
.
@UIButton(position = 10,
showIcon = true,
icon = VaadinIcon.CHECK, //
captionType = CaptionType.NONE,
enabled = EnabledType.DYNAMIC,
shortcutKeyCode = KeyCode.ENTER,
variants = ButtonVariant.LUMO_PRIMARY)
public void save() {
saveAction.apply();
}
public boolean isSaveEnabled() {
return canSaveSupplier.getAsBoolean();
}
@UIButton(position = 20,
captionType = CaptionType.STATIC,
caption = "reset",
variants = ButtonVariant.LUMO_TERTIARY)
public void reset() {
resetAction.apply();
}
Apart from the common properties, buttons have these additional ones:
Caption
The text shown on a button is called a caption. It is not to be confused with a Label, which usually appears besides the control. A button can have both a caption and a label text.
-
captionType: CaptionType
|
the caption of the button is read from the attribute |
|
the button has no caption |
|
the caption of the button is determined by the return value of the method |
Icon
Apart from captions, buttons can be adorned with icons. For this the constants of the Vaadin class VaadinIcon
are used. For the icon to be displayed the property showIcon
must be set true
.
Button Variants
Depending on the function buttons must be styled differently. com.vaadin.flow.component.button.ButtonVariant
offers different theme variants, such as primary or inline.
For more information please refer to Vaadin Button Variants Documentation.
Key Bindings
Some buttons shouldn’t be triggered only by mouse click, but also by key combinations. These can be specified with the properties shortcutModifierKeys
and shortcutKeyCode
. shortcutModifierKeys
defines which keys must be pressed and held before the key in the shortcutKeyCode
is pressed. For instance, in many applications saving is triggered with the shortcut combination "Ctrl + s". In this case the "Ctrl" key is the modifier and the "s" key is the shortcut key.
The appropriate value for modifiers can be found in KeyModifier
. The most common keys are provided by the class KeyCode
. Other values for keys can be deducted by the Vaadin class Keys
.
As button shortcuts work globally, there should always be only one button that uses a key combination as shortcut. In addition, a button that uses enter as shortcut should also use the variant PRIMARY to make it visibly clear to the user that the button would be triggered. |
To prevent unexpected behaviors, defining a shortcut for a button results in preventing the browser default for that key combination. For example, if a button defines the enter key as shortcut, it will not be possible to create line break in text areas using enter. Shift + enter would still work if there is no button that uses shift + enter as shortcut. |