ValueChangeListener vs binding: Vaadin 8 is different from Vaadin 7

There is a field. The field is bound to a bean property using Binder (FieldGroup in V7). The field also has a valueChangeListener.

Vaadin 7: The bean property is updated through binding before the valueChangeListener is called. It makes sense because the code needs to work with the updated bean property, with the new value.

Vaadin 8: The valueChangeListener is invoked before the bean propertty is updated through binding. The processing in the listener method sees obsolete value in the bean. It does not make sense.

Is there a way to update the bean before the valueChangeListener is called?

Any help is greatly appreciated! Thank you!

The processing code in the valueChangeListener is not validation. It’s what needs to happen once the values are valid. I have a method in the bean that is called from the valueChangeListener method that does things to other fields/properties depending on what field is changed and its new value. It’s essential to be able to write that change event code while working with the bean and its properties. That is why I need new values in the bean when the change processing code is executed. This used to work fine in Vaadin 7 but now my code sees old values in the onChange method.

In case I am not clear on what I need to do I will give you an example.

Let’s say there is a combo box that shows US states. Below that there is a list of products. Each state has its own set of available products. When a selected state changes (to a valid value) I want to update the content of the product list hence the value change listener. I want to do it inside of the bean itself that has properties that hold the selected state and product. The bean is an object from the business domain. The dependency between states and products need to be expressed in the business domain language, i.e. the bean properties. Therefore the value change listener calls a bean’s “onChange” method. At teh time of the call, the state selection property of the bean needs to have new value so it can populate the product list based on state selection.

I’d recommend using BeanValidationBinder and defining your validation on the bean properties themselves.

If you do this, you won’t need to do any processing in a valueChangeListener, it is done automatically, according to your validation constraints.

With Vaadin 8 Binder, the Bean itself is not updated if the fields are invalid. You also need to call binder.writeBeanIfValid(bean), in order for the Bean to reflect the changes in the fields (if they are valid, bean will retain old value otherwise).

If you could share your code, I could explain better and maybe show you exactly how to achieve what you want.

Greetings.

If anyone wants to see the code the snippet below should give you an idea what I am doing. The pageComponent is a Java bean that has properties with setters and getters. The definitions collection containts a list of fields I want to see on the page that are mapped by name ot the properties of the pageComponent bean. The value change listener is called. Then the values in the bean are updated automatically. Everything works just in the wrong order.

I’d love to see the order reveresed for two reasons:

  1. In my opinion it makes more sense if bean is updated with (valid) values from the fields before the listener is invoked (as it was in Vaadin 7)
  2. For the sake of people doing the Vaadin 7 to 8 conversion. A little bit of compatibility could help a lot…
Binder binder = new Binder( pageComponent.getClass() );
for( FieldDefinition fieldDefinition : definitions ) {
HasValue field = createField( fieldDefinition );
binder.forField( field ).bind( fieldDefinition.getName() );
field.addValueChangeListener( valueChangeEvent -> { ... } );
}
binder.setBean( pageComponent );

Hello there Sergei.

Sorry for the late answer. Its been a very busy week and I hadn’t logged in :slight_smile:

Can you try doing this instead of using a valueChangeListener?

binder.addStatusChangeListener(e -> { //Called when any bound field is changed. if(!e.hasValidationErrors() && e.getBinder().hasChanges()){ //Check changes are valid and confirm there were actually changes. //Your processing code goes here. } }); Greetings.

Please see a new thread with exact description of the problem:

https://vaadin.com/forum#!/thread/16619118

wow

Hi Sergei
I know this topic is a bit old but I just had a very similar problem as you - a ComboBox that relies on the value of another ComboBox - and would like to share my solution with you, for you and any future devs that run into this problem.

You can add a valuechangeListener to the binder itself, from where you can call the function that you called with your ValueChangeListener that you added to your field. This way, the bean is already updated when said funtion runs.

binder.addValueChangeListener(event -> {
    binder.setBean(binder.getBean());
    functionToCallWhenValueChanges();
})

In
my question about it
you can see even a bit more of how I set up the whole thing.