0

How to add to list with ListModelList and DataBinder

asked 2008-07-21 13:40:53 +0800

dastultz gravatar image dastultz
797 8

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

delete flag offensive retag edit

9 Replies

Sort by ยป oldest newest

answered 2008-07-21 18:25:45 +0800

robertpic71 gravatar image robertpic71
1275 1

Here some examples, loadAll() should work:

Examples

/Robert

link publish delete flag offensive edit

answered 2008-07-22 01:50:04 +0800

henrichen gravatar image henrichen
3869 2
ZK Team

Looks something wrong with your ListitemRenderer. It would be better if you can post a simplified testing code that would replicate your issue.

/henri

link publish delete flag offensive edit

answered 2008-07-22 15:30:53 +0800

dastultz gravatar image dastultz
797 8

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

link publish delete flag offensive edit

answered 2008-07-23 01:53:33 +0800

dastultz gravatar image dastultz
797 8

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

link publish delete flag offensive edit

answered 2008-07-23 07:11:42 +0800

henrichen gravatar image henrichen
3869 2
ZK Team

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

link publish delete flag offensive edit

answered 2008-07-23 14:47:47 +0800

dastultz gravatar image dastultz
797 8

"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?

link publish delete flag offensive edit

answered 2008-07-24 02:22:02 +0800

henrichen gravatar image henrichen
3869 2
ZK Team

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.

link publish delete flag offensive edit

answered 2008-07-24 16:12:01 +0800

dastultz gravatar image dastultz
797 8

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

link publish delete flag offensive edit

answered 2008-07-25 12:34:50 +0800

dastultz gravatar image dastultz
797 8

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?

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-07-21 13:40:53 +0800

Seen: 1,040 times

Last updated: Jul 25 '08

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