ValidatorFX

repository·master·Indexed 42 days ago

https://github.com/effad/validatorfx

A JavaFX validation library for validating arbitrary observable values and decorating nodes. It supports immediate and on-demand validation modes, a fluent API for defining rules via Validator and Check objects, and custom decorations. Version 1.0.0.

Tokens
1.2K
Snippets
5
Records
6
Agent score
4%

What's inside ValidatorFX

  1. How ValidatorFX and Checks work together

    master

    ValidatorFX uses a hierarchical model for form validation:

    1. Validator: The central object representing a form. A typical form has one Validator instance.
    2. Check: Individual validation rules created within a Validator. A single Validator can contain multiple Checks.

    Key capabilities include:

    • Validating arbitrary observable values (not just control values).
    • Decorating any number of arbitrary nodes (not just Control subtypes).
    • Supporting both immediate validation (on every change) and on-demand validation (e.g., on button click).
    • Running multiple check methods per Check without short-circuiting.
    // Conceptual usage pattern
    Validator validator = new Validator();
    
    validator.createCheck()
      .dependsOn("key", observableValue)
      .withMethod(c -> { /* validation logic */ })
      .decorates(node)
      .immediate();
  2. Configure validation modes: immediate vs on-demand

    master

    ValidatorFX allows you to control when validation occurs:

    • Immediate Mode: Call .immediate() on a Check. The check is evaluated constantly, and decorations are applied/removed as soon as the condition changes.
    • On-Demand Mode: Omit the .immediate() call. Validation is typically triggered manually, for example, by calling Validator.validate() (e.g., when a user clicks a submit button).
    • Immediate Clear: Use immediateClear() to immediately remove validation decorations when the user provides input.
  3. Install ValidatorFX via Maven

    master

    Add the following dependency to your pom.xml to use ValidatorFX in your JavaFX project.

    <dependency>
       <groupId>net.synedra</groupId>
       <artifactId>validatorfx</artifactId>
       <version>1.0.0</version>
    </dependency>
  4. Show tooltips on disabled buttons using TooltipWrapper

    master

    In JavaFX, disabled nodes cannot display tooltips. To inform users why a button is disabled (e.g., due to form errors), use TooltipWrapper. It wraps a node and shows a tooltip based on a boolean property and a string binding.

    TooltipWrapper<Button> signUpWrapper = new TooltipWrapper<>(
        signUp,
        validator.containsErrorsProperty(), 
        Bindings.concat("Cannot sign up:\n", validator.createStringBinding())
    );
  5. Create a validation check with the fluent API

    master

    Use the fluent API of the Validator class to define validation rules. You can chain methods to declare dependencies, define the validation logic, specify which nodes to decorate, and set the validation mode.

    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();
  6. Provide custom decorations

    master

    You can override default decorations in two ways:

    1. Per-Check basis: Use .decoratingWith(function) on a specific Check instance.
    2. Global basis: Set a new default factory using DefaultDecoration.setFactory(factory) to modify how all decorations (including standard graphic decorations) are created.
    // Per-check custom decoration
    validator.createCheck()
        ... 
        .decoratingWith(this::sumDecorator);
    
    private Decoration sumDecorator(ValidationMessage m) {
        return new Decoration() {
            @Override
            public void remove(Node target) {
                ((Label) target).setText("OK");
            }
            @Override
            public void add(Node target) {
                ((Label) target).setText("ERR - " + m.getText());
            }
        };
    }
    
    // Global default decoration factory
    DefaultDecoration.setFactory(this::createGraphicDecoration);