Vaadin 8 - 在bean更改后,ComboBox值仍然存在

时间:2018-01-31 09:46:15

标签: vaadin vaadin8

修改:我自己找到了解决方案,如果您只是想帮助而不是自己没有类似的问题,则无需阅读所有这些内容;)

首先,我问过this question in the Vaadin Forum,但我也想在这里问一下,如果它不是一个错误,我只是做错了。

我的ComboBox(ComboBox<Bar>)依赖于另一个ComboBox(ComboBox<Foo>)的值,在ComboBox<Foo>值更改时不会按预期更新其值。

首先,两个组合框都是空的 当我为ComboBox<Foo>选择一个选项时,正在手动重建其他ComboBox的选项 如果我然后为ComboBox<Bar>选择了一个选项,那么一切都很好,直到现在 但是,当我现在为ComboBox<Foo>选择另一个选项时,假设为none / null,ComboBox<Bar>的选项正在重建,但其值仍为!(它应为null)

这是我的(简化)代码来解释/重现我的问题。我知道这有点多,但我真的想清楚我的问题是什么,我做了什么:

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
    ...
}

在我的视图中,我有一个Binder,还有一个ComboBox和一个ComboBox。它们的设置如下:

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);
    }
}

我应该打开一个关于此的新问题还是我做错了什么? 任何帮助,将不胜感激。感谢

1 个答案:

答案 0 :(得分:0)

我在这里看不到树木的问题。binder.setBean(binder.getBean());

结束时再次拨打refillBarOptions()来解决问题
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());
}