0

Multi-value binding in Listbox

asked 2008-08-15 22:38:39 +0800

dastultz gravatar image dastultz
797 8

Hello, I have found through searching the forum that Listbox and binding doesn't support multiple values. I need to build something that will do it. It seems I need to implement a TypeConverter (to replace SelectedItemConverter?). This part is easy enough, but I don't know how yo use it. Where does one "register" the TypeConverter to be used? How will the binder know to use my converter? I don't use ZUL, I write richlets, so a Java code example of activating a custom converter would be great, thanks.

delete flag offensive retag edit

6 Replies

Sort by ยป oldest newest

answered 2008-08-16 02:01:21 +0800

dastultz gravatar image dastultz
797 8

After studying the source, I have this:

binder.addBinding(lstKeys, "selectedItem", "thing.prop", (List) null, (List) null, null, "SelectedItemsConverter");

I'm iterating over my List value and calling listbox.addItemToSelection(listitem) but it doesn't change the selection. What is my converter supposed to return? The javadocs say "Convert an value object to UI component attribute type." but I don't know what that means.

Thanks.

link publish delete flag offensive edit

answered 2008-08-16 14:19:39 +0800

dastultz gravatar image dastultz
797 8

After scanning the source code again (SelectedItemConverter) I now understand. My SelectedItemsConverter (note the plural items) returns an ArrayList of Listitems (for coercetoui). I subclassed Listbox and added this method:

public void setSelectedItems(ArrayList items) {
clearSelection();
Iterator iter = items.iterator();
while (iter.hasNext()) {
Listitem item = (Listitem) iter.next();
addItemToSelection(item);
}
}

Now for coercetobean...

link publish delete flag offensive edit

answered 2008-08-16 14:43:01 +0800

dastultz gravatar image dastultz
797 8

When I use a Listbox the coercetobean method is called as expected in my converter. But when I subclass Listbox, say with MyListbox, the coercetobean method is no longer called. What do I need to do? MyListBox looks like this:

public class MyListbox extends Listbox {

public void setSelectedItems(Set items) {
clearSelection();
Iterator iter = items.iterator();
while (iter.hasNext()) {
Listitem item = (Listitem) iter.next();
addItemToSelection(item);
}
}
}

and I am binding like this:

binder.addBinding(mylistbox, "selectedItems", "thing.prop", (List) null, (List) null, null, "MySelectedItemsConverter");

Any ideas?

link publish delete flag offensive edit

answered 2008-08-16 23:09:27 +0800

dastultz gravatar image dastultz
797 8

Hello me, it's me again...

I'll distill this down a bit just in case I made a mistake in my previous posts. I start by subclassing Listbox with MyListbox that does absolutely nothing. I implement MyTypeConverter which simply issues a print statement and returns null for both methods. Then I call it like so:

binder.addBinding(mylistbox, "selectedItems", "thing.prop", (List) null, (List) null, null, "MyTypeConverter");

And it "works" which is to say both coerceToUi and coerceToBean are called. Then in MyListbox I implement setMonkey and getMonkey which simply issue print statements and getMonkey returns null. Then I use it like so:

binder.addBinding(mylistbox, "monkey", "thing.prop", (List) null, (List) null, null, "MyTypeConverter");

Now coerceToUi is called but coerceToBean is not called. How do I fix this? Thanks.

/Daryl

link publish delete flag offensive edit

answered 2008-08-17 13:07:34 +0800

henrichen gravatar image henrichen
3869 2
ZK Team

Try change this

binder.addBinding(mylistbox, "monkey", "thing.prop", (List) null, (List) null, null, "MyTypeConverter");

to

binder.addBinding(mylistbox, "monkey", "thing.prop", (List) null, (List) null, "both", "MyTypeConverter");

the default accessiblity is "load" only. Specify "both" shall solve the issue.

link publish delete flag offensive edit

answered 2008-08-17 15:03:30 +0800

dastultz gravatar image dastultz
797 8

Excellent, Henri, that did the trick. Here's my complete solution.

First the TypeConverter:

public class SelectedItemsConverter implements TypeConverter {

@SuppressWarnings("unchecked")
public Object coerceToBean(Object val, Component comp) {
if (val instanceof Set) {
HashSet<Object> selectedValues = new HashSet<Object>(); // should be a Set to be consistent with Listbox.getSelectedItems
Set set = (Set) val;
Iterator iter = set.iterator();
while (iter.hasNext()) {
Object item = iter.next();
if (item instanceof Listitem) {
Listitem listitem = (Listitem) item;
selectedValues.add(listitem.getValue()); // todo: deal with posibility of model being set on Listbox
} else throw new IllegalStateException("Expected Listitem, found " + item.getClass().getName());
}
return selectedValues;
} else throw new IllegalStateException("Expected Set, found " + val.getClass().getName());
}

@SuppressWarnings("unchecked")
public Object coerceToUi(Object val, Component comp) {
if (val instanceof Collection) {
Collection values = (Collection) val;
if (comp instanceof Listbox) {
HashSet<Listitem> selectedItems = new HashSet<Listitem>(); // have to return a Set since MultiBinding/Listbox.get/setSelectedItems does same
Listbox listbox = (Listbox) comp;
listbox.clearSelection();
Iterator iter = values.iterator();
while (iter.hasNext()) {
Object key = iter.next();
Iterator iter2 = listbox.getChildren().iterator();
while (iter2.hasNext()) {
Listitem listitem = (Listitem) iter2.next();
if (listitem.getValue().equals(key)) { // should work for integers, todo: deal with posibility of model being set on Listbox
selectedItems.add(listitem);
}
}
}
return selectedItems;
} else {
throw new IllegalArgumentException("Expected Listbox, found " + comp.getClass().getName());
}
} else {
throw new IllegalArgumentException("Expected Collection, found " + val.getClass().getName());
}
}
}

And my Listbox subclass:

public class MultiBindingListbox extends Listbox {

@SuppressWarnings("unchecked")
public void setSelectedItems(Set items) {
clearSelection();
if (items == null) return;
Iterator iter = items.iterator();
while (iter.hasNext()) {
Listitem item = (Listitem) iter.next();
addItemToSelection(item);
}
}
}

And an example binding:

binder.addBinding(listbox, "selectedItems", "thing.prop", (List) null, "onSelect", "both", SelectedItemsConverter.class.getName());

I used "onSelect" just for testing. The implementation thus far is not intended for Listbox backed by a ListModel - just the simpler Listitem.getValue() approach.

/Daryl

link publish delete flag offensive edit
Your reply
Please start posting your answer anonymously - your answer will be saved within the current session and published after you log in or create a new account. Please try to give a substantial answer, for discussions, please use comments and please do remember to vote (after you log in)!

[hide preview]

Question tools

Follow

RSS

Stats

Asked: 2008-08-15 22:38:39 +0800

Seen: 859 times

Last updated: Aug 17 '08

Support Options
  • Email Support
  • Training
  • Consulting
  • Outsourcing
Learn More