Create Data Binding Programmatically"
Line 12: | Line 12: | ||
+ | Assume we have a form to fill in personal information. | ||
+ | |||
+ | <source lang="xml"> | ||
+ | <window apply="org.zkoss.reference.developer.mvvm.advance.DynamicBindingComposer" width="600px"> | ||
+ | <grid > | ||
+ | <rows> | ||
+ | <row> | ||
+ | First Name: | ||
+ | <textbox id="fn"/> | ||
+ | </row> | ||
+ | <row> | ||
+ | Last Name: | ||
+ | <textbox id="ln"/> | ||
+ | </row> | ||
+ | <row> | ||
+ | Age: | ||
+ | <intbox/> | ||
+ | </row> | ||
+ | <row spans="2"> | ||
+ | <div> | ||
+ | <button label="Submit" /> | ||
+ | <button label="Reset" /> | ||
+ | </div> | ||
+ | </row> | ||
+ | <row spans="2"> | ||
+ | <div> | ||
+ | Preview: I am <label id="fnLabel" /> <label id="lnLabel" />, <label id="ageLabel"/> years old. | ||
+ | </div> | ||
+ | </row> | ||
+ | </rows> | ||
+ | </grid> | ||
+ | ... | ||
+ | </window> | ||
+ | </source> | ||
+ | |||
+ | We hope that user input can be automatically saved to a bean. | ||
'''3 basic steps example''' | '''3 basic steps example''' | ||
− | <source lang="java" high='3, | + | <source lang="java" high='3,11,13,15,17, 21'> |
public class DynamicBindingComposer extends SelectorComposer { | public class DynamicBindingComposer extends SelectorComposer { | ||
private Binder binder = new DefaultBinder(); | private Binder binder = new DefaultBinder(); | ||
... | ... | ||
+ | private Person person; | ||
@Override | @Override | ||
Line 24: | Line 61: | ||
super.doAfterCompose(comp); | super.doAfterCompose(comp); | ||
− | binder.init( | + | binder.init(comp,this, null); |
− | + | grid.setAttribute("person", person); | |
− | binder.addPropertySaveBindings(firstNameBox, "value", "person.firstName", null, null, null, null, null,null,null); | + | binder.addPropertySaveBindings(firstNameBox, "value", "person.firstName" |
− | binder.addPropertyLoadBindings(firstNameBox, "value", "person.firstName", null, null, null, null, null); | + | , null, null, null, null, null,null,null); |
+ | binder.addPropertyLoadBindings(firstNameBox, "value", "person.firstName" | ||
+ | , null, null, null, null, null); | ||
// add more data bindings... | // add more data bindings... | ||
Line 36: | Line 75: | ||
</source> | </source> | ||
* Line 3: Create a <javadoc>org.zkoss.bind.DefaultBinder</javadoc> to use as its Javadoc suggests. | * Line 3: Create a <javadoc>org.zkoss.bind.DefaultBinder</javadoc> to use as its Javadoc suggests. | ||
− | * Line | + | * Line 11: We should initialize <tt>DefaultBinder</tt> before using it. The first parameter is root component. The second parameter is ViewModel object. In this example, the composer plays the role as a ViewModel. |
− | * Line | + | * Line 13: Set the data bean as an attribute of the ''Grid'', this can make the bean be accessible for EL expression by its key: <tt>person</tt>. |
− | + | * Line 15,17: Add save- or load-binding according to our requirement. | |
− | * Line 15: | + | * Line 21: Load data for all load-binding inside the component specified at first parameter which is a ''Grid''. |
− | * Line | ||
Line 56: | Line 94: | ||
binder.addPropertyLoadBindings(firstNameBox, "value", "vm.person.firstName", null, null, null, null, null); | binder.addPropertyLoadBindings(firstNameBox, "value", "vm.person.firstName", null, null, null, null, null); | ||
binder.addPropertySaveBindings(firstNameBox,"value","vm.person.firstName", null, null, null, null, null,null,null); | binder.addPropertySaveBindings(firstNameBox,"value","vm.person.firstName", null, null, null, null, null,null,null); | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
</source> | </source> | ||
Revision as of 04:29, 2 January 2013
Overview
Under MVC approach, getting component's attribute value by calling getter methods causes lots of routine code in a composer. But under MVVM approach, all attributes' values are saved to ViewModel's properties automatically without calling any methods because of data binding. Through using a binder to add data binding for components, we also can enjoy this benefit in a composer. This section introduces basic usages of a binder.
Binder API Usage
There are 3 basic steps to create data bindings:
- Initialize the binder
- Store data objects as attributes
- To make data be available for EL expressions
- Add data bindings
Assume we have a form to fill in personal information.
<window apply="org.zkoss.reference.developer.mvvm.advance.DynamicBindingComposer" width="600px">
<grid >
<rows>
<row>
First Name:
<textbox id="fn"/>
</row>
<row>
Last Name:
<textbox id="ln"/>
</row>
<row>
Age:
<intbox/>
</row>
<row spans="2">
<div>
<button label="Submit" />
<button label="Reset" />
</div>
</row>
<row spans="2">
<div>
Preview: I am <label id="fnLabel" /> <label id="lnLabel" />, <label id="ageLabel"/> years old.
</div>
</row>
</rows>
</grid>
...
</window>
We hope that user input can be automatically saved to a bean.
3 basic steps example
public class DynamicBindingComposer extends SelectorComposer {
private Binder binder = new DefaultBinder();
...
private Person person;
@Override
public void doAfterCompose(Component comp) throws Exception {
super.doAfterCompose(comp);
binder.init(comp,this, null);
grid.setAttribute("person", person);
binder.addPropertySaveBindings(firstNameBox, "value", "person.firstName"
, null, null, null, null, null,null,null);
binder.addPropertyLoadBindings(firstNameBox, "value", "person.firstName"
, null, null, null, null, null);
// add more data bindings...
binder.loadComponent(grid, false); //load beans' data to initialize components
}
- Line 3: Create a DefaultBinder to use as its Javadoc suggests.
- Line 11: We should initialize DefaultBinder before using it. The first parameter is root component. The second parameter is ViewModel object. In this example, the composer plays the role as a ViewModel.
- Line 13: Set the data bean as an attribute of the Grid, this can make the bean be accessible for EL expression by its key: person.
- Line 15,17: Add save- or load-binding according to our requirement.
- Line 21: Load data for all load-binding inside the component specified at first parameter which is a Grid.
Here we give some common examples, for more details please refer to Javadoc: Binder.
Property binding in a ZUL
<textbox value="@bind(vm.person.firstName)"/>
Programmatic property binding
binder.addPropertyLoadBindings(firstNameBox, "value", "vm.person.firstName", null, null, null, null, null);
binder.addPropertySaveBindings(firstNameBox,"value","vm.person.firstName", null, null, null, null, null,null,null);
Add Data Binding for Collections
Assume that we hope end users can edit an item directly in a Listbox. Hence we could put a Textbox in each Listcell and make the Textbox bind to a object of Listbox's model. This data binding cannot be made by writing annotation in a zul because those Textboxs are dynamically created.
<window apply="org.zkoss.reference.developer.mvvm.advance.DynamicCollectionBindingComposer"
width="600px">
...
<div apply="org.zkoss.bind.BindComposer"
viewModel="@id('vm') @init('org.zkoss.reference.developer.mvvm.advance.DynamicCollectionBindingVM')">
<listbox model="@load(vm.personList)" selectedItem="@bind(vm.selectedPerson)" rows="10">
</listbox>
...
</div>
...
</window>
Use ItemRenderer
class MyListboxRenderer implements ListitemRenderer{
public void render(Listitem listitem, Object data, int index)
throws Exception {
//TODO explain why
listitem.setAttribute("each", data);
//first name
Listcell fnCell = new Listcell();
listitem.appendChild(fnCell);
Textbox fnBox = new Textbox();
fnBox.setInplace(true);
fnCell.appendChild(fnBox);
binder.addPropertyLoadBindings(fnBox, "value", "each.firstName", null, null, null, null, null);
binder.addPropertySaveBindings(fnBox, "value", "each.firstName", null, null, null, null, null, null, null);
//last name
...
//age
...
//delete button
...
}
}