Part of vaadin/framework8-issues#538tags/8.0.0.beta2
Adding the dependency in Maven projects and compiling the widget set is described in <<addons-maven#addons.maven, "Using Add-ons in a Maven Project">>. | Adding the dependency in Maven projects and compiling the widget set is described in <<addons-maven#addons.maven, "Using Add-ons in a Maven Project">>. | ||||
The section also describes how to use the online compilation and CDN services during development. | The section also describes how to use the online compilation and CDN services during development. | ||||
For Eclipse projects that use Ivy for dependency management, see <<addons-eclipse#addons.eclipse, "Installing Add-ons in Eclipse with Ivy">>. | |||||
You can also download and install add-ons from a ZIP-package, as described in <<addons-downloading#addons.downloading, "Downloading Add-ons from Vaadin Directory">>. | |||||
For Eclipse projects that use Ivy for dependency management, see <<dummy/../../../framework/addons/addons-eclipse.asciidoc#addons.eclipse, "Installing Add-ons in Eclipse with Ivy">>. | |||||
You can also download and install add-ons from a ZIP-package, as described in <<dummy/../../../framework/addons/addons-downloading.asciidoc#addons.downloading, "Downloading Add-ons from Vaadin Directory">>. | |||||
== Add-on Licenses | == Add-on Licenses | ||||
session most conveniently by implementing a custom servlet and adding the UI | session most conveniently by implementing a custom servlet and adding the UI | ||||
provider to sessions in a [interfacename]#SessionInitListener#. | provider to sessions in a [interfacename]#SessionInitListener#. | ||||
You can find an example of custom UI providers in | |||||
<<dummy/../../../mobile/mobile-features#mobile.features.fallback,"Providing a | |||||
Fallback UI">>. | |||||
[[application.lifecycle.ui.preserving]] | [[application.lifecycle.ui.preserving]] | ||||
=== Preserving UI on Refresh | === Preserving UI on Refresh |
.An Example of a Check Box | .An Example of a Check Box | ||||
image::img/checkbox-example1.png[width=35%, scaledwidth=50%] | image::img/checkbox-example1.png[width=35%, scaledwidth=50%] | ||||
For an example on the use of check boxes in a table, see | |||||
<<dummy/../../../framework/components/components-table#components.table,"Table">>. | |||||
== CSS Style Rules | == CSS Style Rules | ||||
.The [classname]#ComboBox# Component | .The [classname]#ComboBox# Component | ||||
image::img/combobox-basic.png[width=35%, scaledwidth=50%] | image::img/combobox-basic.png[width=35%, scaledwidth=50%] | ||||
[classname]#ComboBox# supports adding new items when the user presses | |||||
kbd:[Enter]. | |||||
ifdef::web[] | |||||
See <<dummy/../../../framework/components/components-selection#components.selection.newitems,"Allowing Adding New Items">>. | |||||
endif::web[] | |||||
[[components.combobox.filtering]] | [[components.combobox.filtering]] | ||||
== Filtered Selection | == Filtered Selection | ||||
below, when we type some text in the input area, the drop-down list will show | below, when we type some text in the input area, the drop-down list will show | ||||
all the matching items. | all the matching items. | ||||
[[components.combobox.newitems]] | |||||
== Allowing Adding New Items | |||||
[classname]#ComboBox# allows the user to add new items, when the user types | |||||
in a value and presses kbd:[Enter]. You need to enable this with | |||||
[methodname]#setNewItemHandler()#. | |||||
Adding new items is not possible if the selection component is read-only. An | |||||
attempt to do so may result in an exception. | |||||
=== Handling New Items | |||||
Adding new items is handled by a [interfacename]#NewItemHandler#, which gets the | |||||
item caption string as parameter for the [methodname]#accept(String)# method. | |||||
[source, java] | |||||
---- | |||||
// List of planets | |||||
List<Planet> planets = new ArrayList<>(); | |||||
planets.add(new Planet(1, "Mercury")); | |||||
planets.add(new Planet(2, "Venus")); | |||||
planets.add(new Planet(3, "Earth")); | |||||
planets.add(new Planet(4, "Mars")); | |||||
ComboBox<Planet> select = | |||||
new ComboBox<>("Select or Add a Planet"); | |||||
select.setItems(planets); | |||||
// Use the name property for item captions | |||||
select.setItemCaptionGenerator(Planet::getName); | |||||
// Allow adding new items and add | |||||
// handling for new items | |||||
select.setNewItemHandler(inputString -> { | |||||
// Create a new bean - can't set all properties | |||||
Planet newPlanet = new Planet(planets.size(), inputString); | |||||
planets.add(newPlanet); | |||||
// Update combobox content | |||||
select.setItems(planets); | |||||
// Remember to set the selection to the new item | |||||
select.select(newPlanet); | |||||
Notification.show("Added new planet called " + | |||||
inputString); | |||||
}); | |||||
---- | |||||
[[components.combobox.css]] | [[components.combobox.css]] | ||||
== CSS Style Rules | == CSS Style Rules |
= Composite Fields with [classname]#CustomField# | = Composite Fields with [classname]#CustomField# | ||||
The [classname]#CustomField# is a way to create composite components as with [classname]#CustomComponent#, except that it implements the [interfacename]#Field# interface and inherits [classname]#AbstractField#, described in <<dummy/../../../framework/components/components-fields#components.fields,"Field Components">>. | The [classname]#CustomField# is a way to create composite components as with [classname]#CustomComponent#, except that it implements the [interfacename]#Field# interface and inherits [classname]#AbstractField#, described in <<dummy/../../../framework/components/components-fields#components.fields,"Field Components">>. | ||||
A field allows editing a property value in the Vaadin data model, and can be bound to data with field groups, as described in <<dummy/../../../framework/datamodel/datamodel-itembinding#datamodel.itembinding, "Creating Forms by Binding Fields to Items">>. | |||||
A field allows editing a property value in the Vaadin data model, and can be bound to data with field groups, as described in <<dummy/../../../framework/datamodel/datamodel-forms#datamodel.forms, "Binding Data to Forms">>. | |||||
The field values are buffered and can be validated with validators. | The field values are buffered and can be validated with validators. | ||||
A composite field class must implement the [methodname]#getType()# and [methodname]#initContent()# methods. | A composite field class must implement the [methodname]#getType()# and [methodname]#initContent()# methods. |
---- | ---- | ||||
.v-caption {} | .v-caption {} | ||||
.v-captiontext {} | .v-captiontext {} | ||||
.v-caption-clearelem {} | |||||
.v-required-field-indicator {} | .v-required-field-indicator {} | ||||
---- | ---- | ||||
[literal]#++v-caption++# CSS style class. The containing layout may enclose a | [literal]#++v-caption++# CSS style class. The containing layout may enclose a | ||||
caption inside other caption-related elements. | caption inside other caption-related elements. | ||||
Some layouts put the caption text in a [literal]#++v-captiontext++# element. A | |||||
[literal]#++v-caption-clearelem++# is used in some layouts to clear a CSS | |||||
[literal]#++float++# property in captions. An optional required indicator in | |||||
field components is contained in a separate element with | |||||
Some layouts put the caption text in a [literal]#++v-captiontext++# element. | |||||
An optional required indicator in field components is contained in a separate element with | |||||
[literal]#++v-required-field-indicator++# style. | [literal]#++v-required-field-indicator++# style. | ||||
.A Rich Text Tooltip | .A Rich Text Tooltip | ||||
image::img/tooltip-richtext-withpointer-hi.png[width=40%, scaledwidth=75%] | image::img/tooltip-richtext-withpointer-hi.png[width=40%, scaledwidth=75%] | ||||
Notice that the setter and getter are defined for all field components implementing the | |||||
[classname]#HasValue# interface, not for all components. | |||||
[[components.features.enabled]] | [[components.features.enabled]] | ||||
== Enabled | == Enabled | ||||
interaction with a disabled component is sent to the server and, as an important | interaction with a disabled component is sent to the server and, as an important | ||||
security feature, the server-side components do not receive state updates from | security feature, the server-side components do not receive state updates from | ||||
the client in the disabled state. This feature exists in all built-in | the client in the disabled state. This feature exists in all built-in | ||||
components in Vaadin and is automatically handled for all [classname]#HasValue# | |||||
components that have a value. For custom widgets, you need to make | |||||
sure that the disabled state is checked on the server-side for all | |||||
safety-critical variables. | |||||
components in the Framework meaning all client to server RPC calls are ignored | |||||
for disabled components. | |||||
=== CSS Style Rules | === CSS Style Rules | ||||
This would make the border of all disabled text fields dotted. | This would make the border of all disabled text fields dotted. | ||||
// TODO This may change to $v-button-disabled-opacity | |||||
In the Valo theme, the opacity of disabled components is specified with the | In the Valo theme, the opacity of disabled components is specified with the | ||||
`$v-disabled-opacity` | |||||
ifndef::web[parameter.] | |||||
ifdef::web[parameter, as described in <<dummy/../../../framework/themes/themes-valo#themes.valo.variables,"Common Settings">>] | |||||
`$v-disabled-opacity` parameter. | |||||
[[components.features.icon]] | [[components.features.icon]] | ||||
== Icon | == Icon | ||||
date.setResolution(Resolution.DAY); | date.setResolution(Resolution.DAY); | ||||
layout.addComponent(date); | layout.addComponent(date); | ||||
---- | ---- | ||||
See the http://demo.vaadin.com/book-examples-vaadin7/book#component.features.locale.simple[on-line example, window="_blank"]. | |||||
The resulting date field is shown in <<figure.components.features.locale.simple>>. | The resulting date field is shown in <<figure.components.features.locale.simple>>. | ||||
.Set locale for [classname]#InlineDateField# | .Set locale for [classname]#InlineDateField# | ||||
image::img/features-locale-simple.png[width=40%, scaledwidth=60%] | image::img/features-locale-simple.png[width=40%, scaledwidth=60%] | ||||
ifdef::web[] | |||||
[[components.features.locale.get]] | [[components.features.locale.get]] | ||||
=== Getting the Locale | === Getting the Locale | ||||
}; | }; | ||||
layout.addComponent(cancel); | layout.addComponent(cancel); | ||||
---- | ---- | ||||
See the http://demo.vaadin.com/book-examples-vaadin7/book#component.features.locale.get-attach[on-line example, window="_blank"]. | |||||
However, it is normally a better practice to use the locale of the current UI to | However, it is normally a better practice to use the locale of the current UI to | ||||
get the localized resource right when the component is created. | get the localized resource right when the component is created. | ||||
new Button(bundle.getString(MyAppCaptions.CancelKey)); | new Button(bundle.getString(MyAppCaptions.CancelKey)); | ||||
layout.addComponent(cancel); | layout.addComponent(cancel); | ||||
---- | ---- | ||||
See the http://demo.vaadin.com/book-examples-vaadin7/book#component.features.locale.get-ui[on-line example, window="_blank"]. | |||||
endif::web[] | |||||
ifdef::web[] | |||||
[[component.features.locale.selecting]] | [[component.features.locale.selecting]] | ||||
=== Selecting a Locale | === Selecting a Locale | ||||
A common task in many applications is selecting a locale. This is done in the | |||||
following example with a [classname]#ComboBox#, which gets the available locales | |||||
in Java. | |||||
[source, java] | |||||
---- | |||||
// The locale in which we want to have the language | |||||
// selection list | |||||
Locale displayLocale = Locale.ENGLISH; | |||||
// All known locales | |||||
final Locale[] locales = Locale.getAvailableLocales(); | |||||
// Allow selecting a language. We are in a constructor of a | |||||
// CustomComponent, so preselecting the current | |||||
// language of the application can not be done before | |||||
// this (and the selection) component are attached to | |||||
// the application. | |||||
ComboBox<Locale> select = new ComboBox<>("Select a language") { | |||||
@Override | |||||
public void attach() { | |||||
super.attach(); | |||||
setValue(getLocale()); | |||||
} | |||||
}; | |||||
select.setItems(Arrays.asList(locales)); | |||||
select.setCaptionGenerator(locale -> locale.getDisplayName(displayLocale)); | |||||
select.setValue(getLocale()); | |||||
layout.addComponent(select); | |||||
// Locale code of the selected locale | |||||
Label localeCode = new Label(""); | |||||
layout.addComponent(localeCode); | |||||
// A date field which language the selection will change | |||||
InlineDateField date = | |||||
new InlineDateField("Calendar in the selected language"); | |||||
date.setResolution(Resolution.DAY); | |||||
layout.addComponent(date); | |||||
// Handle language selection | |||||
select.onValueChange(locale -> { | |||||
date.setLocale(locale); | |||||
localeCode.setValue("Locale code: " + | |||||
locale.getLanguage() + "_" + | |||||
locale.getCountry()); | |||||
}); | |||||
---- | |||||
See the http://demo.vaadin.com/book-examples-vaadin7/book#component.features.locale.selection[on-line example, window="_blank"]. | |||||
The user interface is shown in <<figure.components.features.locale.selection>>. | |||||
[[figure.components.features.locale.selection]] | |||||
.Selecting a locale | |||||
image::img/features-locale-selection.png[] | |||||
endif::web[] | |||||
A common task in many applications is selecting a locale. | |||||
The locale can be set for the [classname]#UI# or single [classname]#Component#. | |||||
By default each component uses the locale from the [classname]#UI# it has been | |||||
attached to. Setting a locale to a [classname]#Component# only applies the locale | |||||
to that component and its children. Note, that updating the locale for a component | |||||
does not update its children, thus any child component that uses the locale should be updated manually. | |||||
[[components.features.readonly]] | [[components.features.readonly]] | ||||
((("read-only property"))) | ((("read-only property"))) | ||||
((("Component interface", "read-only"))) | ((("Component interface", "read-only"))) | ||||
The property defines whether the value of a component can be changed. The | The property defines whether the value of a component can be changed. The | ||||
property is only applicable to [classname]#HasValue# components implementing the `HasValue` interface, as they have a | |||||
value that can be edited by the user. | |||||
property is only applicable to components implementing the [interfacename]#HasValue# interface. | |||||
[source, java] | [source, java] | ||||
---- | ---- | ||||
TextField readwrite = new TextField("Read-Write"); | TextField readwrite = new TextField("Read-Write"); | ||||
readwrite.setValue("You can change this"); | readwrite.setValue("You can change this"); | ||||
readwrite.setReadOnly(false); // The default | readwrite.setReadOnly(false); // The default | ||||
layout.addComponent(readwrite); | |||||
TextField readonly = new TextField("Read-Only"); | TextField readonly = new TextField("Read-Only"); | ||||
readonly.setValue("You can't touch this!"); | readonly.setValue("You can't touch this!"); | ||||
readonly.setReadOnly(true); | readonly.setReadOnly(true); | ||||
layout.addComponent(readonly); | |||||
---- | ---- | ||||
The resulting read-only text field is shown in | The resulting read-only text field is shown in | ||||
position of a [classname]#ListSelect#. Custom components should check the read-only | position of a [classname]#ListSelect#. Custom components should check the read-only | ||||
state for variables bound to business data. | state for variables bound to business data. | ||||
//// | |||||
TODO: Note this also in the Advanced: Security section. | |||||
Possibly also in the GWT chapter. | |||||
//// | |||||
=== CSS Style Rules | === CSS Style Rules | ||||
layout.addComponent(invisible); | layout.addComponent(invisible); | ||||
---- | ---- | ||||
The resulting invisible component is shown in | |||||
<<figure.components.features.visible.simple>>. | |||||
[[figure.components.features.visible.simple]] | |||||
.An invisible component | |||||
image::img/features-visible-simple.png[] | |||||
If you need to make a component only cosmetically invisible, you should use a | If you need to make a component only cosmetically invisible, you should use a | ||||
custom theme to set it [literal]#++display: none++# style. This is mainly useful | custom theme to set it [literal]#++display: none++# style. This is mainly useful | ||||
for some special components that have effects even when made invisible in CSS. | for some special components that have effects even when made invisible in CSS. | ||||
such cases, the invisible content of the component can be made visible easily in | such cases, the invisible content of the component can be made visible easily in | ||||
the browser. | the browser. | ||||
A component made invisible with the __visible__ property has no particular CSS | |||||
style class to indicate that it is hidden. The element does exist though, but | |||||
has [literal]#++display: none++# style, which overrides any CSS styling. | |||||
[[components.features.sizeable]] | [[components.features.sizeable]] | ||||
== Sizing Components | == Sizing Components | ||||
[methodname]#setHeight()# methods. The methods take the size as a floating-point | [methodname]#setHeight()# methods. The methods take the size as a floating-point | ||||
value. You need to give the unit of the measure as the second parameter for the | value. You need to give the unit of the measure as the second parameter for the | ||||
above methods. | above methods. | ||||
ifdef::web[] | |||||
The available units are listed in <<components.features.sizeable.units.table>>. | |||||
endif::web[] | |||||
[source, java] | [source, java] | ||||
---- | ---- | ||||
---- | ---- | ||||
The "[literal]#++100%++#" percentage value makes the component take all | The "[literal]#++100%++#" percentage value makes the component take all | ||||
available size in the particular direction (see the description of | |||||
[parameter]#Unit.PERCENTAGE# in the table below). You can also use the | |||||
available size in the particular direction. You can also use the | |||||
shorthand method [methodname]#setSizeFull()# to set the size to 100% in both | shorthand method [methodname]#setSizeFull()# to set the size to 100% in both | ||||
directions. | directions. | ||||
component will take the minimum necessary space. Most components have undefined | component will take the minimum necessary space. Most components have undefined | ||||
size by default, but some layouts have full size in horizontal direction. You | size by default, but some layouts have full size in horizontal direction. You | ||||
can set the height, width, or both as undefined with the methods [methodname]#setWidthUndefined()#, | can set the height, width, or both as undefined with the methods [methodname]#setWidthUndefined()#, | ||||
[methodname]#setHeightUndefined()#, and [methodname]#setHeightUndefined()#, respectively. | |||||
[methodname]#setHeightUndefined()#, and [methodname]#setSizeUndefined()#, respectively. | |||||
Always keep in mind that _a layout with undefined size may not contain components with defined relative size_, such as "full size", except in some special cases. | Always keep in mind that _a layout with undefined size may not contain components with defined relative size_, such as "full size", except in some special cases. | ||||
See <<dummy/../../../framework/layout/layout-settings#layout.settings.size,"Layout Size">> for details. | See <<dummy/../../../framework/layout/layout-settings#layout.settings.size,"Layout Size">> for details. | ||||
ifdef::web[] | |||||
The <<components.features.sizeable.units.table>> table lists the available units and their codes defined in the [interfacename]#Sizeable# interface. | |||||
[[components.features.sizeable.units.table]] | |||||
.Size units | |||||
[cols="5,2,10", options="header"] | |||||
|=============== | |||||
|Constant|Unit|Description | |||||
|[parameter]#Unit.PIXELS#|px|The _pixel_ is the basic hardware-specific measure of one physical display pixel. | |||||
|[parameter]#Unit.POINTS#|pt|The _point_ is a typographical unit, which is usually defined as 1/72 inches or about 0.35 mm. However, on displays the size can vary significantly depending on display metrics. | |||||
|[parameter]#Unit.PICAS#|pc|The _pica_ is a typographical unit, defined as 12 points, or 1/7 inches or about 4.233 mm. On displays, the size can vary depending on display metrics. | |||||
|[parameter]#Unit.EM#|em|A unit relative to the used font, the width of the upper-case "M" letter. | |||||
|[parameter]#Unit.EX#|ex|A unit relative to the used font, the height of the lower-case "x" letter. | |||||
|[parameter]#Unit.MM#|mm|A physical length unit, millimeters on the surface of a display device. However, the actual size depends on the display, its metrics in the operating system, and the browser. | |||||
|[parameter]#Unit.CM#|cm|A physical length unit, _centimeters_ on the surface of a display device. However, the actual size depends on the display, its metrics in the operating system, and the browser. | |||||
|[parameter]#Unit.INCH#|in|A physical length unit, _inches_ on the surface of a display device. However, the actual size depends on the display, its metrics in the operating system, and the browser. | |||||
|[parameter]#Unit.PERCENTAGE#|%|A relative percentage of the available size. For example, for the top-level layout [parameter]#100%# would be the full width or height of the browser window. The percentage value must be between 0 and 100. | |||||
|=============== | |||||
endif::web[] | |||||
If a component inside [classname]#HorizontalLayout# or [classname]#VerticalLayout# has full size in the namesake direction of the layout, the component will expand to take all available space not needed by the other components. | If a component inside [classname]#HorizontalLayout# or [classname]#VerticalLayout# has full size in the namesake direction of the layout, the component will expand to take all available space not needed by the other components. | ||||
See <<dummy/../../../framework/layout/layout-settings#layout.settings.size,"Layout Size">> for details. | See <<dummy/../../../framework/layout/layout-settings#layout.settings.size,"Layout Size">> for details. | ||||
.Field components | .Field components | ||||
image::img/field-diagram-hi.png[width=80%, scaledwidth=100%] | image::img/field-diagram-hi.png[width=80%, scaledwidth=100%] | ||||
Field components are built upon the framework defined in the [classname]#Field# | |||||
interface and the [classname]#AbstractField# base class. | |||||
[classname]#AbstractField# is the base class for all field components. In | |||||
addition to the component features inherited from | |||||
Field components are built upon the framework defined in the [classname]#HasValue# | |||||
interface. | |||||
[classname]#AbstractField# is the base class for all field components, | |||||
except those components that allow the user to select a value. | |||||
(see <<dummy/../../../framework/components/components-selection.asciidoc#components.selection,"Selection Components">>). | |||||
In addition to the component features inherited from | |||||
[classname]#AbstractComponent#, it implements the features defined in the | [classname]#AbstractComponent#, it implements the features defined in the | ||||
[classname]#HasValue# and [classname]#Component.Focusable# interfaces. | |||||
[interfacename]#HasValue# and [classname]#Component.Focusable# interfaces. | |||||
[[figure.components.fields.hasvalue]] | [[figure.components.fields.hasvalue]] | ||||
.Field components having values | .Field components having values | ||||
image::img/field-interface-v8-hi.png[width=60%, scaledwidth=100%] | image::img/field-interface-v8-hi.png[width=60%, scaledwidth=100%] | ||||
The description of the field interfaces and base classes is broken down in the | |||||
following sections. | |||||
The description of the [interfacename]#HasValue# interface and field components extending [classname]#AbstractField] is broken down in the following sections. | |||||
[[components.fields.field]] | [[components.fields.field]] | ||||
== The [classname]#Field# Interface | |||||
The [classname]#Field# interface inherits the [classname]#Component# | |||||
superinterface and also the [classname]#HasValue# interface to have a value for | |||||
the field. [classname]#AbstractField# is the only class implementing the | |||||
[classname]#Field# interface directly. The relationships are illustrated in | |||||
<<figure.components.fields.field>>. | |||||
== The [interfacename]#HasValue# Interface | |||||
[[figure.components.fields.field]] | |||||
.[classname]#Field# interface inheritance | |||||
image::img/field-interface-hi.png[width=60%, scaledwidth=100%] | |||||
The [interfacename]#HasValue# interface marks a component that has a user editable value. | |||||
The type parameter in the interface is the type of the value that the component is editing. | |||||
You can set the field value with the [methodname]#setValue()# and read with the | |||||
You can set the value with the [methodname]#setValue()# and read it with the | |||||
[methodname]#getValue()# method defined in the [classname]#HasValue# interface. | [methodname]#getValue()# method defined in the [classname]#HasValue# interface. | ||||
The actual value type depends on the component. | |||||
The [classname]#Field# interface defines a number of properties, which you can | |||||
The [classname]#HasValue# interface defines a number of properties, which you can | |||||
access with the corresponding setters and getters. | access with the corresponding setters and getters. | ||||
[methodname]#required#:: When enabled, a required indicator (usually the asterisk * character) is | |||||
displayed on the left, above, or right the field, depending on the containing | |||||
layout and whether the field has a caption. If such fields are validated but are | |||||
empty and the [methodname]#requiredError# property (see below) is set, an error | |||||
indicator is shown and the component error is set to the text defined with the | |||||
error property. Without validation, the required indicator is merely a visual | |||||
guide. | |||||
[methodname]#requiredError#:: Defines the error message to show when a value is required, but none is entered. | |||||
The error message is set as the component error for the field and is usually | |||||
displayed in a tooltip when the mouse pointer hovers over the error indicator. | |||||
[methodname]#readOnly#:: Set the component to be read-only, meaning that the value is not editable. | |||||
[[components.fields.valuechanges]] | |||||
== Handling Field Value Changes | |||||
[methodname]#requiredIndicatorVisible#:: When enabled, a required indicator | |||||
(the asterisk * character) is displayed on the left, above, or right the field, | |||||
depending on the containing layout and whether the field has a caption. | |||||
When the component is used in a form (see <<dummy/../../../framework/datamodel/datamodel-forms.asciidoc#datamodel.forms.validation,"Validation">>), | |||||
it can be set to be required, which will automatically show the required indicator, | |||||
and validate that the value is not empty. Without validation, the required indicator | |||||
is merely a visual guide. | |||||
[methodname]#emptyValue#:: The initial empty value of the component. | |||||
[methodname]#clear#:: Clears the value to the empty value. | |||||
[classname]#Field# provides [methodname]#addValueChangeListener# method for listening to changes to the field value. This method takes a [interfacename]#EventListener# that gets | |||||
a [classname]#ValueChange# event instance containing information about the event. | |||||
This method returns a [classname]#Registration# object that can be used to later | |||||
[[components.fields.valuechanges]] | |||||
== Handling Value Changes | |||||
[interfacename]#HasValue# provides [methodname]#addValueChangeListener# method for listening to changes to the field value. This method returns a [classname]#Registration# object that can be used to later | |||||
remove the added listener if necessary. | remove the added listener if necessary. | ||||
[source, java] | [source, java] | ||||
TextField textField = new TextField(); | TextField textField = new TextField(); | ||||
Label echo = new Label(); | Label echo = new Label(); | ||||
// Add a more complex listener | |||||
textField.addValueChangeListener(event -> { | textField.addValueChangeListener(event -> { | ||||
String origin = event.isUserOriginated() | String origin = event.isUserOriginated() | ||||
? "user" | ? "user" | ||||
}); | }); | ||||
---- | ---- | ||||
[[components.fields.databinding]] | [[components.fields.databinding]] | ||||
== Binding Fields to Data | == Binding Fields to Data | ||||
// Bind nameField to the Person.name property | // Bind nameField to the Person.name property | ||||
// by specifying its getter and setter | // by specifying its getter and setter | ||||
binder.forField(nameField) | |||||
.bind(Person::getName, Person::setName); | |||||
binder.bind(nameField, Person::getName, Person::setName); | |||||
// Bind an actual concrete Person instance. | // Bind an actual concrete Person instance. | ||||
// After this, whenever the user changes the value | // After this, whenever the user changes the value | ||||
// of nameField, p.setName is automatically called. | // of nameField, p.setName is automatically called. | ||||
Person p = new Person(); | Person p = new Person(); | ||||
binder.bind(p; | |||||
binder.bind(p); | |||||
---- | ---- | ||||
For more information on data binding, see <<dummy/../../../framework/datamodel/datamodel-forms.asciidoc#datamodel.forms,"Binding Data to Forms">> | |||||
== Validating Field Values | == Validating Field Values | ||||
User input may be syntactically or semantically invalid. | User input may be syntactically or semantically invalid. | ||||
automatically checking the validity of the input before storing it to the data | automatically checking the validity of the input before storing it to the data | ||||
object. You can add validators to fields by calling the [methodname]#withValidator# | object. You can add validators to fields by calling the [methodname]#withValidator# | ||||
method on the [interfacename]#Binding# object returned by [methodname]#Binder.forField#. | method on the [interfacename]#Binding# object returned by [methodname]#Binder.forField#. | ||||
There are several built-in validators in the Framework, such as the [classname]#StringLengthValidator# used below. | |||||
[source, java] | [source, java] | ||||
---- | ---- | ||||
binder.forField(nameField) | binder.forField(nameField) | ||||
.withValidator(new StringLengthValidator(2, 20, | |||||
"Name must be between 2 and 20 characters long")) | |||||
.withValidator(new StringLengthValidator( | |||||
"Name must be between 2 and 20 characters long", | |||||
2, 20)) | |||||
.bind(Person::getName, Person::setName); | .bind(Person::getName, Person::setName); | ||||
---- | ---- | ||||
Failed validation is indicated with the error indicator of the field, described in | |||||
Failed validation is by default indicated with the error indicator of the field, described in | |||||
<<dummy/../../../framework/application/application-errors#application.errors.error-indicator,"Error | <<dummy/../../../framework/application/application-errors#application.errors.error-indicator,"Error | ||||
Indicator and Message">>. Hovering mouse on the field displays the error message | Indicator and Message">>. Hovering mouse on the field displays the error message | ||||
returned by the validator. If any value in a set of bound fields fails validation, | returned by the validator. If any value in a set of bound fields fails validation, | ||||
none of the field values are saved into the bound property until the validation | none of the field values are saved into the bound property until the validation | ||||
passes. | passes. | ||||
[[components.fields.validation.builtin]] | |||||
=== Built-in Validators | |||||
Vaadin includes the following built-in validators. The property value type is | |||||
indicated. | |||||
[classname]#RangeValidator#: [classname]#Comparable#:: | |||||
Checks that the given [interfacename]#Comparable# value is at or between two given values. | |||||
[classname]#StringLengthValidator#: [classname]#String#:: | |||||
Checks that the length of the input string is at or between two given lengths. | |||||
[classname]#RegexpValidator#: [classname]#String#:: | |||||
Checks that the value matches the given regular expression. | |||||
[classname]#EmailValidator#: [classname]#String#:: | |||||
Checks that the string value is a syntactically valid email address. | |||||
The validated syntax is close to the RFC 822 standard regarding email addresses. | |||||
=== Implementing Custom Validators | === Implementing Custom Validators | ||||
---- | ---- | ||||
class MyValidator implements Validator<String> { | class MyValidator implements Validator<String> { | ||||
@Override | @Override | ||||
public Result<String> apply(String input) { | |||||
public Result<String> apply(String value, ValueContext context) { | |||||
if(input.length() == 6) { | if(input.length() == 6) { | ||||
return Result.ok(input); | return Result.ok(input); | ||||
} else { | } else { | ||||
a data source, the type of the source property can be something different, | a data source, the type of the source property can be something different, | ||||
say an [classname]#Integer#. __Converters__ are used for converting the values | say an [classname]#Integer#. __Converters__ are used for converting the values | ||||
between the presentation and the model. Their usage is described in | between the presentation and the model. Their usage is described in | ||||
<<dummy/../../../framework/datamodel/datamodel-properties#datamodel.properties.converter,"Converting | |||||
Between Model and Presentation Types">>. | |||||
<<dummy/../../../framework/datamodel/datamodel-forms.asciidoc#datamodel.forms.conversion,"Conversion">>. | |||||
(((range="endofrange", startref="term.components.fields"))) | (((range="endofrange", startref="term.components.fields"))) |
To use bean validation as in the example above, you need to include an | To use bean validation as in the example above, you need to include an | ||||
implementation of the Bean Validation API in the classpath, as described in | implementation of the Bean Validation API in the classpath, as described in | ||||
<<dummy/../../../framework/datamodel/datamodel-itembinding#datamodel.itembinding.beanvalidation,"Bean | |||||
Validation">>. | |||||
<<dummy/../../../framework/datamodel/datamodel-forms.asciidoc#datamodel.forms.beans,"Binding Beans to Forms">>. | |||||
ifdef::web[] | ifdef::web[] |
[classname]#AbstractComponent# is the base class for all user interface | [classname]#AbstractComponent# is the base class for all user interface | ||||
components. It is the (only) implementation of the [classname]#Component# | components. It is the (only) implementation of the [classname]#Component# | ||||
interface, implementing all the methods defined in the interface. | |||||
[classname]#AbstractComponent# has a single abstract method, | |||||
[methodname]#getTag()#, which returns the serialization identifier of a | |||||
particular component class. It needs to be implemented when (and only when) | |||||
creating entirely new components. [classname]#AbstractComponent# manages much of | |||||
the serialization of component states between the client and the server. | |||||
Creation of new components and serialization is described in | |||||
<<dummy/../../../framework/gwt/gwt-overview.asciidoc#gwt.overview,"Integrating | |||||
with the Server-Side">>. | |||||
interface, implementing all the methods defined in the interface. When | |||||
creating a new component, you should extend [classname]#AbstractComponent# or | |||||
one of its subclasses. | |||||
(((range="endofrange", startref="term.components.interfaces.abstractcomponent"))) | (((range="endofrange", startref="term.components.interfaces.abstractcomponent"))) |
As the size of the [classname]#Panel# in the above example is fixed and the | As the size of the [classname]#Panel# in the above example is fixed and the | ||||
width of [classname]#Label# is the default undefined, the [classname]#Label# | width of [classname]#Label# is the default undefined, the [classname]#Label# | ||||
will overflow the layout horizontally and be truncated. | will overflow the layout horizontally and be truncated. | ||||
<<figure.components.label>>. | |||||
//<<figure.components.label>>. | |||||
//// | //// | ||||
// TODO update figure to match new label settings in Vaadin Framwork 8 | // TODO update figure to match new label settings in Vaadin Framwork 8 |
Vaadin offers many alternative ways for selecting one or more items. The core | Vaadin offers many alternative ways for selecting one or more items. The core | ||||
library includes the following selection components, all based on either | library includes the following selection components, all based on either | ||||
`AbstractSingleSelect` or `AbstractMultiSelect` class: | |||||
// TODO Only use section numbers here, prefixed with "Section", not include section title | |||||
[classname]#AbstractSingleSelect# or [classname]#AbstractMultiSelect# class: | |||||
[classname]#ComboBox# (<<components-combobox#components.combobox,"ComboBox">>):: | [classname]#ComboBox# (<<components-combobox#components.combobox,"ComboBox">>):: | ||||
A drop-down list with a text box, where the user can type text to find matching items. | A drop-down list with a text box, where the user can type text to find matching items. | ||||
// Add an items to the ComboBox | // Add an items to the ComboBox | ||||
select.setItems(planets); | select.setItems(planets); | ||||
select.setItemCaptionGenerator(planet -> planet.getName()); | |||||
// or even select.setItemCaptionGenerator(Planet::getName); | |||||
select.setItemCaptionGenerator(Planet::getName); | |||||
// Select the first | // Select the first | ||||
select.setSelectedItem(planets.get(0)); | select.setSelectedItem(planets.get(0)); | ||||
// or | // or | ||||
select.setValue(planets.get(0)); | |||||
// select.setValue(planets.get(0)); | |||||
---- | ---- | ||||
In addition to a caption, an item can have an icon. The icon is set with | In addition to a caption, an item can have an icon. The icon is set with | ||||
for simple objects like String or Integers, but also for objects that have | for simple objects like String or Integers, but also for objects that have | ||||
human readable output for [methodname]#toString()# . | human readable output for [methodname]#toString()# . | ||||
[source, java] | |||||
---- | |||||
ComboBox<Planet> select = new ComboBox<>("Inner Planets"); | |||||
// A class that implements toString() | |||||
class Planet implements Serializable { | |||||
String planetName; | |||||
Planet(String name) { | |||||
planetName = name; | |||||
} | |||||
public String toString () { | |||||
return "The Planet " + planetName; | |||||
} | |||||
} | |||||
// Use such objects as items | |||||
List<Planet> planets = new ArrayList<>(); | |||||
planets.add(new Planet("Mercury")); | |||||
planets.add(new Planet("Venus")); | |||||
planets.add(new Planet("Earth")); | |||||
select.setItems(planets); | |||||
---- | |||||
Using a field of a item as caption: the caption is retrieved using the | Using a field of a item as caption: the caption is retrieved using the | ||||
[interfacename]#ItemCaptionGenerator# typically given as Java 8 lambda. | |||||
[source, java] | |||||
---- | |||||
// A class that implements toString() | |||||
class Planet implements Serializable { | |||||
Integer id; | |||||
String planetName; | |||||
Planet(Integer id, String name) { | |||||
this.id = id | |||||
this.planetName = name; | |||||
} | |||||
public String toString () { | |||||
return "The Planet " + planetName; | |||||
} | |||||
public Integer getId () { | |||||
return id; | |||||
} | |||||
public String getName () { | |||||
return planetName; | |||||
} | |||||
} | |||||
// Put some example data | |||||
List<Planet> planets = new ArrayList<>(); | |||||
planets.add(new Planet(1, "Mercury")); | |||||
planets.add(new Planet(2, "Venus")); | |||||
planets.add(new Planet(3, "Earth")); | |||||
planets.add(new Planet(4, "Mars")); | |||||
// Create a selection component | |||||
ComboBox<Planet> select = | |||||
new ComboBox<>("Planets"); | |||||
// Set the caption generator to read the | |||||
// caption directly from the 'name' | |||||
// property of the bean | |||||
select.setItemCaptionGenerator(Planet::getName); | |||||
---- | |||||
[interfacename]#ItemCaptionGenerator# typically given as a lambda or a method reference. | |||||
[[components.selection.item-icons]] | [[components.selection.item-icons]] | ||||
elements. | elements. | ||||
[[components.selection.newitems]] | |||||
== Allowing Adding New Items | |||||
[classname]#ComboBox# allows the user to add new items, when the user types | |||||
in a value and presses kbd:[Enter]. You need to enable this with | |||||
[methodname]#setNewItemHandler()#. | |||||
Adding new items is not possible if the selection component is read-only. An | |||||
attempt to do so may result in an exception. | |||||
[[components.selection.newitems.handling]] | |||||
=== Handling New Items | |||||
Adding new items is handled by a [interfacename]#NewItemHandler#, which gets the | |||||
item caption string as parameter for the [methodname]#accept(String)# method. | |||||
ifdef::web[] | |||||
[source, java] | |||||
---- | |||||
// List of planets | |||||
List<Planet> planets = new ArrayList<>(); | |||||
planets.add(new Planet(1, "Mercury")); | |||||
planets.add(new Planet(2, "Venus")); | |||||
planets.add(new Planet(3, "Earth")); | |||||
planets.add(new Planet(4, "Mars")); | |||||
ComboBox<Planet> select = | |||||
new ComboBox<>("Select or Add a Planet"); | |||||
select.setItems(planets); | |||||
// Use the name property for item captions | |||||
select.setItemCaptionGenerator(Planet::getName); | |||||
// Allow adding new items and add | |||||
// handling for new items | |||||
select.setNewItemHandler(inputString -> { | |||||
// Create a new bean - can't set all properties | |||||
Planet newPlanet = new Planet(0, inputString); | |||||
planets.add(newPlanet); | |||||
// Update combobox content | |||||
select.setItems(planets); | |||||
// Remember to set the selection to the new item | |||||
select.select(newPlanet); | |||||
Notification.show("Added new planet called " + | |||||
inputString); | |||||
}); | |||||
[[components.selection.getset]] | [[components.selection.getset]] | ||||
== Getting and Setting Selection | == Getting and Setting Selection | ||||
For a better overview on how selection works, see link:../datamodel/datamodel-selection.asciidoc[Selecting items] | For a better overview on how selection works, see link:../datamodel/datamodel-selection.asciidoc[Selecting items] | ||||
You can get selected the item with [methodname]#getValue()# of the | You can get selected the item with [methodname]#getValue()# of the | ||||
[classname]#HasValue# interface that returns either a single selected item | |||||
(case of `SingleSelect`) or a collection of selected items (case of `MultiSelect`). | |||||
[interfacename]#HasValue# interface that returns either a single selected item | |||||
(case of [interfacename]#SingleSelect#) or a collection of selected items (case of [interfacename]#MultiSelect#). | |||||
You can select an item with the corresponding [methodname]#setValue()# method. | You can select an item with the corresponding [methodname]#setValue()# method. | ||||
The [classname]#ComboBox# and [classname]#NativeSelect# will show empty | The [classname]#ComboBox# and [classname]#NativeSelect# will show empty | ||||
[[components.selection.valuechange]] | [[components.selection.valuechange]] | ||||
== Handling Selection Changes | |||||
== Handling Selection Events | |||||
You can access the currently selected item with the [methodname]#getValue()# (`SingleSelect`) or | |||||
[methodname]#getSelectedItems()# (`MultiSelect`) method of the component. Also, when | |||||
handling selection changes with a | |||||
You can access the currently selected item with the [methodname]#getValue()# ([interfacename]#SingleSelect#) or | |||||
[methodname]#getSelectedItems()# ([interfacename]#MultiSelect#) method of the component. Also, when | |||||
handling selection events with a | |||||
[classname]#SelectionListener#, the | [classname]#SelectionListener#, the | ||||
[classname]#SelectionEvent# will have the selected items of the event. Single- and Multiselect | [classname]#SelectionEvent# will have the selected items of the event. Single- and Multiselect | ||||
components have their own more specific listener and event types, `SingleSelectionListener` for `SingleSelectionEvent` and `MultiSelectionListener` for `MultiSelectionEvent` respectively. Both can be added with the `addSelectionListener` method. | |||||
components have their own more specific listener and event types, [interfacename]#SingleSelectionListener# for [classname]#SingleSelectionEvent# and [interfacename]#MultiSelectionListener# for [classname]#MultiSelectionEvent# respectively. Both can be added with the [methodname]#addSelectionListener# method. | |||||
[source, java] | [source, java] | ||||
ComboBox<String> select = new ComboBox<>("My Select"); | ComboBox<String> select = new ComboBox<>("My Select"); | ||||
select.setItems("Io", "Europa", "Ganymedes", "Callisto"); | select.setItems("Io", "Europa", "Ganymedes", "Callisto"); | ||||
// Handle selection change | |||||
// Handle selection event | |||||
select.addSelectionListener(event -> | select.addSelectionListener(event -> | ||||
layout.addComponent(new Label("Selected " + | layout.addComponent(new Label("Selected " + | ||||
event.getSelectedItem().orElse("none"))); | event.getSelectedItem().orElse("none"))); | ||||
image::img/select-selected1.png[width=30%, scaledwidth=40%] | image::img/select-selected1.png[width=30%, scaledwidth=40%] | ||||
---- | |||||
endif::web[] | |||||
[[components.selection.multiple]] | [[components.selection.multiple]] | ||||
== Multiple Selection | == Multiple Selection | ||||
they extend [classname]#AbstractMultiSelect# class. | they extend [classname]#AbstractMultiSelect# class. | ||||
Multiselect components use the `MultiSelect` interface which extends `HasValue`. | |||||
This provides more fine grained API for selection. You can get and set the selection with the [methodname]#MultiSelect.getSelectedItems()# and | |||||
[methodname]#SelectionModel.Multi.selectItems()# methods. | |||||
Multiselect components use the [interfacename]#MultiSelect# interface which extends [interfacename]#HasValue#. | |||||
This provides more fine grained API for selection. You can get and set the selection with the [methodname]#getSelectedItems()# and | |||||
[methodname]#select()# methods. | |||||
A change in the selection will trigger a [classname]#SelectionChange#, which | |||||
you can handle with a [classname]#SelectionChangeListener#. The | |||||
A change in the selection will trigger a [classname]#SelectionEvent#, which | |||||
you can handle with a [classname]#SelectionListener#. The | |||||
following example shows how to handle selection changes with a listener. | following example shows how to handle selection changes with a listener. | ||||
[classname]#TextField# edits [classname]#String# values, but you can use [classname]#Binder# | [classname]#TextField# edits [classname]#String# values, but you can use [classname]#Binder# | ||||
to bind it to any property type that has a proper converter, as described in | to bind it to any property type that has a proper converter, as described in | ||||
<<dummy/../../../framework/datamodel/datamodel-properties#datamodel.properties.converter,"Converting | |||||
Between Property Type and Representation">>. | |||||
<<dummy/../../../framework/datamodel/datamodel-forms.asciidoc#datamodel.forms.conversion,"Conversion">>. | |||||
Much of the API of [classname]#TextField# is defined in | Much of the API of [classname]#TextField# is defined in | ||||
[classname]#AbstractTextField#, which allows different kinds of text input | [classname]#AbstractTextField#, which allows different kinds of text input |
`Binder` supports checking the validity of the user's input and converting the values between the type used in business objects and the bound UI components. | `Binder` supports checking the validity of the user's input and converting the values between the type used in business objects and the bound UI components. | ||||
These to concepts go hand in hand since validation can be based on a converted value, and being able to convert a value is a kind of validation. | These to concepts go hand in hand since validation can be based on a converted value, and being able to convert a value is a kind of validation. | ||||
[[datamodel.forms.validation]] | |||||
=== Validation | === Validation | ||||
An application typically has some restrictions on exactly what kinds of values the user is allowed to enter into different fields. | An application typically has some restrictions on exactly what kinds of values the user is allowed to enter into different fields. | ||||
departing.addValueChangeListener(event -> returnBinding.validate()); | departing.addValueChangeListener(event -> returnBinding.validate()); | ||||
---- | ---- | ||||
[[datamodel.forms.conversion]] | |||||
=== Conversion | === Conversion | ||||
You can also bind application data to a UI field component even though the types do not match. | You can also bind application data to a UI field component even though the types do not match. | ||||
When using the `setBean` method, the business object instance will be updated whenever the user changes the value in any bound field. | When using the `setBean` method, the business object instance will be updated whenever the user changes the value in any bound field. | ||||
If some other part of the application is also using the same instance, then that part might show changes before the user has clicked the save button. | If some other part of the application is also using the same instance, then that part might show changes before the user has clicked the save button. | ||||
[[datamodel.forms.beans]] | |||||
== Binding Beans to Forms | == Binding Beans to Forms | ||||
The business objects used in an application are in most cases implemented as Java beans or POJOs. | The business objects used in an application are in most cases implemented as Java beans or POJOs. |