Class FormBinder<T>
- Type Parameters:
T- The class/record type bound by this binder.
- All Implemented Interfaces:
com.vaadin.flow.component.HasValue<FormBinderValueChangeEvent<T>, T>, Serializable
Binder.
Note, that this is still a fairly new class, so there might be API changes to it.
Design principles:
- Only support "non-buffered mode" so that validation logic can use the bean/record + simplicity of the implementation
- Validation is "just validation", and not concern of this class. BUT, API must support binding external validation logic, like Bean Validation API
- Must support Records and immutable objects as well
- No requirements for BeanValidation or Spring DataBinding stuff, but optional support (or extensible for those)
- Aiming for binding anything without property names (for good solution this needs to be resolved at language level and supported with thing like Bean Validation first)
- Being a field in another form. A binder binds the fields of a form; it is
not one. When a property is itself a value worth editing as a unit, put its
fields in a
CustomFieldand bind that — a CustomField is a component, it can show a violation of its own, and it can use a FormBinder of its own inside. SeeFormBinderKnownIssuesTest#aCompositionIsBoundThroughACustomFieldfor the whole of it.
- See Also:
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic classNested classes/interfaces inherited from interface com.vaadin.flow.component.HasValue
com.vaadin.flow.component.HasValue.ValueChangeEvent<V>, com.vaadin.flow.component.HasValue.ValueChangeListener<E> -
Constructor Summary
ConstructorsConstructorDescriptionFormBinder(Class<T> tClass, com.vaadin.flow.component.Component... containerComponents) Constructs a new binder.FormBinder(Class<T> tClass, Object editorObject) Deprecated.not sure yet if this is a good idea, added for backwards compatibilityFormBinder(Class<T> tClass, Map<String, com.vaadin.flow.component.HasValue> propertyNameToEditor) Binds type to given property editorsFormBinder(tools.jackson.databind.introspect.BasicBeanDescription bdd) Constructs a new binder for semi-manual wiring.FormBinder(T dto, com.vaadin.flow.component.Component... containerComponents) Binds given dto to the UI fields found from given component(s). -
Method Summary
Modifier and TypeMethodDescriptioncom.vaadin.flow.shared.RegistrationaddValidValueChangeListener(com.vaadin.flow.component.HasValue.ValueChangeListener<? super FormBinderValueChangeEvent<T>> listener) Adds a listener for changes the reader made that left the form in a usable state.com.vaadin.flow.shared.RegistrationaddValueChangeListener(com.vaadin.flow.component.HasValue.ValueChangeListener<? super FormBinderValueChangeEvent<T>> listener) protected voidapplyConstraintsToEditor(tools.jackson.databind.introspect.BeanPropertyDefinition property, com.vaadin.flow.component.HasValue<?, ?> hasValue) Hands the constraints a field can enforce itself over to the field.voidbindProperty(tools.jackson.databind.introspect.BeanPropertyDefinition property, com.vaadin.flow.component.HasValue hasValue) Binds given property to the given editor field.voidRemoves all validation errors from bound fields andgetClassLevelViolationDisplay().protected voidconfigureEditor(tools.jackson.databind.introspect.BeanPropertyDefinition property, com.vaadin.flow.component.HasValue hasValue) protected Tprotected Tcom.vaadin.flow.component.HasComponentsGets the class level violation display.com.vaadin.flow.component.HasValuecom.vaadin.flow.component.HasValuegetEditor(PropertyRef<T, ?> property) Returns the field editing the given property, naming it with a method reference to its getter instead of a string.Returns a map containing input conversion errors (propertyname-error).Class<?>[]getValue()The value the form currently holds.protected voidhandleClassLevelValidations(Set<jakarta.validation.ConstraintViolation<T>> violations) protected ObjecthandleInputConversionError(tools.jackson.databind.introspect.BeanPropertyDefinition property, com.vaadin.flow.data.binder.ValueContext ctx, String conversionErrorMsg) Handles input conversion error.booleanChecks if there have recently been errors to convert value from the UI to the domain object.protected booleanignoreRequiredConstraintForField(jakarta.validation.ConstraintViolation<T> cv, com.vaadin.flow.component.HasValue hasValue) By default, if a validation is "required" validation for a field that user has not touched, it is not reported in the UI, but is taken otherwise into accound.booleanisEmpty()Whether every bound editor is empty.protected booleanbooleanprotected booleanisReadOnly(tools.jackson.databind.introspect.BeanPropertyDefinition property) protected booleanisRequired(tools.jackson.databind.introspect.BeanPropertyDefinition property) protected static booleanisRequired(tools.jackson.databind.introspect.BeanPropertyDefinition property, Class<?>[] activeGroups) booleanbooleanisValid()voidsetClassLevelValidationViolationComponentProvider(com.vaadin.flow.function.SerializableFunction<String, com.vaadin.flow.component.Component> classLevelValidationViolationComponentProvider) voidsetClassLevelViolationDisplay(com.vaadin.flow.component.HasComponents display) Sets the container component where "class level" constraint violations are displayed.voidsetConstraintViolations(Set<jakarta.validation.ConstraintViolation<T>> violations) Set the constraint violations found during validation.voidsetConverter(String property, com.vaadin.flow.data.converter.Converter<?, ?> strToDt) Sets a converter to use between the domain model property and the corresponding UI component editing it.voidsetConverter(PropertyRef<T, ?> property, com.vaadin.flow.data.converter.Converter<?, ?> strToDt) Sets a converter to use between the domain model property and the corresponding UI component editing it, naming the property with a method reference to its getter instead of a string.voidsetIgnoreServerOriginatedChanges(boolean ignore) A flag to control whether server originated value change events should be ignored.voidsetRawConstraintViolation(String property, String message) Reports a single constraint violation for the given property.voidsetRawConstraintViolation(PropertyRef<T, ?> property, String message) Reports a single constraint violation, naming the property with a method reference to its getter instead of a string:voidsetRawConstraintViolations(Map<String, String> propertyToViolation) An alternative API to report constraint violations without BeanValidation API on the classpath.voidsetReadOnly(boolean readOnly) Not supported: a binder binds the fields of a form rather than being one.voidsetRequiredIndicatorVisible(boolean requiredIndicatorVisible) Not supported: a binder has no place to show a required indicator, and marking every bound field required would say something else entirely.voidsetValidationGroups(Class<?>... groups) Sets the active validation groups.voidSets the value object bound to this form.voidunBind()Clears bindings, might be needed to clean up references if e.g. re-using fieldsMethods inherited from class Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, waitMethods inherited from interface com.vaadin.flow.component.HasValue
bindReadOnly, bindRequiredIndicatorVisible, bindValue, clear, getEmptyValue, getOptionalValue
-
Constructor Details
-
FormBinder
Constructs a new binder.- Parameters:
tClass- the class of the bound entity/bean, set later withsetValue(Object)containerComponents- the components whose class contains the fields to bound
-
FormBinder
Deprecated.not sure yet if this is a good idea, added for backwards compatibilityConstructs a new binder.- Parameters:
tClass- the class of the bound entity/bean, set later withsetValue(Object)editorObject- the editor object that contains the fields to bound, does not need to be a component
-
FormBinder
-
FormBinder
public FormBinder(tools.jackson.databind.introspect.BasicBeanDescription bdd) Constructs a new binder for semi-manual wiring. Not designed for general use, but can be handy for some special cases. -
FormBinder
Binds given dto to the UI fields found from given component(s).- Parameters:
dto- the object to bind. The type of the FormBinder will be taken from this object.containerComponents- the components whose class contains the fields to bound
-
-
Method Details
-
setValidationGroups
Sets the active validation groups. This affects which fields show the required indicator based on their constraint annotations' group membership.- Parameters:
groups- the validation groups to activate
-
getValidationGroups
-
isRequired
protected boolean isRequired(tools.jackson.databind.introspect.BeanPropertyDefinition property) -
isRequired
protected static boolean isRequired(tools.jackson.databind.introspect.BeanPropertyDefinition property, Class<?>[] activeGroups) -
applyConstraintsToEditor
protected void applyConstraintsToEditor(tools.jackson.databind.introspect.BeanPropertyDefinition property, com.vaadin.flow.component.HasValue<?, ?> hasValue) Hands the constraints a field can enforce itself over to the field.@NotNullhas always reached the widget as a required indicator, and that one mapping does real work: a required field refuses to be emptied, so the constraint is met in the browser rather than reported after the fact. The same is available for the limits —@Size(max = 64)is a maxlength, and the developer should not have to write it twice.Only bounds that mean exactly what the field means:
- a limit the developer already set is kept. They knew something; the constraint is still checked where it always was.
- strict bounds are left out.
@Positiveis "greater than zero" while a field's minimum is inclusive, and there is no next double after zero to use instead. A field that allowed zero while the constraint refused it would be a worse lie than no limit at all. @Patternis left out too: the expression would be handed to the browser, and a Java regular expression is not a JavaScript one.- constraints belonging to a validation group are left out. Which groups are active is decided after binding, and a limit cannot be un-set per group.
- Parameters:
property- the property being boundhasValue- the editor bound to it
-
isReadOnly
protected boolean isReadOnly(tools.jackson.databind.introspect.BeanPropertyDefinition property) -
bindProperty
public void bindProperty(tools.jackson.databind.introspect.BeanPropertyDefinition property, com.vaadin.flow.component.HasValue hasValue) Binds given property to the given editor field.- Parameters:
property- the property to bindhasValue- the editor field to bind
-
configureEditor
protected void configureEditor(tools.jackson.databind.introspect.BeanPropertyDefinition property, com.vaadin.flow.component.HasValue hasValue) -
handleInputConversionError
protected Object handleInputConversionError(tools.jackson.databind.introspect.BeanPropertyDefinition property, com.vaadin.flow.data.binder.ValueContext ctx, String conversionErrorMsg) Handles input conversion error. By default, the error message saved and set to the field.- Parameters:
property-ctx-conversionErrorMsg-- Returns:
- the value to be set to the edited object, null by default
-
getValue
The value the form currently holds.For a record a new instance is built from the editors on every call: that is what immutability leaves available, and record equality makes it invisible.
For a mutable bean the object that was set is returned, and it is the same object every time — the binder writes the changes into it as they are made. When nothing has been set, one is built from the editors on the first ask and kept from then on, so that both cases behave alike: a caller may hold on to what it was given and write into it without the next call handing back something else. Building a fresh bean per call, as this used to, made such a write disappear without a word.
Emptying the form with
setValue(null)lets go of that bean as well; the next call builds another.- Specified by:
getValuein interfacecom.vaadin.flow.component.HasValue<FormBinderValueChangeEvent<T>, T>- Returns:
- the value, never null
-
setValue
Sets the value object bound to this form.A
nullvalue is accepted and empties the form: every bound editor is cleared to its own empty value and validation errors are removed. This is the empty value of a binder, soHasValue.clear(), which theHasValuecontract defines assetValue(getEmptyValue()), does the same thing. It also matchesBinder.setBean(null)in Vaadin's own binder.Note that
getValue()does not return null afterwards: with no value object bound it constructs one from the current editor values, which is what makes a binder usable for creating a new object as well as for editing one.- Specified by:
setValuein interfacecom.vaadin.flow.component.HasValue<FormBinderValueChangeEvent<T>, T>- Parameters:
valueObject- the new value, or null to empty the form
-
isEmpty
public boolean isEmpty()Whether every bound editor is empty.HasValuedefines this as the value being equal toHasValue.getEmptyValue(), and that comparison cannot answer it here. The empty value of a form would have to be an object built from empty editors, and such an object cannot always be built — a record with a primitive component has none — nor recognised, since a mutable bean is equal to nothing but itself unless someone wrote it an equals. So the question goes to the editors, where "empty" is already defined exactly for each of them: an empty text field, a number field with nothing in it, an unticked checkbox.This is therefore about the form rather than about the value. A component of the value that no editor edits — an identifier carried over from the object that was set — does not make the form non-empty. "Nothing has been typed here" is the question a form can answer.
A binder with no editors bound at all is empty, for the same reason.
- Specified by:
isEmptyin interfacecom.vaadin.flow.component.HasValue<FormBinderValueChangeEvent<T>, T>- Returns:
- true if no bound editor holds a value
-
withValue
-
addValueChangeListener
public com.vaadin.flow.shared.Registration addValueChangeListener(com.vaadin.flow.component.HasValue.ValueChangeListener<? super FormBinderValueChangeEvent<T>> listener) - Specified by:
addValueChangeListenerin interfacecom.vaadin.flow.component.HasValue<FormBinderValueChangeEvent<T>, T>
-
addValidValueChangeListener
public com.vaadin.flow.shared.Registration addValidValueChangeListener(com.vaadin.flow.component.HasValue.ValueChangeListener<? super FormBinderValueChangeEvent<T>> listener) Adds a listener for changes the reader made that left the form in a usable state.The two conditions a "save as you type" form checks, in one place: the change came from the client rather than from the application filling the fields, and nothing is currently reported as wrong.
"Wrong" means what this binder has been told, since a binder shows violations rather than producing them — a conversion error it noticed itself, and the violations last handed to
setConstraintViolations(Set). If you feed those from a listener of your own, add that listener first, or this one will answer about the change before last.BeanValidationFormhas no such order to get right: it registers its own validating listener when the binder is created.- Parameters:
listener- the listener- Returns:
- a registration for removing it
-
isReadOnly
public boolean isReadOnly()- Specified by:
isReadOnlyin interfacecom.vaadin.flow.component.HasValue<FormBinderValueChangeEvent<T>, T>
-
setReadOnly
public void setReadOnly(boolean readOnly) Not supported: a binder binds the fields of a form rather than being one.- Specified by:
setReadOnlyin interfacecom.vaadin.flow.component.HasValue<FormBinderValueChangeEvent<T>, T>- Throws:
UnsupportedOperationException- always
-
isRequiredIndicatorVisible
public boolean isRequiredIndicatorVisible()- Specified by:
isRequiredIndicatorVisiblein interfacecom.vaadin.flow.component.HasValue<FormBinderValueChangeEvent<T>, T>
-
setRequiredIndicatorVisible
public void setRequiredIndicatorVisible(boolean requiredIndicatorVisible) Not supported: a binder has no place to show a required indicator, and marking every bound field required would say something else entirely.- Specified by:
setRequiredIndicatorVisiblein interfacecom.vaadin.flow.component.HasValue<FormBinderValueChangeEvent<T>, T>- Throws:
UnsupportedOperationException- always
-
isImmutable
protected boolean isImmutable() -
constructRecord
-
constructPojo
-
setConstraintViolations
Set the constraint violations found during validation. If violation is bound to a bound property, it is shown next to the field, otherwise shown at "form level", seesetClassLevelViolationDisplay(HasComponents).- Parameters:
violations- the constraint violations that should be shown in the UI
-
ignoreRequiredConstraintForField
protected boolean ignoreRequiredConstraintForField(jakarta.validation.ConstraintViolation<T> cv, com.vaadin.flow.component.HasValue hasValue) By default, if a validation is "required" validation for a field that user has not touched, it is not reported in the UI, but is taken otherwise into accound.- Parameters:
cv- validation constrainghasValue- the field to be tested- Returns:
- true if should be ignored based on emptry validity
-
getClassLevelViolationDisplay
public com.vaadin.flow.component.HasComponents getClassLevelViolationDisplay()Gets the class level violation display. If not set, the first container component is used if of appropriate type.- Returns:
- the component where constraint violations will be displayed
-
setClassLevelViolationDisplay
public void setClassLevelViolationDisplay(com.vaadin.flow.component.HasComponents display) Sets the container component where "class level" constraint violations are displayed.- Parameters:
display- the component where the "class level" constraint violations will be displayed.
-
handleClassLevelValidations
-
setClassLevelValidationViolationComponentProvider
public void setClassLevelValidationViolationComponentProvider(com.vaadin.flow.function.SerializableFunction<String, com.vaadin.flow.component.Component> classLevelValidationViolationComponentProvider) -
setRawConstraintViolations
-
setRawConstraintViolation
Reports a single constraint violation, naming the property with a method reference to its getter instead of a string:
Likebinder.setRawConstraintViolation(Account::getPasswordVerification, "Passwords do not match!");setRawConstraintViolations(Map), of which this is the single property form, this replaces the violations currently shown. Use the map version to report several at once.- Parameters:
property- a method reference to the getter of the property the violation is aboutmessage- the message to show
-
setRawConstraintViolation
-
clearValidationErrors
public void clearValidationErrors()Removes all validation errors from bound fields andgetClassLevelViolationDisplay(). -
setConverter
Sets a converter to use between the domain model property and the corresponding UI component editing it.- Parameters:
property- the propertystrToDt- the converter
-
setConverter
public void setConverter(PropertyRef<T, ?> property, com.vaadin.flow.data.converter.Converter<?, ?> strToDt) Sets a converter to use between the domain model property and the corresponding UI component editing it, naming the property with a method reference to its getter instead of a string.- Parameters:
property- a method reference to the getter of the propertystrToDt- the converter
-
hasInputConversionErrors
public boolean hasInputConversionErrors()Checks if there have recently been errors to convert value from the UI to the domain object.- Returns:
- true if there are active conversion errors
-
getInputConversionErrors
-
isValid
public boolean isValid()- Returns:
- true if the binging looks valid for the user: no displayed constraint violations nor input conversion errors.
-
setIgnoreServerOriginatedChanges
public void setIgnoreServerOriginatedChanges(boolean ignore) A flag to control whether server originated value change events should be ignored. Currently only known to be needed for testing, might be removed in the future.- Parameters:
ignore- true if non-client originated events should be ignored
-
unBind
public void unBind()Clears bindings, might be needed to clean up references if e.g. re-using fields -
getBoundProperties
-
getEditor
-
getEditor
Returns the field editing the given property, naming it with a method reference to its getter instead of a string.- Parameters:
property- a method reference to the getter of the property- Returns:
- the field bound to the property, or null if none is bound
-