I have a client requirement that I enable certain form fields only when other form fields have certain values.
(Picture a checkbox that controls the enabled status of other form fields.)
What is the best–in the community’s opinion–way to accomplish this?
I could see overriding attachField() and inspecting each field as it goes by to see if it’s one of the ones I’m interested in–but this seems error prone.
I could see abusing the validation contract, since it already deals with focus gained/lost events, but that smells like a hack.
Don’t know about best practices or not, but if the checkbox is immediate, it’s easy to use the current value when it changes to do a setVisible(true|false) on a Field (or a Layout if the area to appear/disappear contains several Fields) and the field will appear/disappear based on the value of the checkbox.
Thanks. I’m somewhat confused, though, about the issue of databinding.
The form in question is bound to a Java bean wrapped by a BeanItem.
At some point the controlling field–the checkbox–will be set to the state of the Property that it is bound to.
Even in this case I need to make sure that the other values are (a) disabled (if need be) and (b) set to proper no-op values when they’re disabled.
(In point of fact it’s not a checkbox, it’s a ComboBox without null selection allowed, and if you pick item #3 then (and only then) should two other ComboBoxes be enabled.)
Well, make sure your checkbox or combobox is in immediate mode so that changes are sent back to the server automatically when they change value. Assuming you also have an appropriate value change listener, you should get called when this takes place, at which time you can set the other fields/layouts to visible or not. Does that make sense?
For example, in the Form’s field factory we do something similar when we create our select box. Note that the value change listener, which then calls our ‘setupFieldsByType’ method that does the visible changes.
if (propertyId.equals("type")) {
NativeSelect select = new NativeSelect(vaadinApp.getMsg("LibFieldForm.type.label"));
select.setNullSelectionAllowed(false);
select.setImmediate(true);
select.addItem(FieldTemplate.TYPE_GENERAL);
select.setItemCaptionMode(NativeSelect.ITEM_CAPTION_MODE_EXPLICIT);
select.setItemCaption(FieldTemplate.TYPE_GENERAL, vaadinApp.getMsg("fieldTemplate.type.general"));
select.addListener( new Property.ValueChangeListener() {
@Override
public void valueChange(Property.ValueChangeEvent event) {
setupFieldsByType((String)event.getProperty().getValue());
}
});
return select;
}
So we can then query the other fields on the form and set them visible or not:
void setupFieldsByType(String type) {
Field minLengthField = getField("minLength");
if ( minLengthField == null ) return; // If we don't have our fields setup yet, ignore
Field maxLengthField = getField("maxLength");
if ( FieldTemplate.TYPE_CHECKBOX.equals(type) ) {
minLengthField.setVisible(false);
maxLengthField.setVisible(false);
} else {
minLengthField.setVisible(true);
maxLengthField.setVisible(true);
}
}
No need to bog down in any details of our code, but I hope you can see the idea…use a value change listener with ‘immediate’ field to detect changes, then you can make any other fields/layout on the form visible or not.