Form validation made easy.
ValidatorFX is a validation library for JavaFX. It is inspired by ControlsFX but tries to overcome its shortcomings:
- Validations based on arbitrary observable values (not just the value of a control)
- Validations can decorate an arbitrary number of nodes (not just the one control)
- Validations can decorate any node (not just
Control
subtypes) - Validations can be done immediately or on-demand (e.g. when clicking a button)
The central class of ValidatorFX is Validator
which contains a number of Check
s. As a rule a form will have one Validator
object and multiple Check
s.
<dependency>
<groupId>net.synedra</groupId>
<artifactId>validatorfx</artifactId>
<version>0.5.1</version>
</dependency>
Here is a minimal complete example of how ValidatorFX is used:
package net.synedra.validatorfx.demo;
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
import net.synedra.validatorfx.Validator;
public class MinimalExample extends Application {
private Validator validator = new Validator();
@Override
public void start(Stage primaryStage) throws Exception {
TextField userTextField = new TextField();
validator.createCheck()
.dependsOn("username", userTextField.textProperty())
.withMethod(c -> {
String userName = c.get("username");
if (!userName.toLowerCase().equals(userName)) {
c.error("Please use only lowercase letters.");
}
})
.decorates(userTextField)
.immediate();
;
GridPane grid = createGrid();
grid.add(userTextField, 1, 1);
Scene scene = new Scene(grid);
primaryStage.setScene(scene);
primaryStage.show();
}
private GridPane createGrid() {
GridPane grid = new GridPane();
grid.setAlignment(Pos.CENTER);
grid.setPrefSize(400, 200);
return grid;
}
public static void main(String[] args) {
launch();
}
}
Let's look at the central lines which show the fluent API of ValidatorFX:
validator.createCheck()
A new check is created within the validator in this line.
.dependsOn("username", userTextField.textProperty())
A dependency named username
is declared here. You can call dependsOn multiple times if you have more dependencies.
.withMethod(c -> {
String userName = c.get("username");
if (!userName.toLowerCase().equals(userName)) {
c.error("Please use only lowercase letters.");
}
})
This defines the check to be executed. Note how the dependency declared above can easily be accessed here (of course we could also have used userTextField.getText()
instead of c.get("username")
here.
Since ValidatorFX-0.5.0 you may also call withMethod multiple times thus installing multiple checks to be executed. All given check methods will be executed (i.e. no short circuit evaluation).
.decorates(userTextField)
This line tells ValidatorFX to decorate the text field itself. You can call decorates multiple times if you want multiple nodes to be decorated.
.immediate();
The check is declared immediate by this line which means it will be evaluated constantly and userTextField
will be decorated as soon as the check condition changes. Without this line you can validate on submit.
You may also want to use explicit validation (i.e. a call to Validator.validate()
)) at first and then switch to immediate mode or use immediateClear()
which will immediately clear validation / decoration when the user gives input.
Here's a screenshot of the example in action:
To see more features and Details have a look at ValidatorFXDemo.java and the other files in the demo folder.
In many cases a form will contain a submit button that should be disabled if form validation fails. It is important to tell the user about the reason for the button being disabled. This can be done by using a graphic decoration that will display a tooltip if hovered. However this is not very intuitive and the graphic decorations will usually be very small and thus difficult for the user to hover.
Unfortunately disabled nodes cannot show tooltips in JavaFX due to JDK-8090379.
TooltipWrapper
provides a generic workaround to this problem and can be used either independently or in conjunction with convenience methods from Validator
as shown in this example:
TooltipWrapper<Button> signUpWrapper = new TooltipWrapper<>(
signUp,
validator.containsErrorsProperty(),
Bindings.concat("Cannot sign up:\n", validator.createStringBinding())
);
this will result in a tooltip like: