Reputation: 1
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
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
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