修改:我自己找到了解决方案,如果您只是想帮助而不是自己没有类似的问题,则无需阅读所有这些内容;)
首先,我问过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);
}
}
我应该打开一个关于此的新问题还是我做错了什么? 任何帮助,将不胜感激。感谢
答案 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());
}