Form Validation
- Bean Validation Constraints
- Required Fields
- Error Messages
- Validators in the View
- Errors from the Service
A form validates its value in the browser, so that the user sees errors right away. The service validates the value again on the server, when the form is submitted. The browser runs the Bean Validation constraints of the Java type, and validators that the view adds. The server runs only the Bean Validation constraints, and checks of its own.
The browser validates a field when the user changes its value, and when the field loses focus. On submit, it validates the whole form.
Bean Validation Constraints
The generator copies these Jakarta Bean Validation constraints from the Java type to the form model, so that the browser checks them, too:
-
@AssertFalse,@AssertTrue -
@DecimalMax,@DecimalMin,@Digits,@Max,@Min -
@Negative,@NegativeOrZero,@Positive,@PositiveOrZero -
@Email,@NotBlank,@NotEmpty,@Pattern,@Size -
@Future,@Past -
@NotNull,@Null
Only the server checks other constraints, such as @PastOrPresent, @FutureOrPresent, and constraints of your own. Their errors appear in the fields after a submit, as described in Server-Side Validation.
For example, the Person record on Forms has these constraints:
Source code
Person.java
The @Valid annotations make the server validate the nested objects, too. The browser validates them in any case.
Required Fields
A field is required when its property has a @NotNull, @NotEmpty, or @NotBlank constraint, or a @Size constraint with a min greater than 0. The field() function sets the required state of the component, which shows an indicator.
When a field isn’t required and its value is empty, the browser doesn’t run its other validators. For example, an empty postal code passes a @Pattern constraint. A number field is an exception: an empty field for a non-nullable number fails with the message "must be a number".
Error Messages
When a constraint has no message attribute in Java, the browser shows a message of its own in English, such as "must not be blank". After a submit, the field shows the message of the server, which comes from Bean Validation. When the constraint has a message attribute, both use it.
The browser shows the message as it’s written in Java. It doesn’t replace placeholders such as {min}. To replace them, set the static interpolateMessageCallback property of BinderRoot, from @vaadin/hilla-lit-form. It gets the message and the validator, which has the attributes of the constraint as properties:
Source code
TypeScript
import { BinderRoot } from '@vaadin/hilla-lit-form';
BinderRoot.interpolateMessageCallback = (message, validator) =>
message.replace(/\{(\w+)\}/gu, (placeholder, name: string) =>
String((validator as unknown as Record<string, unknown>)[name] ?? placeholder),
);Validators in the View
A view can add validators of its own, for checks that have no Bean Validation constraint. Only the browser runs these validators, so they don’t protect the data. When the check matters, make the service check it, too.
A validator is an object with a message and a validate() function. The function gets the value, and returns whether it’s valid. It can also return a promise. Add the validators once, in an effect without dependencies.
The examples in this section use this record:
Source code
SignUp.java
Field Validators
To validate a single field, get its part of the form with useFormPart(), and call addValidator():
Source code
sign-up-form.tsx
The field shows the message of the validator when validate() returns false.
The validators of the Bean Validation constraints are also available as classes in @vaadin/hilla-lit-form, with the same names. For example, username.addValidator(new Size({ max: 20, message: 'At most 20 characters' })) adds a @Size check to a field in the browser.
Form Validators
A check that involves several fields belongs to the form. Call addValidator() of the form, and return the fields to mark from validate():
Source code
sign-up-form.tsx
The validate() function of a form validator gets the whole value of the form. It can return these values:
trueor an empty array-
The value is valid.
- An object or an array of objects with a
property, and an optionalmessage -
Each object marks the field of its
propertyas invalid. Thepropertyis the model of the field, or its path, such as'address.street'. Themessageof the object replaces the message of the validator. false-
The form is invalid, but no field shows the error. It’s in the
errorsof the form.
The browser runs the form validators together with the validators of the fields.
Errors from the Service
A service can report validation errors of its own, for example for checks that need data from a database. Throw an EndpointValidationException, with a ValidationErrorData for each error. Its second argument is the path of the field that shows the error:
Source code
SignUpService.java
The form shows the error in the field, like the errors of the Bean Validation constraints: