Listbox Template"
Line 84: | Line 84: | ||
There is a variable called [[ZUML Reference/EL Expressions/Implicit Objects/forEachStatus|forEachStatus]] providing the information of the iteration, such as index. It is an instance of <javadoc type="interface">org.zkoss.zk.ui.util.ForEachStatus</javadoc>. However, unlike [[ZUML Reference/ZUML/Attributes/forEach|the forEach attribute]], <javadoc method="getPrevious()" type="interface">org.zkoss.zk.ui.util.ForEachStatus</javadoc> always returns null. Thus, to retrieve the information of the outer template, please refer to the section below. | There is a variable called [[ZUML Reference/EL Expressions/Implicit Objects/forEachStatus|forEachStatus]] providing the information of the iteration, such as index. It is an instance of <javadoc type="interface">org.zkoss.zk.ui.util.ForEachStatus</javadoc>. However, unlike [[ZUML Reference/ZUML/Attributes/forEach|the forEach attribute]], <javadoc method="getPrevious()" type="interface">org.zkoss.zk.ui.util.ForEachStatus</javadoc> always returns null. Thus, to retrieve the information of the outer template, please refer to the section below. | ||
− | ===Data in the outer template | + | ===Data in the outer template=== |
− | To access the data of the outer template from the inner template, you could use the parent listitem's <javadoc method="getValue()">org.zkoss.zul.Listitem</javadoc> where the data is stored by default. | + | To access the data of the outer template from the inner template, you could use the parent listitem's <javadoc method="getValue()">org.zkoss.zul.Listitem</javadoc> where the data is stored by default. Thus, as shown at line 9 of the following example, the straightforward way to retrieve data is to traverse the component tree: |
<source lang="xml" high="9"> | <source lang="xml" high="9"> | ||
Line 107: | Line 107: | ||
</source> | </source> | ||
+ | It is tedious and somehow error prone. Alternatively, you can store the information into a custom attribute. For example, | ||
+ | |||
+ | <source lang="xml" high="4,10"> | ||
+ | <listbox model="${quarters}"> | ||
+ | <template name="model"> | ||
+ | <listitem> | ||
+ | <custom-attributes master="${each}"/> | ||
+ | <listcell> | ||
+ | <listbox model="${months[each]}"> | ||
+ | <template name="model"> | ||
+ | <listitem> | ||
+ | <listcell label="${forEachStatus.index}" /> | ||
+ | <listcell>${master}</listcell> | ||
+ | <listcell>${each}</listcell> | ||
+ | </listitem> | ||
+ | </template> | ||
+ | </listbox> | ||
+ | </listcell> | ||
+ | </listitem> | ||
+ | </template> | ||
+ | </listbox> | ||
+ | </source> | ||
+ | |||
Notice that [[ZUML Reference/EL Expressions/Implicit Objects/forEachStatus|forEachStatus]] (line 8) doesn't have any information of the outer template<ref>It is because the inner template is ''not'' rendered at the same time as the outer's.</ref>. In other words, <code>${forEachStatus.previous}</code> always returns null. | Notice that [[ZUML Reference/EL Expressions/Implicit Objects/forEachStatus|forEachStatus]] (line 8) doesn't have any information of the outer template<ref>It is because the inner template is ''not'' rendered at the same time as the outer's.</ref>. In other words, <code>${forEachStatus.previous}</code> always returns null. | ||
Revision as of 09:54, 13 February 2012
The template used to control the rendering of each item must be named model
and declared right inside the listbox
element. For example,
<listbox model="${$composer.fruits}" apply="foo.FruitProvider">
<listhead>
<listheader label="Name" sort="auto"/>
<listheader label="Weight" sort="auto"/>
</listhead>
<template name="model">
<listitem>
<listcell label="${each[0]}"/>
<listcell label="${each[1]}"/>
</listitem>
</template>
</listbox>
As illustrated above, custom rendering is defined by a template called model
. The template's name is important because users are allowed to associate multiple templates to one component, and listbox
's default renderer looks only for the template called model
.
When the template is rendered, a variable called each
is assigned with the data being rendered. Thus, you could retrieve the information to render with EL expressions, such as ${each[0]}
or ${each.name}
, if it is a bean with a setter called name
.
Notice that, if value="${each}"
is not specified to the listitem
element (Listitem.setValue(Object)) in the template, listbox
will automatically assign the data being rendered to the listitem
's value, such that you could conveniently retrieve back the data when necessary.
The $composer.fruits
expression, in this example, is expected to return a two-dimensional array[1]. It is provided by the foo.FruitProvider
composer such as follows[2].
public class FruitProvider extends org.zkoss.zk.ui.select.SelectorComposer {
public String[][] fruits = new ListModelArray(
new String[][] {
{"Apple", "10kg"},
{"Orange", "20kg"},
{"Mango", "12kg"}
});
public String[][] getFruits() {
return fruits;
}
}
- ↑ Of course, it can be anything you like. Just make sure it matches the EL expressions specified in the template.
- ↑ Here we use SelectorComposer for simplicity. There are several ways to implement a composer, such as wiring a Spring-managed bean. For more information, please refer to the Composer section
Nested Listboxes
The template can be applied recursively. Here is an example of a listbox-in-listbox:
<zk>
<zscript><![CDATA[
ListModel quarters = new ListModelArray(new String[] {"Q1", "Q2", "Q3", "Q4"});
Map months = new HashMap();
months.put("Q1", new ListModelArray(new String[] {"Jan", "Feb", "Mar"}));
months.put("Q2", new ListModelArray(new String[] {"Apr", "May", "Jun"}));
months.put("Q3", new ListModelArray(new String[] {"Jul", "Aug", "Sep"}));
months.put("Q4", new ListModelArray(new String[] {"Oct", "Nov", "Dec"}));
ListModel qs = (quarters);
]]></zscript>
<listbox model="${quarters}">
<template name="model">
<listitem>
<listcell>${each}</listcell>
<listcell>
<listbox model="${months[each]}">
<template name="model">
<listitem label="${each}"/>
</template>
</listbox>
</listcell>
</listitem>
</template>
</listbox>
</zk>
forEachStatus
There is a variable called forEachStatus providing the information of the iteration, such as index. It is an instance of ForEachStatus. However, unlike the forEach attribute, ForEachStatus.getPrevious() always returns null. Thus, to retrieve the information of the outer template, please refer to the section below.
Data in the outer template
To access the data of the outer template from the inner template, you could use the parent listitem's Listitem.getValue() where the data is stored by default. Thus, as shown at line 9 of the following example, the straightforward way to retrieve data is to traverse the component tree:
<listbox model="${quarters}">
<template name="model">
<listitem>
<listcell>
<listbox model="${months[each]}">
<template name="model">
<listitem>
<listcell label="${forEachStatus.index}" />
<listcell>${self.parent.parent.parent.parent.parent.value}</listcell>
<listcell>${each}</listcell>
</listitem>
</template>
</listbox>
</listcell>
</listitem>
</template>
</listbox>
It is tedious and somehow error prone. Alternatively, you can store the information into a custom attribute. For example,
<listbox model="${quarters}">
<template name="model">
<listitem>
<custom-attributes master="${each}"/>
<listcell>
<listbox model="${months[each]}">
<template name="model">
<listitem>
<listcell label="${forEachStatus.index}" />
<listcell>${master}</listcell>
<listcell>${each}</listcell>
</listitem>
</template>
</listbox>
</listcell>
</listitem>
</template>
</listbox>
Notice that forEachStatus (line 8) doesn't have any information of the outer template[1]. In other words, ${forEachStatus.previous}
always returns null.
- ↑ It is because the inner template is not rendered at the same time as the outer's.
Template for GroupsModel
When used with GroupsModel, listboxes will use the template called model:grouping for rendering the grouping object. If it is not defined, it will look for the template called model instead (i.e., the same template is used for rendering the grouping and non-grouping objects).
<listbox mode="${fooGroupsModel}">
<template name="model:group">
<listgroup open="${groupingInfo.open}" label="${each}"/>
</template>
<template name="model">
<listitem>....</listitem>
</template>
<template name="model:groupfoot">
<listgroupfoot>....</listgroupfoot>
</template>
<listbox>
- Note the groupingInfo is used to get the information of the grouping data. Please refer to GroupingInfo
Version History
Version | Date | Content |
---|---|---|
6.0.0 | July 2011 | The template feature was introduced. |
6.0.0 | January 2012 | The GroupingInfo statement was introduced. |