ZK Attributes
This documentation is for an older version of ZK. For the latest one, please click here.
Act on component, such like conditional evaluation, iteration, load on demand.
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 likeif
. 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
- the order of
label="${each}"
andforEach="Good, Better, Best"
inside<listitem/>
doesn't matter, because they are both inside the scope oflistitem
. - Since
forEach
is declared in<listitem.../>
,listitem
is rendered three times for "Good, Better, Best" has three elements. - 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
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 button
s 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")){
}
}
}