ComboBox value remains after the bean has changed


Edit: Immediately after posting this I saw the solution. This issue is resolved :wink:

A ComboBox (ComboBox) of mine that relies on the value of another ComboBox (ComboBox) does not update its value as expected when the ComboBox value changes.

At first, both comboBoxes are empty. When I select an option for ComboBox the options of the other ComboBox are being manually rebuilt.
If I then select an option for ComboBox it’s getting selected, all is fine until now.
But when I now select another option for ComboBox, let’s say none/null, the Options of ComboBox are being rebuilt,
but its value remains!
(it should be null)

Here is my (simplified) code to eplain/reproduce my problem. I know it’s a bit much but I really want to be clear what my problem is and what I did:

public class FooBar {
    private Foo foo = null;

    public FooBar(){
    }

    // getters and setters
    ...
}

public class Foo {
    private Collection<Bar> bars;
    private Bar selectedBar = null;

    public Foo(Collection<Bar> bars){
        this.bars = bars;
    }

    // getters and setters
    ...
}

public class Bar {
    private String name;

    public Bar(String name){
        this.name = name;
    }

    // getters and setters
    ...
}

In my View, I have a Binder and there is a ComboBox and also a ComboBox. They are being set up like this:

Binder<FooBar> binder = new Binder<>(new FooBar()); 
binder.addValueChangeListener(event -> {
    binder.setBean(binder.getBean()); // forces bound components to get the value again / refresh
    refillBarOptions(); 
})

ComboBox<Foo> cbFoo = new ComboBox<>();
cbFoo.setCaption("foo");

Collection<Foo> allFoos = fooService.findAll(); // the foos do NOT have a selectedBar yet
ListDataProvider<Foo> ldpFoo = new ListDataProvider<Foo>(allFoos);
cbFoo.setDataProvider(ldpFoo);

binder.forField(cbFoo)
    .bind(
        fooBar -> fooBar.getFoo(), //valueprovider
        (fooBar, foo) -> fooBar.setFoo(foo) //setter
    );
// so initially this combobox' value is empty because the FooBar.getFoo() returns null. thats OK!


ComboBox<Bar> cbBar = new ComboBox<>();
cbBar.setCaption("bar");

cbBar.setDataProvider(new ListDataProvider<Bar>(new HashSet<>())); // no items initially because the Foo-ComboBox has no value yet
cbBar.setItemCaptionGenerator(Bar::getName);

binder.forField(cbBar)
    .bind(
        fooBar -> fooBar.getFoo() == null ? null : fooBar.getFoo().getSelectedBar(), //valueprovider
        (fooBar, bar) -> {
            if(fooBar.getFoo() != null){
                fooBar.getFoo().setSelectedBar(bar);
            }
        }
    );
cbBar.setEnabled(false) // disable because no items initially    


/**
 * gets called when binder value has changed. 
 * This way I circumvent the fact that a normal valueChangeListener of a component is fired before the binder-bean is updated
 */
private void refillBarOptions(){
    Foo selectedFoo = binder.getBean().getFoo();
    if(selectedFoo != null){
        cbBar.setDataProvider<>(new ListDataProvider<>(selectedFoo.getBars())); //cbBar is actually not a local variable so it can be accessed here
        cbBar.setEnabled(true);
    } else {
        // there is no foo selected, therefore no bars should be allowed to be selected
        cbBar.setDataProvider(new ListDataProvider<Bar>(new HashSet<>()));
        cbBar.setEnabled(false);
    }
}

Should I open a new Issue about this or am I doing something wrong?
Any help would be appreciated. Thanks

Wow, sometimes I can’t see the wood for the trees… yesterday I spent half of my day trying to solve this issue, but now immediately after posting it it came to me:

I simply have to call

binder.setBean(binder.getBean()) 

again at the end of refillBarOptions(). It works perfectly now.

private void refillBarOptions(){
    Foo selectedFoo = binder.getBean().getFoo();
    if(selectedFoo != null){
        cbBar.setDataProvider<>(new ListDataProvider<>(selectedFoo.getBars())); //cbBar is actually not a local variable so it can be accessed here
        cbBar.setEnabled(true);
    } else {
        // there is no foo selected, therefore no bars should be allowed to be selected
        cbBar.setDataProvider(new ListDataProvider<Bar>(new HashSet<>()));
        cbBar.setEnabled(false);
    }
    binder.setBean(binder.getBean());
}

Sorry for having bothered you :cry: