niya
niya

Reputation: 1

JavaFX Button's disableProperty bind to multiple BooleanBindings

I have several TextFields and a submit button. I want my button to be disabled unless all the textfields have been validated. Below is my code for the BooleanBindings:

        BooleanBinding firstNameValidation, middleNameValidation, lastNameValidation, 
        usernameValidation, passwordValidation, retypePasswordValidation, emailValidation, phoneNumberValidation;

        firstNameValidation = Bindings.createBooleanBinding(()->{
            if(employee.setFirstName(txtFirstName.getText()) == 0){
                piFirstName.setProgress(100);
                return true;
            } else {
                piFirstName.setProgress(0);
                return false;
            }
        }, txtFirstName.textProperty());

        middleNameValidation = Bindings.createBooleanBinding(()->{
            if(employee.setMiddleName(txtMiddleName.getText()) == 0){
                piMiddleName.setProgress(100);
                return true;
            } else {
                piMiddleName.setProgress(0);
                return false;
            }
        }, txtMiddleName.textProperty());

..and so on.

This is how I try to bind the disableProperty of the submit button to the BooleanBindings:

btnSetPermissions.disableProperty().bind(firstNameValidation.not().or(middleNameValidation.not()).or(lastNameValidation.not())
                .or(usernameValidation.not()).or(passwordValidation.not()).or(retypePasswordValidation.not())
                .or(emailValidation.not()).or(phoneNumberValidation.not()));

It works, but if the first condition returns false, it doesn't check the rest of the conditions because of the OR-operation.

I can't seem to find a solution. Any help would be much appreciated.

Upvotes: 0

Views: 1746

Answers (2)

James_D
James_D

Reputation: 209684

You're mixing your functionality too much. Separate it out into constituent components:

firstNameValidation = Bindings.createBooleanBinding(() -> {
    String firstName = txtFirstName.getText();
    if (/* firstName is valid */) {
        return true ;
    } else {
        return false ;
    }
}, txtFirstName.textProperty());

employee.firstNameProperty().bind(txtFirstName.textProperty());
// if you want employee.firstName to change only if the name is valid,
// use a listener here instead of the binding above:
txtFirstName.textProperty().addListener((obs, oldText, newText) -> {
    if (firstNameValidation.get()) {
        employee.setFirstName(newText);
    }
});

piFirstName.bind(Bindings.when(firstNameValidation).then(100).otherwise(0));

// similarly for other properties...

// then (this logic is equivalent to yours, but easier to read imho)

btnSetPermissions.disableProperty().bind(
    (firstNameValidation.and(middleNameValidation)
     .and(userNameValidation).and(passwordValidation)
     .and(retypePasswordValidation).and(emailValidation)
     .and(phoneNumberValidation)
    ).not());

Note you can, of course, reduce the code by moving anything repetitive to a method in the usual way:

private BooleanBinding createValidationBinding(
        TextField field, Predicate<String> validationRule, 
        StringProperty boundValue, ProgressIndicator indicator) {

    BooleanBinding validation = Bindings.createBooleanBinding(() -> {
        String value = field.getText();
        return validationRule.test(value);
    }, field.textProperty());

    field.textProperty().addListener((obs, oldText, newText) -> {
        if (binding.get()) {
            boundValue.set(newText);
        }
    });

    indicator.progressProperty().bind(Bindings.when(validation).then(100).otherwise(0));

    return validation ;
}

Then you can do

firstNameValidation = createValidationBinding(txtFirstName, 
    name -> /* boolean indicating if name is valid */,
    employee.firstNameProperty(), piFirstName);

and similarly for the other fields.

Upvotes: 1

Jai
Jai

Reputation: 8363

Personally, this is what I do:

btnSetPermissions.disableProperty.bind(Bindings.createBooleanBinding(() -> {
    if (!validateFirstName() ||
        !validateMiddleName() /* and so on */)
        return true;
    else return false;
}, firstNameProperty(), middleNameProperty() /* and other properties*/ ));

public boolean validateFirstName() {
    // Your validation logic
}

public boolean validateMiddleName() {
    // Your validation logic
}

/* Other validation methods */

There is no need to create so many objects (those BindingExpression objects), and you can easily use conditional operators like || and && which will guarantee skipping of non-essential checks whenever possible.

Upvotes: 1

Related Questions