From Documentation

Jump to: navigation, search



Contents


Act on component, such like conditional evaluation, iteration, load on demand.

Attribute Name
Description
if Conditional evaluation of an component
forEach, each Iterative evaluate component against a collection
use, apply Write event handling code in pure java file. apply support MVC pattern better.
forward Let centralized controller handle events.


Overview

ZK attributes are used to control the associated element, other than initializing the data member.

The if Attribute

The evaluation of an element could be conditional. By specifying the if attribute, developers could control whether to evaluate the associated element.

 if="${an-EL-expr}"

It specified the condition to evaluate the associated element. In other words, the associated element and all its child elements are ignored, if the condition is evaluated to false.

In the following example, the window component is created only if a is 1.

<window if="${a==1}">
     ...
</window>


Note

There are other control attributes unless, switch, case, choose, when function like if. Please refer to Developer's Reference for more information.
Besides logical comparison, value of if also accepts string. But only string "true" will be accepted as true. Therefore, <button if="abc"/> won't be rendered, but <button if="true"/> will.

The forEach, each Attribute

The evaluation of an element could be iterative. By specifying a collection of objects to the forEach Attribute, developers could control how many times of the associated element shall be evaluated.

In the following example, the list item is created three times. Each of them has the label called "Good", "Better" and "Best", respectively.

 <listbox>
   <listitem label="${each}" forEach="Good, Better, Best"/>
 </listbox>

Therefore, above example is expanded to:

 <listbox>
   <listitem label="Good"/>
   <listitem label="Better"/>
   <listitem label="Best"/>
 </listbox>

Note that

  1. the order of label="${each}" and forEach="Good, Better, Best" inside <listitem/> doesn't matter, because they are both inside the scope of listitem.
  2. Since forEach is declared in <listitem.../>, listitem is rendered three times for "Good, Better, Best" has three elements.
  3. And inside each <listitem/>, ${each} is assigned "Good", "Better", "Best" in sequence.

The each Variable

During the evaluation, a variable called each is created and assigned with the item from the specified collection being iterated by forEach. In the above example, each is assigned with "Good" in the first iteration, then "Better" and finally "Best".

The forEach Attribute

 forEach="${an-EL-expr}"
 forEach="${an-EL-expr},a-value"

The value assigned to forEach is usually a collection of objects, such that the associated element will be evaluated repeatedly against each object in the collection. It's scope is the same as the component it is declared inside. In the above example, the forEach can only be seen inside listitem's scope. And only each inside the listitem's scope will be assigned with the evaluating object in the collection.

The following is another example. You can assign a collection of object in zscript, and assign it to forEach with EL.

<window>
	<zscript><![CDATA[	
		grades = new String[] {"Good", "Better", "Best"};
	]]>
	</zscript>
	<listbox>
		<listitem label="${each}" forEach="${grades}" />
	</listbox>
</window>

The use, apply Attribute

As demoed in section Design pattern: MVC. You can use MVC pattern with ZK easily. It is suggested to use apply instead of use.

The use Attribute

 use="a-class-name"
 use="${EL_returns_a_class_or_a_class_name}"

Every ZK UI component has its mapping java class. use specifies a class to create a component instead of the default one. In the following example, MyWindow is used instead of the default class, Window.

 <window use="MyWindow"/>

If you want to customize your UI component, use is the suggested way.

<window use="MyWindow"/>

And MyWindow.java

import org.zkoss.zul.Window;

public class MyWindow extends Window {
	public void onCreate(){
		this.setTitle("my window");
	}
}

You can customized your own class by extending from original class. In above example, MyWindow is extended from Window. You can write event handling code in extended class. Therefore you can customize your UI component in onCreate().

The apply Attribute

 apply="a-class-name"
 apply="class1, class2,..."
 apply="${EL_returns_a_class_or_a_collection_of_classes}"
 apply="${EL_returns_an_instance_or_a_collection_of_Composer_instances}"

This attribute is mainly for MVC pattern. You can implement the controller, and then apply it.

It specifies a class, a collection of classes that are used to initialize the component. The class must implement the Composer interface. And then, you can do the initialization in the doAfterCompose method, since it is called after the component and all its children are instantiated. Developer can call addEventListener inside doAfterCompose.

For easier implementing, it has implemented auto-wire feature, which enable you use java code to access UI component with more intuitive syntax. As example in section Design pattern: MVC showed, you can forward event to controller, let controller handle it.

For even easier implementing, forward can be omitted. In this smalltalk, ZK MVC Made Easy demo ways to use apply to implement MVC pattern. It's highly recommended to read this smalltalk.

In the following example, when button is clicked, its label will change from "test" to "event handled". Beware of naming pattern of button. It's btn_1 both in zul file and java file. By giving the same name, it's auto-wired. Isn't it so intuitive?

<window apply="MyController">
	<button id="btn_1" label="test"/>
</window>

And MyController.java

import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.util.GenericForwardComposer;
import org.zkoss.zul.Button;

//Must extend from GenericForwardComposer to omit forward.
public class MyController extends GenericForwardComposer {
	private Button btn_1;

    //onClick event from btn_1 component
    public void onClick$btn_1(Event event) { 
    	btn_1.setLabel("event handled");
    }
}

The difference between use and apply

You can write event handling code in java file through attribute use or apply. What's the difference between use and apply? It's a design pattern MVC issue. use will entangle View with Control, since you write the event handling codes in class that extends from UI component. Therefore, for MVC approach, apply is suggested. More than that, you can assign a java Object of composer to apply, but use can't. There are more article about MVC in ZK. Please goto ZK's Small_Talks and search "MVC". A Forum Thread that discuss the difference between use and apply thoroughly.

The forward Attribute

 forward="oringal_event=target_event_expr"
 forward="target_event_expr"
 forward="oringal_event=" (since 5.0.0)

where target_event_expr is an event expressions which will be described later.

The second format assumes the original event is onClick. In other words, the following are the same. They both rename the onClick event to onOK and forward to the space owner

<button forward="onOK"/>
<button forward="onClick=onOK"/>

The third format assumes the name of the forward event is the same as the original one. For example, the following is the same.

<button forward="onClick="/>
<button forward="onClick=onClick"/>

Event Expression

An event expression is used to identify an event that is targeting a particular component. It can be one of the following formats:

 event-name
 target-id.event-name
 id1/id2/id3.event-name
 ${el-expr}.event-name

It is used to forward an event, that is targeting a particular component, to another component and to another event name. It is called the forward condition.

For example, you can forward the onClick event targeting a button to the window as follows:

 <window id="w" use="MyWindow">
     ...
     <button label="Submit" forward="onClick=w.onOK"/>
 </window>

Then, you can handle the submission in the MyWindow class as follows:

 public class MyWindow extends Window {
     public void onOK() {
         //handle the submission
     }
 }

The original event is optional. If it is omitted, onClick is assumed. Similarly, the target ID is also optional. If omitted, the space owner is assumed. Thus, the above codes can be simplified to the following:

 <window id="w" use="MyWindow">
     ...
     <button lable="Submit" forward="onOK"/>
 </window>

If you want to forward several events, you can specify these conditions in the forward attribute by separating them with the comma (,):

 <textbox forward="onChanging=onUpdating, onChange=some.onUpdate"/>

The Forward Event

Event that is forwarded, will be wrapped and transformed to Forward Event (ForwardEvent), not the type of original event anymore. If you want to get event data, you can retrieve the original event by use of the getOrigin method. An event may be forwarded multiple times, therefore you may have to use getOrigin in a while loop, till you get the origin event.

Pass Information to the Forward Event

forward="orginalEvent=targetId1/targetId2.targetEvent(eventData)"

You can pass the application-specific information to the forward event by surrounding it with parenthesis and appending it to the forward condition as shown above. The information can be retrieved by use of the getData method of the ForwardEvent class.

 <button forward="onCancel(abort)"/>

The getData method will return "abort".

Of course, you can specify EL expressions to pass whatever type of data you want.

In the following example, a Date object will be the data in the event. You can set breakpoint in Eclipse to observe the content of evt

 <window id="win" title="ZK app 6" apply="MyComposer">
 	<zscript><![CDATA[  
		Date now = new Date();
 	]]> 	
 	</zscript>
 	<button label="Say Hello" forward="onSayHello(${now})" />
 </window>

And MyComposer.java

import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.util.GenericComposer;
import org.zkoss.zul.Label;

public class MyComposer extends GenericComposer {
	public void onSayHello(Event evt) {
		evt.getTarget().appendChild(new Label("Hello"));
	}
}

Note forward="onSayHello(${now})" is not zscript, and it accept EL. On the other hand, value of onXXX is zscript.

EL Expressions in the Forward Condition

forward="originalEvent=${el-targetPath}.targetEvent(${el-eventData})"

You can use EL expressions when specifying the target ID/path and the application-specific information (a.k.a., the event data).

 <button forward='${mainWnd}.onOK(${c:getProperty("status")})'/>

However, you can not use EL expressions to specify the event names.

If you prefer pure java solution

addForward is the api you need. Please refer to the java doc.

See Also

From ZK Forum:

Difference between use="" and apply=""

passing params to the controller class

Accessing EJB from Window controller

"Extend Window" --- problem

Quiz

1.We can append parameter in url by appending ?variableName=variableValue behind usual url. For example, the following url: http://10.1.3.103:8080/zksTest/helloworld.zul?good=yes And ${param.good=="yes"} will be evaluated as true.

Use if to write a zul that will layout 1 to 3 buttons depends on user input parameter.


2.Generate 100 buttons by each and forEach

3.Implement MyWindow.java, such that

<window title="Hello" border="normal" width="200px" height="200px"/>

can be write to

<window use="MyWindow"/>


4. Implement MyController.java, such that each the button is clicked, a new button is appended to the window.

<window apply="MyController">
	<button id="btn_1" label="test"/>
</window>

5. Complete MyWindow.java, when button Submit or Cancel is clicked, a different text will append to the window.

 <window use="MyWindow">     
     <button label="Submit" forward="onOK(yes)"/>
     <button label="Cancel" forward="onOK(no)"/>
 </window>

And MyWindow.java

public class MyWindow extends Window{
	public void onOK(Event evt){
		String input = (String)evt.getData();
		if(input.equals("yes")){
		}
	}
}




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