|
|
@@ -10,8 +10,8 @@ layout: page |
|
|
|
((("[classname]#Field#", id="term.components.fields", range="startofrange"))) |
|
|
|
|
|
|
|
_Fields_ are components that have a value that the user can change through the |
|
|
|
user interface. |
|
|
|
<<figure.components.fields>> illustrates the inheritance relationships and the important interfaces and base classes. |
|
|
|
user interface. <<figure.components.fields>> illustrates the inheritance relationships |
|
|
|
and the important interfaces and base classes. |
|
|
|
|
|
|
|
[[figure.components.fields]] |
|
|
|
.Field components |
|
|
@@ -69,114 +69,93 @@ guide. |
|
|
|
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. |
|
|
|
|
|
|
|
[[components.fields.databinding]] |
|
|
|
== Data Binding and Conversions |
|
|
|
|
|
|
|
Fields and selects can be coupled with business data objects with the [classname]#Binder# class. |
|
|
|
Select components also allow management of the selectable items through the |
|
|
|
[classname]#DataSource# interface. [classname]#Binder# and [classname]#DataSource# |
|
|
|
can be thought of as bridges between the __presentation__ and __model__ architectural layers. |
|
|
|
|
|
|
|
Fields are __editors__ for values of some particular type. For example, |
|
|
|
[classname]#TextField# allows editing [classname]#String# values. When bound to |
|
|
|
a data source, the type of the source property can be something different, |
|
|
|
say an [classname]#Integer#. __Converters__ are used for converting the values |
|
|
|
between the presentation and the model. They are described in |
|
|
|
<<dummy/../../../framework/datamodel/datamodel-properties#datamodel.properties.converter,"Converting |
|
|
|
Between Model and Presentation Types">>. |
|
|
|
|
|
|
|
|
|
|
|
[[components.fields.valuechanges]] |
|
|
|
== Handling Field Value Changes |
|
|
|
|
|
|
|
[classname]#Field# inherits [classname]#Property.ValueChangeListener# to allow |
|
|
|
listening for field value changes and [classname]#Property.Editor# to allow |
|
|
|
editing values. |
|
|
|
|
|
|
|
When the value of a field changes, a [classname]#Property.ValueChangeEvent# is |
|
|
|
triggered for the field. You should not implement the |
|
|
|
[methodname]#valueChange()# method in a class inheriting |
|
|
|
[classname]#AbstractField#, as it is already implemented in |
|
|
|
[classname]#AbstractField#. You should instead implement the method explicitly |
|
|
|
by adding the implementing object as a listener. |
|
|
|
[classname]#Field# provides two methods for listening to changes to the field value: |
|
|
|
[methodname]#onValueChange# and [methodname]#addValueChangeListener#. The difference |
|
|
|
is that the former takes a [interfacename]#Consumer# object that only receives the new value; |
|
|
|
the latter, on the other hand, takes an [interfacename]#EventListener# that gets |
|
|
|
a [classname]#ValueChange# event instance containing extra information about the event. |
|
|
|
|
|
|
|
Both methods return a [classname]#Registration# object that can be used to later |
|
|
|
remove the added listener if necessary. |
|
|
|
|
|
|
|
[[components.fields.buffering]] |
|
|
|
== Field Buffering |
|
|
|
[source, java] |
|
|
|
---- |
|
|
|
TextField textField = new TextField(); |
|
|
|
Label echo = new Label(); |
|
|
|
|
|
|
|
// Just echo in the label anything the user enters |
|
|
|
textField.onValueChange(echo::setValue); |
|
|
|
|
|
|
|
// Add a more complex listener |
|
|
|
textField.addValueChangeListener(event -> { |
|
|
|
String origin = event.isUserOriginated() |
|
|
|
? "user" |
|
|
|
: "application"; |
|
|
|
String message = origin |
|
|
|
+ " entered the following: " |
|
|
|
+ event.getValue(); |
|
|
|
Notification.show(message); |
|
|
|
}); |
|
|
|
---- |
|
|
|
|
|
|
|
Field components implement the [interfacename]#Buffered# and |
|
|
|
[interfacename]#BufferedValidatable# interfaces. When buffering is enabled for a |
|
|
|
field with [methodname]#setBuffered(true)#, the value is not written to the |
|
|
|
property data source before the [methodname]#commit()# method is called for the |
|
|
|
field. Calling [methodname]#commit()# also runs validators added to the field, |
|
|
|
and if any fail (and the [parameter]#invalidCommitted# is disabled), the value |
|
|
|
is not written. |
|
|
|
[[components.fields.databinding]] |
|
|
|
== Binding Fields to Data |
|
|
|
|
|
|
|
Fields can be grouped into _forms_ and coupled with business data objects with |
|
|
|
the [classname]#Binder# class. When a field is bound to a property using |
|
|
|
[classname]#Binder#, it gets its default value from the property, and |
|
|
|
is stored to the property either manually via the [methodname]#Binder.save# method, |
|
|
|
or automatically every time the value changes. |
|
|
|
|
|
|
|
[source, java] |
|
|
|
---- |
|
|
|
form.addComponent(new Button("Commit", |
|
|
|
new Button.ClickListener() { |
|
|
|
@Override |
|
|
|
public void buttonClick(ClickEvent event) { |
|
|
|
try { |
|
|
|
editor.commit(); |
|
|
|
} catch (InvalidValueException e) { |
|
|
|
Notification.show(e.getMessage()); |
|
|
|
} |
|
|
|
} |
|
|
|
})); |
|
|
|
---- |
|
|
|
See the http://demo.vaadin.com/book-examples-vaadin7/book#component.field.buffering.basic[on-line example, window="_blank"]. |
|
|
|
class Person { |
|
|
|
private String name; |
|
|
|
public String getName() { /* ... */ } |
|
|
|
public void setName(String) { /* ... */ } |
|
|
|
} |
|
|
|
|
|
|
|
Calling [methodname]#discard()# reads the value from the property data source to |
|
|
|
the current input. |
|
|
|
TextField nameField = new TextField(); |
|
|
|
|
|
|
|
If the fields are bound in a [classname]#FieldGroup# that has buffering enabled, |
|
|
|
calling [methodname]#commit()# for the group runs validation on all fields in |
|
|
|
the group, and if successful, all the field values are written to the item data |
|
|
|
source. See |
|
|
|
<<dummy/../../../framework/datamodel/datamodel-itembinding#datamodel.itembinding.buffering,"Buffering |
|
|
|
Forms">>. |
|
|
|
Binder<Person> binder = new Binder<>(); |
|
|
|
|
|
|
|
// Bind nameField to the Person.name property |
|
|
|
// by specifying its getter and setter |
|
|
|
binder.addField(nameField) |
|
|
|
.bind(Person::getName, Person::setName); |
|
|
|
|
|
|
|
[[components.fields.validation]] |
|
|
|
== Field Validation |
|
|
|
// Bind an actual concrete Person instance. |
|
|
|
// After this, whenever the user changes the value |
|
|
|
// of nameField, p.setName is automatically called. |
|
|
|
Person p = new Person(); |
|
|
|
binder.bind(p; |
|
|
|
---- |
|
|
|
|
|
|
|
The input for a field component can be syntactically or semantically invalid. |
|
|
|
Fields implement the [interfacename]#Validatable# interface, which allows |
|
|
|
checking validity of the input with __validators__ that implement the |
|
|
|
[interfacename]#Validator# interface. You can add validators to fields with |
|
|
|
[methodname]#addValidator()#. |
|
|
|
== Validating Field Values |
|
|
|
|
|
|
|
User input may be syntactically or semantically invalid. |
|
|
|
[classname]#Binder# allows adding a chain of one or more __validators__ for |
|
|
|
automatically checking the validity of the input before storing it to the data |
|
|
|
object. You can add validators to fields by calling the [methodname]#addValidator# |
|
|
|
method on the [interfacename]#Binding# object returned by [methodname]#Binder.addField#. |
|
|
|
|
|
|
|
[source, java] |
|
|
|
---- |
|
|
|
TextField field = new TextField("Name"); |
|
|
|
field.addValidator(new StringLengthValidator( |
|
|
|
"The name must be 1-10 letters (was {0})", |
|
|
|
1, 10, true)); |
|
|
|
field.setNullRepresentation(""); |
|
|
|
field.setNullSettingAllowed(true); |
|
|
|
layout.addComponent(field); |
|
|
|
binder.addField(nameField) |
|
|
|
.addValidator(new StringLengthValidator(2, 20, |
|
|
|
"Name must be between 2 and 20 characters long")) |
|
|
|
.bind(Person::getName, Person::setName); |
|
|
|
---- |
|
|
|
See the http://demo.vaadin.com/book-examples-vaadin7/book#component.field.validation.basic[on-line example, window="_blank"]. |
|
|
|
|
|
|
|
Failed validation is indicated with the error indicator of the field, described |
|
|
|
in |
|
|
|
Failed validation is indicated with the error indicator of the field, described in |
|
|
|
<<dummy/../../../framework/application/application-errors#application.errors.error-indicator,"Error |
|
|
|
Indicator and Message">>, unless disabled with |
|
|
|
[methodname]#setValidationVisible(false)#. Hovering mouse on the field displays |
|
|
|
the error message given as a parameter for the validator. If validated |
|
|
|
explicitly with [methodname]#validate()#, as described later, the |
|
|
|
[classname]#InvalidValueException# is thrown if the validation fails, also |
|
|
|
carrying the error message. The value [literal]#++{0}++# in the error message |
|
|
|
string is replaced with the invalid input value. |
|
|
|
|
|
|
|
Validators validate the property type of the field after a possible conversion, |
|
|
|
not the presentation type. For example, an [classname]#IntegerRangeValidator# |
|
|
|
requires that the value type of the property data source is |
|
|
|
[classname]#Integer#. |
|
|
|
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, |
|
|
|
none of the field values are saved into the bound property until the validation |
|
|
|
passes. |
|
|
|
|
|
|
|
[[components.fields.validation.builtin]] |
|
|
|
=== Built-in Validators |
|
|
@@ -184,164 +163,67 @@ requires that the value type of the property data source is |
|
|
|
Vaadin includes the following built-in validators. The property value type is |
|
|
|
indicated. |
|
|
|
|
|
|
|
[classname]#BeanValidator#:: |
|
|
|
Validates a bean property according to annotations defined in the Bean Validation API 1.0 (JSR-303). |
|
|
|
This validator is usually not used explicitly, but they are created implicitly when binding fields in a [classname]#BeanFieldGroup#. |
|
|
|
Using bean validation requires an implementation library of the API. |
|
|
|
See <<dummy/../../../framework/datamodel/datamodel-itembinding#datamodel.itembinding.beanvalidation,"Bean Validation">> for details. |
|
|
|
|
|
|
|
[classname]#CompositeValidator#:: |
|
|
|
Combines validators using logical AND and OR operators. |
|
|
|
[classname]#RangeValidator#: [classname]#Comparable#:: |
|
|
|
Checks that the given [interfacename]#Comparable# value is at or between two given values. |
|
|
|
|
|
|
|
[classname]#DateRangeValidator#: [classname]#Date#:: |
|
|
|
Checks that the date value is within the range at or between two given dates/times. |
|
|
|
[classname]#StringLengthValidator#: [classname]#String#:: |
|
|
|
Checks that the length of the input string is at or between two given lengths. |
|
|
|
|
|
|
|
[classname]#DoubleRangeValidator#: [classname]#Double#:: |
|
|
|
Checks that the double value is at or between two given values. |
|
|
|
[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. |
|
|
|
|
|
|
|
[classname]#IntegerRangeValidator#: [classname]#Integer#:: |
|
|
|
Checks that the integer value is at or between two given values. |
|
|
|
|
|
|
|
[classname]#NullValidator#:: |
|
|
|
Checks whether the value is or is not a null value. |
|
|
|
+ |
|
|
|
For the validator to be meaningful, the component must support inputting null |
|
|
|
values. For example, for selection components and [classname]#TextField#, |
|
|
|
inputting null values can be enabled with [methodname]#setNullSettingAllowed()#. |
|
|
|
You also need to set the representation of null values: in selection components |
|
|
|
with [methodname]#setNullSelectionItemId()# and in [classname]#TextField# with |
|
|
|
[methodname]#setNullRepresentation()#. |
|
|
|
|
|
|
|
ifdef::web[] |
|
|
|
+ |
|
|
|
Setting field as __required__ can be used for similar effect, and it also |
|
|
|
enables an indicator to indicate that a value is required. |
|
|
|
endif::web[] |
|
|
|
|
|
|
|
[classname]#RegexpValidator#: [classname]#String#:: |
|
|
|
Checks that the value matches with the given regular expression. |
|
|
|
|
|
|
|
[classname]#StringLengthValidator#: [classname]#String#:: |
|
|
|
Checks that the length of the input string is at or between two given lengths. |
|
|
|
|
|
|
|
ifdef::web[] |
|
|
|
+ |
|
|
|
The [parameter]#allowNull# parameter determines whether null values should be |
|
|
|
allowed for the string, regardless of the string length. A null value has zero |
|
|
|
length, so it will be invalid if the minimum length is greater than zero. |
|
|
|
Allowing null value is meaningful only if inputting null values is enabled with |
|
|
|
[methodname]#setNullSettingAllowed(true)#, and typically in such case, you want |
|
|
|
to set the null representation to empty string with |
|
|
|
[methodname]#setNullRepresentation("")#. Note that _this parameter is |
|
|
|
deprecated_ and should normally be [parameter]#true#; then you can use |
|
|
|
[methodname]#setRequired()# (for the false case) or [classname]#NullValidator#. |
|
|
|
endif::web[] |
|
|
|
|
|
|
|
Please see the API documentation for more details. |
|
|
|
|
|
|
|
[[components.fields.validation.automatic]] |
|
|
|
=== Automatic Validation |
|
|
|
|
|
|
|
The validators are normally, when [literal]#++validationVisible++# is true for |
|
|
|
the field, executed implicitly on the next server request if the input has |
|
|
|
changed. If the field is in immediate mode, it (and any other fields with |
|
|
|
changed value) are validated immediately when the focus leaves the field. |
|
|
|
|
|
|
|
|
|
|
|
[source, java] |
|
|
|
---- |
|
|
|
TextField field = new TextField("Name"); |
|
|
|
field.addValidator(new StringLengthValidator( |
|
|
|
"The name must be 1-10 letters (was {0})", |
|
|
|
1, 10, true)); |
|
|
|
field.setImmediate(true); |
|
|
|
field.setNullRepresentation(""); |
|
|
|
field.setNullSettingAllowed(true); |
|
|
|
layout.addComponent(field); |
|
|
|
---- |
|
|
|
See the http://demo.vaadin.com/book-examples-vaadin7/book#component.field.validation.basic[on-line example, window="_blank"]. |
|
|
|
|
|
|
|
|
|
|
|
[[components.fields.validation.explicit]] |
|
|
|
=== Explicit Validation |
|
|
|
|
|
|
|
The validators are executed when the [methodname]#validate()# or |
|
|
|
[methodname]#commit()# methods are called for the field. |
|
|
|
=== Implementing Custom Validators |
|
|
|
|
|
|
|
Validators implement the [interfacename]#Validator# interface that simply |
|
|
|
extends [interfacename]#java.util.function.Function#, returning a special type |
|
|
|
called [interfacename]#Result#. This return type represents the validation outcome: |
|
|
|
whether or not the given input was valid. |
|
|
|
|
|
|
|
[source, java] |
|
|
|
---- |
|
|
|
// A field with automatic validation disabled |
|
|
|
final TextField field = new TextField("Name"); |
|
|
|
field.setNullRepresentation(""); |
|
|
|
field.setNullSettingAllowed(true); |
|
|
|
layout.addComponent(field); |
|
|
|
|
|
|
|
// Define validation as usual |
|
|
|
field.addValidator(new StringLengthValidator( |
|
|
|
"The name must be 1-10 letters (was {0})", |
|
|
|
1, 10, true)); |
|
|
|
|
|
|
|
// Run validation explicitly |
|
|
|
Button validate = new Button("Validate"); |
|
|
|
validate.addClickListener(new ClickListener() { |
|
|
|
class MyValidator implements Validator<String> { |
|
|
|
@Override |
|
|
|
public void buttonClick(ClickEvent event) { |
|
|
|
field.setValidationVisible(false); |
|
|
|
try { |
|
|
|
field.validate(); |
|
|
|
} catch (InvalidValueException e) { |
|
|
|
Notification.show(e.getMessage()); |
|
|
|
field.setValidationVisible(true); |
|
|
|
public Result<String> apply(String input) { |
|
|
|
if(input.length() == 6) { |
|
|
|
return Result.ok(input); |
|
|
|
} else { |
|
|
|
return Result.error( |
|
|
|
"Must be exactly six characters long"); |
|
|
|
} |
|
|
|
} |
|
|
|
}); |
|
|
|
layout.addComponent(validate); |
|
|
|
} |
|
|
|
---- |
|
|
|
See the http://demo.vaadin.com/book-examples-vaadin7/book#component.field.validation.explicit[on-line example, window="_blank"]. |
|
|
|
|
|
|
|
|
|
|
|
[[components.fields.validation.custom]] |
|
|
|
=== Implementing a Custom Validator |
|
|
|
|
|
|
|
You can create custom validators by implementing the [interfacename]#Validator# |
|
|
|
interface and implementing its [methodname]#validate()# method. If the |
|
|
|
validation fails, the method should throw either |
|
|
|
[classname]#InvalidValueException# or [classname]#EmptyValueException#. |
|
|
|
|
|
|
|
Because [methodname]#Result.ok# takes the valid value as an argument, a validator |
|
|
|
can also do some sanitization on valid inputs, such as removing leading and |
|
|
|
trailing whitespace from a string. Since [interfacename]#Validator# is a functional |
|
|
|
interface, you can often simply write a lambda expression instead of a full class |
|
|
|
declaration. There is also an [methodname]#addValidator# overload that creates a |
|
|
|
validator from a boolean function and an error message. |
|
|
|
|
|
|
|
[source, java] |
|
|
|
---- |
|
|
|
class MyValidator implements Validator { |
|
|
|
@Override |
|
|
|
public void validate(Object value) |
|
|
|
throws InvalidValueException { |
|
|
|
if (!(value instanceof String && |
|
|
|
((String)value).equals("hello"))) |
|
|
|
throw new InvalidValueException("You're impolite"); |
|
|
|
} |
|
|
|
} |
|
|
|
binder.addField(nameField) |
|
|
|
.addValidator(name -> name.length() < 20, |
|
|
|
"Name must be less than 20 characters long") |
|
|
|
.bind(Person::getName, Person::setName); |
|
|
|
|
|
|
|
TextField field = new TextField("Say hello"); |
|
|
|
field.addValidator(new MyValidator()); |
|
|
|
field.setImmediate(true); |
|
|
|
layout.addComponent(field); |
|
|
|
---- |
|
|
|
See the http://demo.vaadin.com/book-examples-vaadin7/book#component.field.validation.customvalidator[on-line example, window="_blank"]. |
|
|
|
|
|
|
|
== Converting Field Values |
|
|
|
|
|
|
|
[[components.fields.validation.fieldgroup]] |
|
|
|
=== Validation in Field Groups |
|
|
|
Field values are always of some particular type. For example, |
|
|
|
[classname]#TextField# allows editing [classname]#String# values. When bound to |
|
|
|
a data source, the type of the source property can be something different, |
|
|
|
say an [classname]#Integer#. __Converters__ are used for converting the values |
|
|
|
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">>. |
|
|
|
|
|
|
|
If the field is bound to a [classname]#FieldGroup#, described in |
|
|
|
<<dummy/../../../framework/datamodel/datamodel-itembinding#datamodel.itembinding,"Creating |
|
|
|
Forms by Binding Fields to Items">>, calling [methodname]#commit()# for the |
|
|
|
group runs the validation for all the fields in the group, and if successful, |
|
|
|
writes the input values to the data source. |
|
|
|
|
|
|
|
endif::disabled[] |
|
|
|
|