Iterative Evaluation"

From Documentation
m (remove empty version history (via JWB))
 
(22 intermediate revisions by 5 users not shown)
Line 21: Line 21:
 
</source>
 
</source>
  
When the ZK Loader iterates through items of the given collection, it will update two implicit objects: [[ZUML Reference/EL Expressions/Implicit Objects/each|each]] and [[ZUML Reference/EL Expressions/Implicit Objects/forEachStatus|forEachStatus]]. The <tt>each</tt> object represents the item being iterated, while forEachStatus is an instance of <javadoc type="interface">org.zkoss.zk.ui.util.ForEachStatus</javadoc>, from which you could retrieve the index and the previous forEach, if any (nested iterations).
+
When ZK Loader iterates through items of the given collection, it will update two implicit objects: [[ZUML Reference/EL Expressions/Implicit Objects/each|each]] and [[ZUML Reference/EL Expressions/Implicit Objects/forEachStatus|forEachStatus]]. The <code>each</code> object represents the item being iterated, while forEachStatus is an instance of <javadoc type="interface">org.zkoss.zk.ui.util.ForEachStatus</javadoc>, from which you could retrieve the index and the previous forEach, if any (nested iterations).
  
If you have a variable holding a collection of objects, you can specify it directly in the forEach attribute. For example, assume you have a variable called <tt>grades</tt> as follows.
+
If you have a variable holding a collection of objects, you can specify it directly in the forEach attribute. For example, assume that you have a variable called <code>grades</code> as follows.
  
 
<source lang="java">
 
<source lang="java">
Line 34: Line 34:
 
<listbox>
 
<listbox>
 
     <listitem label="${each}" forEach="${grades}"/>     
 
     <listitem label="${each}" forEach="${grades}"/>     
</listitem>
+
</listbox>
 
</source>
 
</source>
  
 
The iteration depends on the type of the value of the forEach attribute:
 
The iteration depends on the type of the value of the forEach attribute:
  
* If it is java.util.Collection iterates each element of the collection.
+
* If it is java.util.Collection, it iterates each element of the collection.
 
* if it is java.util.Map, it iterates each Map.Entry of the map.
 
* if it is java.util.Map, it iterates each Map.Entry of the map.
 
* If it is java.util.Iterator, it iterates each element from the iterator.
 
* If it is java.util.Iterator, it iterates each element from the iterator.
* If jit is ava.util.Enumeration, it iterates each element from the enumeration.
+
* If it is java.util.Enumeration, it iterates each element from the enumeration.
* If it is Object[], int[], short[], byte[], char[], float[] or double[] is specified, it iterates each element from the array.
+
* If it is Object[], int[], short[], byte[], char[], float[] or double[], it iterates each element from the array.
 
* If it is null, nothing is generated (it is ignored).
 
* If it is null, nothing is generated (it is ignored).
 
* If neither of the above types is specified, the associated element will be evaluated once as if a collection with a single item is specified.
 
* If neither of the above types is specified, the associated element will be evaluated once as if a collection with a single item is specified.
Line 49: Line 49:
 
==The each Object==
 
==The each Object==
  
During the evaluation, an object called each is created and assigned with the item from the specified collection. In the above example, each is assigned with "Best" in the first iteration, then "Better" and finally "Good".
+
During the evaluation, an object called <code>each</code> is created and assigned with the item from the specified collection. In the above example, <code>each</code> is assigned with "Best" in the first iteration, then "Better" and finally "Good".
  
Notice that the <tt>each</tt> object is accessible both in EL expression and in zscript. ZK will preserve the value of the <tt>each</tt> object if it is defined before, and restore it after the evaluation of the associated element.
+
Notice that the <code>each</code> object is accessible both in an EL expression and in zscript. ZK will preserve the value of the <code>each</code> object if it is defined before, and restore it after the evaluation of the associated element.
  
 
== The forEachStatus Object ==
 
== The forEachStatus Object ==
  
The forEachStatus object is an instance of <javadoc type="interface">org.zkoss.ui.util.ForEachStatus</javadoc>. It holds the information about the current iteration. It is mainly used to get the item of the enclosing element that is also assigned with the forEach attribute.
+
The <code>forEachStatus</code> object is an instance of <javadoc type="interface">org.zkoss.ui.util.ForEachStatus</javadoc>. It holds the information about the current iteration. It is mainly used to get the item of the enclosing element that is also assigned with the forEach attribute.
  
 
In the following example, we use nested iterative elements to generate two listboxes.
 
In the following example, we use nested iterative elements to generate two listboxes.
Line 72: Line 72:
 
         </listhead>
 
         </listhead>
 
         <listitem label="${forEachStatus.previous.each}: ${each}"
 
         <listitem label="${forEachStatus.previous.each}: ${each}"
         forEach="${grades[forEachStatus.previous.index]}"/>
+
         forEach="${grades[forEachStatus.index]}"/>
 
     </listbox>
 
     </listbox>
 
</hlayout>
 
</hlayout>
 
</source>
 
</source>
  
Notice that the <tt>each</tt> and <tt>forEachStatus</tt> objects are accessible both in EL expression and in zscript.
+
Notice that the <code>each</code> and <code>forEachStatus</code> objects can be accessible both in an EL expression and in zscript.
  
==Apply forEach to Muliple Elements==
+
==Apply forEach to Multiple Elements==
  
 
If you have to iterate a collection of items for multiple XML elements, you could group them with the [[ZUML Reference/ZUML/Elements/zk|zk]] element as shown below.
 
If you have to iterate a collection of items for multiple XML elements, you could group them with the [[ZUML Reference/ZUML/Elements/zk|zk]] element as shown below.
Line 91: Line 91:
 
</source>
 
</source>
  
The <code>zk</code> element is a special element used to ''group'' a set of XML element nested. ZK Loader won't create a component for it. Rather, ZK Loader interprets the forEach, if and unless attribute it might have.
+
The <code>zk</code> element is a special element used to ''group'' a set of XML elements nested. ZK Loader will not create a component for it. Rather, it interprets the <code>forEach</code>, if and unless attribute it might have.
  
 
= Access each and forEachStatus in Java=
 
= Access each and forEachStatus in Java=
  
You could access the <tt>each</tt> and <tt>forEachStatus</tt> object directly in zscript such as:
+
You could access the <code>each</code> and <code>forEachStatus</code> object directly in zscript such as:
 
<source lang="xml">
 
<source lang="xml">
 
<window>
 
<window>
Line 118: Line 118:
 
</source>
 
</source>
  
If the component is a root, you could retrieve them from page's attributes (<javadoc method="getAttribute(java.lang.String)" type="interface">org.zkoss.zk.ui.Page</javadoc>).
+
If the component is a root, you could retrieve them from the page's attributes (<javadoc method="getAttribute(java.lang.String)" type="interface">org.zkoss.zk.ui.Page</javadoc>).
  
 
== Access each and forEachStatus in Event Listeners==
 
== Access each and forEachStatus in Event Listeners==
  
However, you cannot access the values of <tt>each</tt> and <tt>forEachStatus</tt> in an event listener because their values are reset after the XML element which <tt>forEach</tt> is associated has been evaluated.
+
However, you cannot access the values of <code>each</code> and <code>forEachStatus</code> in an event listener because their values are reset after the XML element which <code>forEach</code> is associated has been evaluated.
  
For example, the following code won't work:
+
For example, the following code will not work:
  
 
<source lang="xml">
 
<source lang="xml">
Line 131: Line 131:
 
</source>
 
</source>
  
When the onClick event is received, the <tt>each</tt> object no longer exists.
+
When the onClick event is received, the <code>each</code> object no longer exists.
  
 
There is a simple solution: store the value in the component's attribute, so you can retrieve it when the event listener is called. For example,
 
There is a simple solution: store the value in the component's attribute, so you can retrieve it when the event listener is called. For example,
Line 144: Line 144:
 
=Iterate a Subset of a Collection=
 
=Iterate a Subset of a Collection=
  
If you'd like to iterate a subset of a collection, you could specify the [[ZUML Reference/ZUML/Attributes/forEachBegin|forEachBegin]] and/or [[ZUML Reference/ZUML/Attributes/forEachEnd|forEachEnd]] attributes.
+
If you would like to iterate a subset of a collection, you could specify the [[ZUML Reference/ZUML/Attributes/forEachBegin|forEachBegin]] and/or [[ZUML Reference/ZUML/Attributes/forEachEnd|forEachEnd]] attributes.
  
 
<source lang="xml">
 
<source lang="xml">
Line 156: Line 156:
 
</source>
 
</source>
  
=Version History=
+
 
{{LastUpdated}}
 
{| border='1px' | width="100%"
 
! Version !! Date !! Content
 
|-
 
| &nbsp;
 
| &nbsp;
 
| &nbsp;
 
|}
 
  
 
{{ZKDevelopersReferencePageFooter}}
 
{{ZKDevelopersReferencePageFooter}}

Latest revision as of 05:54, 6 February 2024


Iterative Evaluation


forEach

By default, ZK instantiates a component for each XML element. If you would like to generate a collection of components, you could specify the forEach attribute. For example,

<listbox>
    <listitem label="${each}" forEach="Apple, Orange, Strawberry"/>
</listbox>

is equivalent to

<listbox>
    <listitem label="Apple"/>
    <listitem label="Orange"/>
    <listitem label="Strawberry"/>
</listbox>

When ZK Loader iterates through items of the given collection, it will update two implicit objects: each and forEachStatus. The each object represents the item being iterated, while forEachStatus is an instance of ForEachStatus, from which you could retrieve the index and the previous forEach, if any (nested iterations).

If you have a variable holding a collection of objects, you can specify it directly in the forEach attribute. For example, assume that you have a variable called grades as follows.

grades = new String[] {"Best", "Better", "Good"};

Then, you can iterate them by the use of the forEach attribute as follows. Notice that you have to use EL expression to specify the collection.

<listbox>
    <listitem label="${each}" forEach="${grades}"/>    
</listbox>

The iteration depends on the type of the value of the forEach attribute:

  • If it is java.util.Collection, it iterates each element of the collection.
  • if it is java.util.Map, it iterates each Map.Entry of the map.
  • If it is java.util.Iterator, it iterates each element from the iterator.
  • If it is java.util.Enumeration, it iterates each element from the enumeration.
  • If it is Object[], int[], short[], byte[], char[], float[] or double[], it iterates each element from the array.
  • If it is null, nothing is generated (it is ignored).
  • If neither of the above types is specified, the associated element will be evaluated once as if a collection with a single item is specified.

The each Object

During the evaluation, an object called each is created and assigned with the item from the specified collection. In the above example, each is assigned with "Best" in the first iteration, then "Better" and finally "Good".

Notice that the each object is accessible both in an EL expression and in zscript. ZK will preserve the value of the each object if it is defined before, and restore it after the evaluation of the associated element.

The forEachStatus Object

The forEachStatus object is an instance of ForEachStatus. It holds the information about the current iteration. It is mainly used to get the item of the enclosing element that is also assigned with the forEach attribute.

In the following example, we use nested iterative elements to generate two listboxes.

<hlayout>
    <zscript>
    classes = new String[] {"College", "Graduate"};
    grades = new Object[] {
        new String[] {"Best", "Better"}, new String[] {"A++", "A+", "A"}
    };
    </zscript>
    <listbox width="200px" forEach="${classes}">
        <listhead>
            <listheader label="${each}"/>
        </listhead>
        <listitem label="${forEachStatus.previous.each}: ${each}"
         forEach="${grades[forEachStatus.index]}"/>
    </listbox>
</hlayout>

Notice that the each and forEachStatus objects can be accessible both in an EL expression and in zscript.

Apply forEach to Multiple Elements

If you have to iterate a collection of items for multiple XML elements, you could group them with the zk element as shown below.

<zk forEach="${cond}">
    ${each.name}
    <textbox value="${each.value}"/>
    <button label="Submit"/>
</zk>

The zk element is a special element used to group a set of XML elements nested. ZK Loader will not create a component for it. Rather, it interprets the forEach, if and unless attribute it might have.

Access each and forEachStatus in Java

You could access the each and forEachStatus object directly in zscript such as:

<window>
    <button label="${each}" forEach="apple, orange">
        <zscript>
   self.parent.appendChild(new Label("" + each));
        </zscript>
    </button>
</window>

In a composer, you could retrieve them from the attributes, because these objects are actually stored in the parent component's attributes (Component.getAttribute(String)). For example,

public class Foo implements Composer {
    public void doAfterCompose(Component comp) throws Exception {
        Object each = comp.getParent().getAttribute("each"); //retrieve the each object
        ForEachStatus forEachStatus = (ForEachStatus)comp.getParent().getAttribute("forEachStatus");
        //...
    }
}

If the component is a root, you could retrieve them from the page's attributes (Page.getAttribute(String)).

Access each and forEachStatus in Event Listeners

However, you cannot access the values of each and forEachStatus in an event listener because their values are reset after the XML element which forEach is associated has been evaluated.

For example, the following code will not work:

<button label="${each}" forEach="${countries}"
    onClick="alert(each)"/> <!-- incorrect!! -->

When the onClick event is received, the each object no longer exists.

There is a simple solution: store the value in the component's attribute, so you can retrieve it when the event listener is called. For example,

<button label="${each}" forEach="${countries}"
    onClick='alert(self.getAttribute("country"))'>
        <custom-attributes country="${each}"/>
</button>

Iterate a Subset of a Collection

If you would like to iterate a subset of a collection, you could specify the forEachBegin and/or forEachEnd attributes.

<grid>
    <rows>
        <row forEach="${foos}" forEachBegin="${param.begin}" forEachEnd="${param.end}">
            ${each.name} ${each.title}
        </row>
    </rows>
</grid>




Last Update : 2024/02/06

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