-
FEATURED COMPONENTS
First time here? Check out the FAQ!
Hello, I have a Listbox backed by ListModelList and DataBinder. My ListitemRenderer binds the data as it renders. When I add an object to the model, the new row appears with the proper components (meaning the renderer is called, right?) but the components don't have any values (blank label, no label for a button). Adding a call to binder.loadAll() doesn't seem to help. I know the values in the binding bean are good because I can delete it from the list which depends on a value in the bean.
All I am doing is this to add the new object:
listModelList.add(data);
binder.loadAll(); // doesn't seem to help
I assume my renderer is doing what it needs to, but that could be what's missing.
Any ideas? Thanks.
/Daryl
Here some examples, loadAll() should work:
/Robert
Yes, "simple" is the problem, right? I'm all in Richlet Land so I'll try to post the main bits and hopefully the hole will be visible.
My button listener to add an item looks like this:
listModel.add(data);
binder.loadAll();
My List renderer looks like this:
public void render(Listitem listItem, Object data) throws Exception {
final String beanId = listItem.getId(); // don't require user (me) to make up an id
binder.bindBean(beanId, data);
// loop over "plug in" cell renderers
Iterator<BindingCellRenderer> iter = cellRenderers.iterator();
while (iter.hasNext()) {
BindingCellRenderer renderer = iter.next();
renderer.renderCell(data, listItem, beanId, getBinder());
}
}
My cell renderer looks like this:
public void renderCell(Object data, Listitem listItem, String beanId, DataBinder binder) {
Listcell cell = new Listcell();
listItem.appendChild(cell);
final Component comp = (Component) getComponentTemplate().clone(); // base actual component on template object
cell.appendChild(comp);
String attr = componentBindingAttributes.get(comp.getClass()); // map of common binding attribute
if (attr == null) attr = "value";
binder.addBinding(comp, attr, beanId + "." + getExpression()); // expression is name of property to bind to
}
Hope there is something useful there...
/Daryl
Ok, here it is all in one place. I made some simplifications...
Listbox list = new Listbox();
list.setMultiple(true);
list.setCheckmark(true);
final DataBinder binder = new DataBinder();
list.setItemRenderer(new ListitemRenderer() {
public void render(Listitem listItem, Object data) throws Exception {
String beanId = listItem.getId();
binder.bindBean(beanId, data);
Listcell cell = new Listcell();
listItem.appendChild(cell);
final Component comp = new Label();
cell.appendChild(comp);
binder.addBinding(comp, "value", beanId + ".name");
}
});
final ListModelList listModel = create list model...
list.setModel(listModel);
list.renderAll();
list.setPage(getPage());
binder.loadAll();
final Textbox txt = new Textbox();
txt.setPage(getPage());
Button btnSave = new Button("Save");
btnSave.addEventListener("onClick", new EventListener() {
public void onEvent(Event event) throws Exception {
create bean...
bean.setName(txt.getText());
txt.setText("");
listModel.add(dbt);
binder.loadAll();
}
});
btnSave.setPage(getPage());
dastultz,
Data Binder does not support "dynamically added Binding" yet. That is, when first loadXxx() or saveXxx() method is called, the binding is "fixed". All those bindings added later are not "visible" to the Data Binder. Here in your example, the binding of the Label's value is added later so it is not visible to the Data Binder and not work as your expect. This is really an implementation limitation. A feature regarding this is already fired but we have had no resource to do it yet.
http://sourceforge.net/tracker/index.php?func=detail&aid=1739790&group_id=152762&atid=785194
Don't you consider to use the collection data binding for your case?
/henri
"A feature regarding this is already fired but we have had no resource to do it yet."
I looked at the tracker, not sure my case fits.. I don't know.
"Don't you consider to use the collection data binding for your case?"
I'm pretty new to this, so I don't know what you mean. Do mean BindingListModelList or CollectionItem? I'm happy to try some other approach. It seems like this would be a pretty common pattern, so there must be a solution. Do you have some example?
Have you seen this small talk?
http://www.zkoss.org/smalltalks/databind4/databind4.dsp
The idea is that you create a template for listitem and the Data Binder will use an implicit ListitemRenderer to render each Listitem for you based on the provided template. So you don't generate the Listitem and Listcell yourself one by one; rather you create a template Listitem so Data Binder knows how to produce similar ones for you.
The <a:bind ...> expression you saw in the small talk is the old way to denote an annotation. The new way is @{...} but the concept is the same.
<?init class="org.zkoss.zkplus.databind.AnnotateDataBinderInit" ?> <window> <listbox model="@{persons}" selectedItem="@{selected}" rows="4"> <listitem self="@{each=person}"> <!-- The each=... tells Data Binder that this listitem is a template --> <listcell label="@{person.firstName}"/> <!-- "person" would be the object taken from each model iteration --> <listcell label="@{person.lastName}"/> </listitem> </listbox> </window>
I knew you are using Richlet. However, you can create a component hierarchy by java code and provide proper bindings then the Data Binder will do the job for you.
Thanks Henri, I'll give this a try. The obvious shortcoming of this approach is that you can't vary the rendered component, e.g., if property X = 0 render a label, if property X = 1 render a hyper link...
/Daryl
Ok, I totally can't figure out how to convert your example to Richlet form, but that's ok, I've got something that works. My renderer keeps a reference to the binder. So when I add an item, I instantiate a new binder and then re-render the whole list:
myrenderer.clearBinder(); // instantiate new binder
listModel.add(newDataBean); // does this render anything?
listbox.renderAll();
myrenderer.getBinder().loadAll();
I don't really mind doing this because I'd like to refresh the list from the database anyway so I pick up new items someone else might have made, plus the new one ends up in the right position in the list. My question is one of efficiency. My test case of 10 items or so works quite fast. I don't see the blank row show up as it did before, but I'm wondering if there is any hidden extra work being done. My listModel is a ListModelList, so the Listbox listens for changes and rerenders the new data (wrongly as we've seen), or does it? Anything I should worry about?
Asked: 2008-07-21 13:40:53 +0800
Seen: 1,050 times
Last updated: Jul 25 '08