Binding with Collection and Selection"

From Documentation
m (correct highlight (via JWB))
 
(3 intermediate revisions by 2 users not shown)
Line 1: Line 1:
 
{{Template:Smalltalk_Author|
 
{{Template:Smalltalk_Author|
 
|author=Hawk Chen, Engineer, Potix Corporation
 
|author=Hawk Chen, Engineer, Potix Corporation
|date=October?, 2012
+
|date=October 18, 2012
 
|version=6.5.0
 
|version=6.5.0
 
}}
 
}}
Line 11: Line 11:
 
= Property Binding in Collection Type =
 
= Property Binding in Collection Type =
  
Assume that we have following ViewModel which has a collection type property, <tt>itemList</tt>.
+
Assume that we have the following ViewModel which has a collection type property, <code>itemList</code>.
  
 
'''The ViewModel for tree example'''
 
'''The ViewModel for tree example'''
Line 23: Line 23:
  
  
For a ViewModel's <tt> Collection</tt> type property, we usually bind it with those components that support '''model''' attribute like ''Listbox'', ''Grid'', or ''Tree''. ZK will automatically wrap Java Collection type object as ZK's <javadoc>org.zkoss.zul.ListModel</javadoc> object. You should not bind multiple attributes to a shared collection object (e.g. a static List) as a model because it might arise concurrent access problem.
+
For a ViewModel's <code> Collection</code> type property, we usually bind it with those components that support '''model''' attribute like ''Listbox'', ''Grid'', or ''Tree''. ZK will automatically wrap Java Collection type object as ZK's <javadoc>org.zkoss.zul.ListModel</javadoc> object. You should not bind multiple attributes to a shared collection object (e.g. a static List) as a model because it might arise concurrent access problem.
 
<!--  related issue: http://tracker.zkoss.org/browse/ZK-1334 -->
 
<!--  related issue: http://tracker.zkoss.org/browse/ZK-1334 -->
  
When we bind a collection type property as a data source, we have to specify how to render each object of the model with <tt> <template></tt> ([[ZK Developer's Reference/MVC/View/Template]]). and ZK will create components according to the fragment specified in <tt> <template></tt> iteratively. There are 2 implicit variables we can use in <tt> <template></tt>.
+
When we bind a collection type property as a data source, we have to specify how to render each object of the model with <code> <template></code> ([[ZK Developer's Reference/MVC/View/Template]]). and ZK will create components according to the fragment specified in <code> <template></code> iteratively. There are 2 implicit variables we can use in <code> <template></code>.
  
'''each''', iteration object variable which references to each object of the model. We can use it to access an object's properties with dot notation, e.g. <tt>each.name</tt>.
+
'''each''', iteration object variable which references to each object of the model. We can use it to access an object's properties with dot notation, e.g. <code>each.name</code>.
  
'''forEachStatus''', iteration status variable. it's used to get iteration index by <tt>forEachStatus.index</tt>.
+
'''forEachStatus''', iteration status variable. it's used to get iteration index by <code>forEachStatus.index</code>.
  
 
'''Binding a collection with a Tree'''
 
'''Binding a collection with a Tree'''
<source lang="xml" high="8,9,10,11,12,13,14,15">
+
<source lang="xml" highlight="8,9,10,11,12,13,14,15">
 
<window apply="org.zkoss.bind.BindComposer"
 
<window apply="org.zkoss.bind.BindComposer"
 
viewModel="@id('vm') @init('org.zkoss.reference.developer.mvvm.collection.TreeVM')">
 
viewModel="@id('vm') @init('org.zkoss.reference.developer.mvvm.collection.TreeVM')">
Line 53: Line 53:
 
</window>
 
</window>
 
</source>
 
</source>
* When using template element, we don't need to put <tt><treechildren></tt> inside a <tt><tree></tt>.
+
* When using template element, we don't need to put <code><treechildren></code> inside a <code><tree></code>.
  
 
== Collection Property in Children Binding ==
 
== Collection Property in Children Binding ==
Line 60: Line 60:
  
 
'''Children binding with checkbox'''
 
'''Children binding with checkbox'''
<source lang="xml" high="3">
+
<source lang="xml" highlight="3">
 
<window apply="org.zkoss.bind.BindComposer"
 
<window apply="org.zkoss.bind.BindComposer"
 
viewModel="@id('vm') @init('org.zkoss.reference.developer.mvvm.collection.ItemsVM')">
 
viewModel="@id('vm') @init('org.zkoss.reference.developer.mvvm.collection.ItemsVM')">
Line 78: Line 78:
  
 
'''An example of dynamic menu bar'''
 
'''An example of dynamic menu bar'''
<source lang="xml" high="1,2,4,7">
+
<source lang="xml" highlight="1,2,4,7">
 
   
 
   
 
<menubar id="mbar" children="@bind(vm.menuList) @template(empty each.children?'menuitem':'menu')">
 
<menubar id="mbar" children="@bind(vm.menuList) @template(empty each.children?'menuitem':'menu')">
Line 95: Line 95:
 
'''Dynamic menu bar screenshot'''
 
'''Dynamic menu bar screenshot'''
  
[[File:Mvvm-dynamic-menu.png‎]]
+
[[File:Mvvm-dynamic-menu.png | center‎]]
  
 
= Selection in Collection =
 
= Selection in Collection =
Line 106: Line 106:
  
 
'''Properties for selection'''
 
'''Properties for selection'''
<source lang="java" high="5,6">
+
<source lang="java" highlight="5,6">
  
 
public class SingleSelectionVM{
 
public class SingleSelectionVM{
Line 124: Line 124:
 
=== Binding to Selected Index ===
 
=== Binding to Selected Index ===
  
To save or restore a component's selected index, we should bind '''selectedIndex''' attribute to a ViewModel's property with <tt>@bind</tt>. If we change the property's value for selection state in ViewModel, the component's selection state will also change.
+
To save or restore a component's selected index, we should bind '''selectedIndex''' attribute to a ViewModel's property with <code>@bind</code>. If we change the property's value for selection state in ViewModel, the component's selection state will also change.
  
 
'''Listbox selectedIndex example'''
 
'''Listbox selectedIndex example'''
<source lang="xml" high="4">
+
<source lang="xml" highlight="4">
 
<window apply="org.zkoss.bind.BindComposer"  
 
<window apply="org.zkoss.bind.BindComposer"  
 
viewModel="@id('vm') @init('org.zkoss.reference.developer.mvvm.collection.SingleSelectionVM')">
 
viewModel="@id('vm') @init('org.zkoss.reference.developer.mvvm.collection.SingleSelectionVM')">
Line 149: Line 149:
 
=== Binding to Selected Item ===
 
=== Binding to Selected Item ===
  
To save or restore selected item we should bind '''selectedItem''' to a property whose type equals the object of the Model. In our example, we should bind "selectedItem" to an <tt>Item</tt> object.  
+
To save or restore selected item we should bind '''selectedItem''' to a property whose type equals the object of the Model. In our example, we should bind "selectedItem" to an <code>Item</code> object.  
  
 
'''Listbox selectedItem example'''
 
'''Listbox selectedItem example'''
<source lang="xml" high="4">
+
<source lang="xml" highlight="4">
 
<window apply="org.zkoss.bind.BindComposer"  
 
<window apply="org.zkoss.bind.BindComposer"  
 
viewModel="@id('vm') @init('org.zkoss.reference.developer.mvvm.collection.SingleSelectionVM')">
 
viewModel="@id('vm') @init('org.zkoss.reference.developer.mvvm.collection.SingleSelectionVM')">
Line 173: Line 173:
 
== Multiple Selections ==
 
== Multiple Selections ==
  
Some components support multiple selections, but it needs to be enabled before using it. The way to enable multiple selections depends on property's type you bind with "model" attribute. If property type is a Java Collection type like <tt>List, Set, or Map </tt>, we should specify <tt>multiple="true"</tt> on the component to enable multiple selections. If property type is <javadoc>org.zkoss.zul.ext.Selectable</javadoc> (All classes that implement ListModel implement Selectable), we should call <tt>setMultiple(true)</tt> to enable it.
+
Some components support multiple selections, but it needs to be enabled before using it. The way to enable multiple selections depends on property's type you bind with "model" attribute. If property type is a Java Collection type like <code>List, Set, or Map </code>, we should specify <code>multiple="true"</code> on the component to enable multiple selections. If property type is <javadoc>org.zkoss.zul.ext.Selectable</javadoc> (All classes that implement ListModel implement Selectable), we should call <code>setMultiple(true)</code> to enable it.
  
To keep multiple selections state, we should bind '''selectedItems''' to a property whose type is <tt>Set</tt>.
+
To keep multiple selections state, we should bind '''selectedItems''' to a property whose type is <code>Set</code>.
  
 
'''Selected Set'''
 
'''Selected Set'''
<source lang="java" high="5">
+
<source lang="java" highlight="5">
  
 
public class MultipleSelectionsVM{
 
public class MultipleSelectionsVM{
Line 192: Line 192:
  
 
'''Listbox with multiple selections'''
 
'''Listbox with multiple selections'''
<source lang="xml" high="3,4">
+
<source lang="xml" highlight="3,4">
 
<window apply="org.zkoss.bind.BindComposer"  
 
<window apply="org.zkoss.bind.BindComposer"  
 
viewModel="@id('vm') @init('org.zkoss.reference.developer.mvvm.collection.MultipleSelectionsVM')">
 
viewModel="@id('vm') @init('org.zkoss.reference.developer.mvvm.collection.MultipleSelectionsVM')">
Line 210: Line 210:
 
</window>
 
</window>
 
</source>
 
</source>
* Line 3: Because <tt>vm.itemList</tt> is Java list object, we can enable multiple selection by set "multiple" to "true".
+
* Line 3: Because <code>vm.itemList</code> is Java list object, we can enable multiple selection by set "multiple" to "true".
  
  

Latest revision as of 04:20, 20 January 2022

DocumentationSmall Talks2012OctoberBinding with Collection and Selection
Binding with Collection and Selection

Author
Hawk Chen, Engineer, Potix Corporation
Date
October 18, 2012
Version
6.5.0

Opening

When you want to display a collection type object (e.g. List, Set, Map) in a ViewModel, you can bind it to a component's "model" attribute or use children binding. In addition to displaying, some components also keeps the user's selection state like selected index and item of a collection type object, e.g. Listbox and Tree. This article will present the usage of binding collection and selection in MVVM approach. For more details, please refer to ZK Developer's Reference/MVVM/Data Binding/Collection and Selection

Property Binding in Collection Type

Assume that we have the following ViewModel which has a collection type property, itemList.

The ViewModel for tree example

public class TreeVM {

	TreeModel<TreeNode<String>> itemList;
	//omit getter and setter for brevity
}


For a ViewModel's Collection type property, we usually bind it with those components that support model attribute like Listbox, Grid, or Tree. ZK will automatically wrap Java Collection type object as ZK's ListModel object. You should not bind multiple attributes to a shared collection object (e.g. a static List) as a model because it might arise concurrent access problem.

When we bind a collection type property as a data source, we have to specify how to render each object of the model with <template> (ZK Developer's Reference/MVC/View/Template). and ZK will create components according to the fragment specified in <template> iteratively. There are 2 implicit variables we can use in <template>.

each, iteration object variable which references to each object of the model. We can use it to access an object's properties with dot notation, e.g. each.name.

forEachStatus, iteration status variable. it's used to get iteration index by forEachStatus.index.

Binding a collection with a Tree

<window apply="org.zkoss.bind.BindComposer"
	viewModel="@id('vm') @init('org.zkoss.reference.developer.mvvm.collection.TreeVM')">
	<tree model="@bind(vm.itemTree)" width="400px" >
		<treecols>
			<treecol label="name" />
			<treecol label="index" />
		</treecols>
		<template name="model" >
			<treeitem>
				<treerow>
					<treecell label="@bind(each.data)" />
					<treecell label="@bind(forEachStatus.index)" />
				</treerow>
			</treeitem>
		</template>
	</tree>
...
</window>
  • When using template element, we don't need to put <treechildren> inside a <tree>.

Collection Property in Children Binding

For those components that do not support "model" attribute, we still can bind them to a collection type property with children binding ( For basic concept, please refer to ZK Developer's Reference/MVVM/Data Binding/Children Binding).

Children binding with checkbox

<window apply="org.zkoss.bind.BindComposer"
	viewModel="@id('vm') @init('org.zkoss.reference.developer.mvvm.collection.ItemsVM')">
	<vlayout id="vlayout" children="@load(vm.itemList)">
		<template name="children">
			<checkbox label="@load(each.name)" />
		</template>
	</vlayout>
</window>

Combine with Dynamic Template

We can combine children binding with dynamic template in order to render different child components upon different conditions.

Here is an example to create a menu bar dynamically. If a menu item has no sub-menu, it creates Menuitem otherwise it creates Menu.


An example of dynamic menu bar

 
	<menubar id="mbar" children="@bind(vm.menuList) @template(empty each.children?'menuitem':'menu')">
		<template name="menu" var="menu">
			<menu label="@bind(menu.name)">
				<menupopup children="@bind(menu.children) @template(empty menu.children?'menuitem':'menu')"/>
			</menu>
		</template>
		<template name="menuitem" var="item">
			<menuitem label="@bind(item.name)" onClick="@command('menuClicked',node=item)" />
		</template>
	</menubar>

Dynamic menu bar screenshot

center‎

Selection in Collection

Listbox and Tree store user selection state including single or multiple selection. Single selection is enabled by default. The way to enable multiple selection depends on object's type you bind with "model" attribute. ZK allows us to bind selection state with ViewModel's property.

Single Selection

For single selection state, ZK provides 2 kind of state. One is selected index and another is selected item of a model. We can create 2 properties in ViewModel for them respectively.

Properties for selection

public class SingleSelectionVM{

	private ItemService itemService = new ItemService();
	private List<Item> itemList = itemService.getAllItems();
	private int pickedIndex;
	private Item pickedItem;

	//omit getter and setter for brevity
}
  • Line 5: pickedIndex is an integer for selected index.
  • Line 6: pickedItem's type should equal to the object's type in collection.


Binding to Selected Index

To save or restore a component's selected index, we should bind selectedIndex attribute to a ViewModel's property with @bind. If we change the property's value for selection state in ViewModel, the component's selection state will also change.

Listbox selectedIndex example

<window apply="org.zkoss.bind.BindComposer" 
viewModel="@id('vm') @init('org.zkoss.reference.developer.mvvm.collection.SingleSelectionVM')">
	<listbox  width="400px" model="@bind(vm.itemList)" 
	selectedIndex="@bind(vm.pickedIndex)">
		<listhead>
			<listheader label="index"/>
			<listheader label="name"/>
		</listhead>
		<template name="model" var="item" status="s">
			<listitem>
				<listcell label="@bind(s.index)"/>
				<listcell label="@bind(item.name)"/>
			</listitem>
		</template>
	</listbox>	
</window>


Binding to Selected Item

To save or restore selected item we should bind selectedItem to a property whose type equals the object of the Model. In our example, we should bind "selectedItem" to an Item object.

Listbox selectedItem example

<window apply="org.zkoss.bind.BindComposer" 
viewModel="@id('vm') @init('org.zkoss.reference.developer.mvvm.collection.SingleSelectionVM')">
	<listbox  width="400px" model="@bind(vm.itemList)" 
    selectedItem="@bind(vm.pickedItem)" >
		<listhead>
			<listheader label="index"/>
			<listheader label="name"/>
		</listhead>
		<template name="model" var="item" status="s">
			<listitem>
				<listcell label="@bind(s.index)"/>
				<listcell label="@bind(item.name)"/>
			</listitem>
		</template>
	</listbox>


Multiple Selections

Some components support multiple selections, but it needs to be enabled before using it. The way to enable multiple selections depends on property's type you bind with "model" attribute. If property type is a Java Collection type like List, Set, or Map , we should specify multiple="true" on the component to enable multiple selections. If property type is Selectable (All classes that implement ListModel implement Selectable), we should call setMultiple(true) to enable it.

To keep multiple selections state, we should bind selectedItems to a property whose type is Set.

Selected Set

public class MultipleSelectionsVM{

	private ItemService itemService = new ItemService();
	private List<Item> itemList = itemService.getAllItems();
	private Set pickedItemSet;

	//omit getter and setter for brevity
}


Listbox with multiple selections

<window apply="org.zkoss.bind.BindComposer" 
viewModel="@id('vm') @init('org.zkoss.reference.developer.mvvm.collection.MultipleSelectionsVM')">
	<listbox  width="400px" model="@bind(vm.itemList)" checkmark="true" multiple="true"
	selectedItems="@bind(vm.pickedItemSet)" >
		<listhead>
			<listheader label="index"/>
			<listheader label="name"/>
		</listhead>
		<template name="model" var="item" status="s">
			<listitem>
				<listcell label="@bind(s.index)"/>
				<listcell label="@bind(item.name)"/>
			</listitem>
		</template>
	</listbox>
</window>
  • Line 3: Because vm.itemList is Java list object, we can enable multiple selection by set "multiple" to "true".


Summary

Displaying and keeping selections state of a collection type object is a common requirement in a web application. ZK helps you accomplish this task easily by writing data binding expression and eliminate boilerplate codes.



Comments



Copyright © Potix Corporation. This article is licensed under GNU Free Documentation License.