Get Multiselcted items from listbox and annotation
Because your listbox didn't contain anything.
And I'm not sure that Annotated Databinding support multiple selection in listbox.
If your requirement need to do a lot of detail control of Listbox, then using Model + renderer would be safety.
Sometimes it's better to choose the folksy approach.
Thanks for the reply.
>>Because your listbox didn't contain anything.
I have it, both model and renderer are set in the controller.
public void onCreate$applicantWindow() {
try {
lbCategory.setModel(new ListModelList(ApiManager.getMasterGroupDao().readAllMasterGroup()));
lbCategory.setItemRenderer(new SimpleListboxRenderer());
applicant = (MasterApplicant) params.get("applicant");
binder = new AnnotateDataBinder(this);
binder.bindBean("applicant", applicant);
binder.loadAll();
} catch (DAOException ex) {
log.error("onCreate$applicantWindow : "+ex.getMessage());
}
}
To make it work I have taken away the selectedItems="@{applicant.applicantGroup}" from the list box and set the bean value manually (using getSelecteItems()). My question remains how do I get the values using annotation?
regards
Devinder
Ok, now I see your problem.
Instead of ListModelList, maybe you should try this one:
org.zkoss.zkplus.databind.BindingListModelList
Thanks for the reply.
That doesn't work either.
regards
Devinder
Are you sure "applicant" is a instance from ApiManager.getMasterGroupDao().readAllMasterGroup()?
If the instances are different then there's nothing Binder can do.
Thanks for the reply.
No. "applicant" is an instance of "MasterApplicant"
applicant = (MasterApplicant) params.get("applicant");
In MasterApplicant (my model) I have a class variable :
private transient Set<MasterApplicantGroup> applicantGroup;
to which I am referring in zul file as :
<listbox id="lbCategory" width="350px" multiple="true" checkmark="true" rows="4" selectedItems="@{applicant.applicantGroup}"/>
Is there something that I am missing?
regards
Devinder
Finally I have checked the Javadoc, and now I sorry say: "you can't make it in this approach."
because there's no "setSelectedItems(Set selected)" method in listbox!
So now the way to do your job is control it all by your self. In this complex situation I think we should forget Annotated Databinding.
This technology doesn't feet this situation.
public void onCreate$applicantWindow() {
try {
ListModelList groupModel = new ListModelList(ApiManager.getMasterGroupDao().readAllMasterGroup());
lbCategory.setModel(groupModel );
lbCategory.setItemRenderer(new SimpleListboxRenderer());
applicant = (MasterApplicant) params.get("applicant");
Listitem item;
for(MasterApplicantGroup group : applicant.getApplicantGroup()){
item = lbCategory.getItemAtIndex(groupModel.indexOf(group))
lbCategory.addItemToSelection(item);
}
} catch (DAOException ex) {
log.error("onCreate$applicantWindow : "+ex.getMessage());
}
}
Multiple databinding with annotations is only available with an own converter.
The user dasultz has written one.
<listbox id="lbCategory" width="350px" multiple="true" checkmark="true" rows="4" selectedItems="@{applicant.applicantGroup, converter=daslutz.magiccode}"/>
Check this thread.
Post if you have any troubles - i do not need multiple selection until now... so i have not testet the code. But user dasultz seems to be a poweruser, so i think the code shoudl work.
Or use the non-databinding-way as descriped by Iantsai.
/Robert
Thanks guys for the reply.
Iantsai, there is a setSelectedItems method in listbox which accepts set (since 3.6.0, a new addition I guess)
public void setSelectedItems(java.util.Set listItems)
which is why my model variable is a set.
private transient Set<MasterApplicantGroup> applicantGroup;
I was thinking a mere selectedItems="@{applicant.applicantGroup} should work. I will also to look into the Dasulz's approach of converter, as suggested by Robert.
I am already using manual approach as you too suggested, but would definitely like to see the annotation working.
regards
Devinder
Solution provided by robertpic71 won't work because the listbox doesn't update the selectedItems wen items are selected.
And the converter fails sometimes wen listbox has listhead's or other different child components.
Also,
public void setSelectedItems(java.util.Set listItems)
Yes, because you can change the Component implementation providing the "use" property and access the component by interface in your composer class. This is the correct way, by decoupling interface and implementation.
And I can't access method setSelectedItems with the interface, and this is clearly an interface method.
I have post it to SF.net as a feature request, I think we'll get the answer soon.
https://sourceforge.net/tracker/?func=detail&aid=2786357&group_id=152762&atid=785194
Yes, i think the selectedItems are "unfinished". Databinding is working only one-way. My TypeConverter is not called for CorcetoBean.
I extend the original SelectedItemConverter, here is my work-a-round:
Because the selectedItems is only working in one-way, i use selectedItem and update the listbox(entries) inside the converter.
Tested with 3.6.0, 3.6.1 and listbox with livemodel - should also work for listbox w/o livemodel.
It works, but is a little bit tricky:
1. because it's the single selectItem it is called for every selected Listitem (only extra work, no problems)
2. I do not (re)fire an onSelect-Event for every (selected) Listitem (i think there is no need with databinding)
3. When the method selectItems is ready for databinding, i'll post my converter for this also.
/Robert
<listbox model="@{model.users}" multiple="true" rows="5" width="400px"
selectedItem="@{model.ticket.users, converter=webtests.binder.SelectedItemsConverterV3}">
<listhead>
<listheader label="Id"/>
<listheader label="Name"/>
</listhead>
<listitem self="@{each=user}">
<listcell label="@{user.id}" />
<listcell label="@{user.name}" />
</listitem>
</listbox>
And the javacode:
package webtests.binder;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zk.ui.UiException;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zk.ui.event.SelectEvent;
import org.zkoss.zkplus.databind.BindingListModel;
import org.zkoss.zkplus.databind.TypeConverter;
import org.zkoss.zul.ListModel;
import org.zkoss.zul.Listbox;
import org.zkoss.zul.Listitem;
/**
* Convert selected items to bean and vice versa.
*
*/
public class SelectedItemsConverterV3 implements TypeConverter, java.io.Serializable {
private static final long serialVersionUID = 1L;
public Object coerceToUi(Object val, Component comp) { //load
Listbox lbx = (Listbox) comp;
if (val != null & val instanceof Collection) {
Collection<Object> values = (Collection) val;
Iterator<Object> valuesIterator = values.iterator();
Set<Object> items = new HashSet<Object>();
final ListModel xmodel = lbx.getModel();
if (xmodel instanceof BindingListModel) {
final BindingListModel model = (BindingListModel) xmodel;
Listitem item = null;
while (valuesIterator.hasNext()) {
Object value = valuesIterator.next();
int index = model.indexOf(value);
if (index >= 0) {
item = (Listitem) lbx.getItemAtIndex(index);
if (item != null) {
items.add(item);
}
}
}
//We need this to support load-when:onSelect when first load
//the page in (so it is called only once).
if (items.size() > 0 & items.size() != lbx.getSelectedCount()) { // bug 1647817, avoid endless-loop
//bug #2140491
Executions.getCurrent().setAttribute("zkoss.zkplus.databind.ON_SELECT"+lbx.getUuid(), Boolean.TRUE);
Events.postEvent(new SelectEvent("onSelect", lbx, items, item));
}
lbx.setSelectedItems(items);
return TypeConverter.IGNORE;
} else if (xmodel == null) { //no model case, assume Listitem.value to be used with selectedItem
//iterate to find the selected item assume the value (select mold)
while (valuesIterator.hasNext()) {
Object value = valuesIterator.next();
for (Iterator it = lbx.getItems().iterator(); it.hasNext();) {
Listitem item = (Listitem) it.next();
if (value.equals(item.getValue())) {
items.add(item);
}
}
}
lbx.setSelectedItems(items);
return TypeConverter.IGNORE;
} else {
throw new UiException("model of the databind listbox "+lbx+" must be an instanceof of org.zkoss.zkplus.databind.BindingListModel." + xmodel);
}
}
return null;
}
public Object coerceToBean(Object val, Component comp) { //save
final Listbox lbx = (Listbox) comp;
if (Executions.getCurrent().getAttribute("zkoss.zkplus.databind.ON_SELECT"+lbx.getUuid()) != null) {
//bug #2140491
//triggered by coerceToUi(), ignore this
Executions.getCurrent().removeAttribute("zkoss.zkplus.databind.ON_SELECT"+lbx.getUuid());
return TypeConverter.IGNORE;
}
if (val != null) {
final ListModel model = lbx.getModel();
Set<Listitem> listitems = (Set<Listitem>) lbx.getSelectedItems();
Iterator<Listitem> itemsIterator = listitems.iterator();
HashSet<Object> selectedValues = new HashSet<Object>();
while (itemsIterator.hasNext()) {
Listitem listitem = itemsIterator.next();
if (model != null) { // model case
selectedValues.add(model.getElementAt(listitem.getIndex()));
} else { // no model case --> Value
selectedValues.add(listitem.getValue());
}
}
return selectedValues;
}
return null;
}
}Robertpic71 - thanks! it works for me :)
I just changed this line:
> if (val != null & val instanceof Collection) {
to use the and comparison logical operator "&&"
> if (val != null && val instanceof Collection) {
...and added a couple @SuppressWarning("unchecked") lines to have a clean compile log
>> & -> &&
Thanks, I correct for future posts (when set/getSelectedItems is ready for databinding).
>> it works for me :)
Yes for my example also. It is nice no handle n:m relations without any extra javacode.
Just databinding (with this converter) and getters for the servicelayer/DAO's.
/Robert
ZK - Open Source Ajax Java Framework
Hi :
zul snippet :
<listbox id="lbCategory" width="350px" multiple="true" checkmark="true" rows="4" selectedItems="@{applicant.applicantGroup}"/>The model :
private transient Set<MasterApplicantGroup> applicantGroup; public Set<MasterApplicantGroup> getApplicantGroup() { return applicantGroup; } public void setApplicantGroup(Set<MasterApplicantGroup> applicantGroup) { this.applicantGroup = applicantGroup; }In my controller when I do binder.loadAll() it gives me a Nullpointer exception. If applicantGroup is initalized then the null pointer goes away but binder.saveAll() doesn't have the selectedItems in it.
What wrong am I doing?
regards
Devinder