Unbind and rebind a field AFTER Binder.readBean()

Hi,

Is it possible to removeBinding() and then bind() it again AFTER the bean has been read.

My use case I have an entity which has two sets of fields that need to be entered based on some boolean field.
E.g. If optionA is true then fields a, b & c are to be entered and validated.
If optionA is false then fields a, b, d and e are to be entered and validated.
Note that optionA is also a bound field.
I have a checkbox in the form for the optionA boolean value, and then bind and unbind the relevant fields triggered by a value change listener on the checkbox.
However this doesn’t seem to work because one can’t bind a field after the bean has been read. I can’t re-read the bean because that will overwrite the optionA field.

Does anyone know a better way to do this kind of dual form entry?

Thanks.

What I do is this…

first I use the WorkaroundBinder (from https://github.com/vaadin/framework/issues/11280)


import java.lang.reflect.Field;
import java.util.Set;

import com.vaadin.flow.data.binder.Binder;
import com.vaadin.flow.data.binder.PropertySet;

/**
 * This is a DIRTY workaround since at this version of Vaadin the Binder is not removing the Binding of a field so keeps validation on wrong
 * fields.. 
 * This 'hack' seems to do the job (until we move to a newer version perhaps?)
 * 
 *
 * @param <T>
 */
public class WorkaroundBinder<T> extends Binder<T> {

	private static final long serialVersionUID = 1L;

	public WorkaroundBinder() {
		super();
	}

	public WorkaroundBinder(Class<T> beanType, boolean scanNestedDefinitions) {
		super(beanType, scanNestedDefinitions);
	}

	public WorkaroundBinder(Class<T> beanType) {
		super(beanType);
	}

	public WorkaroundBinder(PropertySet<T> propertySet) {
		super(propertySet);
	}
	
	@SuppressWarnings("unchecked")
	@Override
	protected void removeBindingInternal(Binding<T, ?> binding) {		
		super.removeBindingInternal(binding);
		try {
// if binder does not validate changedBindings is not cleared (possibly a mistake in doWriteIfValid method) as such
// a reference to binding might be left hanging in that set.
// This hack removes hanging reference from changedBindings .
			Field field = Binder.class.getDeclaredField("changedBindings");
			field.setAccessible(true);
			Set<Binding<T, ?>> changedBindings = (Set<Binding<T, ?>>) field.get(this);
			changedBindings.remove(binding);
		} catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e) {
			e.printStackTrace();
		}
	}
	
}

Then I bind only the common ones at the object…
binder.forField(optionAField).asRequired…blah blah blah…

and I add a valueChangeListener on optionAField
if true
binder.removeBinding(optionBField);

binder.forField(optionCField)…blah blah blah…

if false
binder.removeBinding(optionCField);
binder.forField(optionBField);…

Note: I’m not using binder.readBean(x) but binder.setBean(x) (don’t know if it makes any difference) but it seems to work like this on Vaadin 13.x.x.

Hello Nick,

Thanks for the pointers. I didn’t realize there was an issue with binding and unbinding fields. I will try the workaorund and see how it goes.

But I suspect my issue might be different because I am using readBean(). If I bind a field after the readBean() then the field value of the underlying bean is not copied into the binder field buffer. Maybe what I need to do is bind ALL fields before the readBean() and then immediately unbind those that are not necessary. And use your WorkaroundBinder as well.