Getting Started"

From Documentation
m (correct highlight (via JWB))
 
(49 intermediate revisions by 4 users not shown)
Line 1: Line 1:
{{DevelopersGuidePageHeader}}
+
{{ZKDevelopersGuidePageHeader}}
  
This chapter describes how to write your first [[The_zk_user_interface_markup_language | '''ZUML''']](ZK User interface Markup Language) page, and demonstrates some ZK's features in really simple examples. More detail explanation can be find at [[Developer's_Guide#Part_B.__Fundamental_ZK | Part B: Fundamental Concepts]].
+
This chapter describes how to write your first [http://books.zkoss.org/wiki/ZK_ZUML_Reference/The_ZK_User_Interface_Markup_Language '''ZUML''' ](ZK User interface Markup Language) page, and demonstrates some ZK's features in simple examples.  
  
Please goto [http://www.zkoss.org/zkdemo/userguide/ ZK Demo] to see example usage of components. You can also copy and paste following example code to ZK Demo to see the result.
 
 
 
==Hello World!==
 
==Hello World!==
After ZK is installed into your favorite Web server<ref>Refer to the Quick Start Guide.</ref>, writing applications is straightforward. Just create a ZUML file, say hello.zul<ref>The other way to try examples depicted here is to use the live demo to run them.</ref>, as follows under a proper directory.
+
After ZK is installed on your favorite Web server<ref>For more information, please refer to [[ZK Installation Guide]].</ref>, writing applications is straightforward. Just create a ZUML file, say hello.zul<ref>The other way to try examples is to use [http://www.zkoss.org/zksandbox/userguide ZK Sandbox] to run them.</ref>, under one of the Web application's directories just as you would do for an HTML file.
<source lang="xml" >
+
 
  <window title="ZK App 1">
+
<syntax lang="xml" >
 +
  <window title="My First ZK Application" border="normal">
 
  Hello World!
 
  Hello World!
 
  </window>
 
  </window>
</source>
+
</syntax>
  
  
Then, browse to the right URL, say http://localhost/myapp/hello.zul, and you got it.
+
Then, go to the corresponding URL, say http://localhost/myapp/hello.zul, and you'll see your first ZK application running.
  
[[Image:dgGettingStartedHello.zul.JPG]]
+
[[Image:dgGettingStartedHello.zul.png]]
  
In a ZUML page, a XML element describes what component to create. In this example, it is a <tt>window</tt> . The XML attributes are used to assign values to properties of the window component. In this example, it sets the window's <tt>title</tt> attribute to 「ZK App 1」.
+
In a ZUML page, an XML element describes what component to create while the XML attributes are used to assign values to a component's properties. In this example, a <code>window</code> component is created and its <code>title</code> is set to <code>"My First ZK Application"</code> and its <code>border</code> is set to <code>normal</code>.
  
The text enclosed in the XML elements is also interpreted as a special component called <tt>label</tt> . Thus, the above example is equivalent to the following.
+
The text enclosed in the XML elements is also interpreted as a special component called <code>label</code>. Thus, the above example is equivalent to the following.
  
<source lang="xml" >
+
<syntax lang="xml" >
<window title="ZK App 1">
+
<window title="My First ZK Application" border="normal">
 
<label value="Hello World!"/>
 
<label value="Hello World!"/>
 
</window>
 
</window>
</source>
+
</syntax>
 +
 
 +
<blockquote>
 +
----
 +
<references/>
 +
</blockquote>
  
==Click the <tt>button</tt>, and then a <tt>window</tt> pop==
+
==Say Hello in Ajax way==
  
 
Let us put some interactivity into it.
 
Let us put some interactivity into it.
  
<source lang="xml" >
+
<syntax lang="xml" >
<window title="ZK app 2">
+
<button label="Say Hello" onClick='Messagebox.show("Hello World!")'/>
<button label="Say Hello" onClick="alert("Hello World!")"/>
+
</syntax>
 +
 
 +
Then, when you click the button, you'll see the following:
 +
 
 +
[[Image:DgGettingStartedHello2.png]]
 +
 
 +
The <code>onClick</code> attribute is a special attribute used to add an event listener to the component such that it is invoked when an end user clicks the component. The attribute value could be any legal Java code. Notice that it is not JavaScript, and we have to use the double quotes (") to represent a string. Furthermore, to specify a double quote in an XML attribute, we could use single quotes (') to enclose it<ref>If you are not familiar with XML, you might take a look at [[ZK_Developer%27s_Guide/Fundamental_ZK/ZK_User_Interface_Markup_Language/XML |the XML section]].</ref>.
 +
 
 +
Here we invoke <javadoc method="show(java.lang.String)">org.zkoss.zul.Messagebox</javadoc> to show a message box as depicted above.
 +
 
 +
The Java code is interpreted by [http://www.beanshell.org/ BeanShell] at run time. In additions to event handling, we could embed the code in a ZUML page by specifying it in a special element called <code>zscript</code>. For example, we could define a function to simply the code as follows.
 +
 
 +
<syntax lang="xml" >
 +
<window title="My First ZK Application" border="normal">
 +
<button label="Say Hello" onClick='alert("Hello World!")'/>
 +
<zscript>
 +
void alert(String message){ //declare a function
 +
Messagebox.show(message);
 +
}
 +
</zscript>
 +
</window>
 +
</syntax>
 +
 
 +
In fact, <code>alert</code> is a built-in function that you can use directly in the embedded Java code.
 +
 
 +
<blockquote>
 +
----
 +
<references/>
 +
</blockquote>
 +
 
 +
==It is Java and runs at the server==
 +
The embedded Java code runs at the server so it could access any resource available at the server. For example,
 +
 
 +
<syntax lang="xml" >
 +
<window title="Property Retrieval" border="normal">
 +
    Enter a property name: <textbox/>
 +
    <button label="Retrieve" onClick="alert(System.getProperty(self.getPreviousSibling().getValue()))"/>
 
</window>
 
</window>
</source>
+
</syntax>
  
Then, when you click the button, you see as follows.
+
where <code>self</code> is a built-in variable that references the component receiving the event.
  
[[Image:getting_started_app_2.JPG]]
+
If we entered <code>java.version</code> and then clicked the button, the result is as follows.
  
The <tt>onClick</tt> attribute is a special attribute used to add an event listener to the component when it is left-clicked by mouse. The attribute value could be any legal Java codes. Notice that we use <FONT FACE="Courier">quot</FONT>; to denote the double quot (") to make it a legal XML document. If you are not familiar with XML, you might take a look at the XML section in the ZK User Interface Markup Language chapter.
+
[[Image:DgGettingStartedProperty.png]]
  
The <tt>alert</tt> function is a global function to display a message dialog box. It is a shortcut to one of the <tt>show</tt> methods of the  <javadoc>org.zkoss.zul.Messagebox</javadoc> class.
+
==Identify a component==
  
<source lang="xml" >
+
A component is a POJO, so you can reference it any way you like. However, ZK provides a convenient way to identify and to retrieve a component: identifier. For example, the above code can be simplified if we named the textbox as <code>input</code> by assigning <code>id</code> to it, as follows.
<button label="Say Hello" onClick="Messagebox.show(&quot;Hello World!&quot;)"/>
 
</source>
 
  
Notes:
+
<syntax lang="xml" >
*The scripts embedded in ZUML pages are running at the server, the default language is java.
+
<window title="Property Retrieval" border="normal">
* <FONT FACE="Courier">label</FONT> in this example is not a component. It's a property of component <tt>button</tt>
+
    Enter a property name: <textbox id="input"/>
 +
    <button label="Retrieve" onClick="alert(System.getProperty(input.getValue()))"/>
 +
</window>
 +
</syntax>
  
==Write java code in your ZUML==
+
Once an identifier is assigned, it can be referenced directly in a ZUML page (such as <code>onClick</code> in the above example). In pure Java, it can be retrieved by use of <javadoc method="getFellow(java.lang.String)">org.zkoss.zk.ui.Component</javadoc>.
For fast prototyping, you can embed codes in ZUML page. The <tt>zscript</tt> element is a special element to define the scripting codes that will be evaluated when a ZUML page is rendered. Typical use includes initialization and declaring global variables and methods.
 
  
For example, the following example displays an alert window when the button is pressed.
+
<syntax lang="xml">
 +
Window win = new Window();
 +
win.setId("main"); //assign an identifier
 +
...
 +
Grid grid = (Grid)wnd.getFellow("a_grid"); //retrieve a component by identifier
 +
</syntax>
  
<source lang="xml" >
+
==A component is a POJO==
<window title="ZK app 3">
+
 
<button label="Say Hello" onClick="sayHello()"/>
+
A component is a POJO. You could instantiate and manipulate directly. For example, we could generate the result by instantiating a component to represent it, and then append it to another component (an instance of [[ZK_Component_Reference/Layouts/Vlayout|vlayout]]).
<zscript>
+
 
//default language is java
+
<syntax lang="xml" >
void sayHello(){ //declare a global function
+
<window title="Property Retrieval" border="normal">
Messagebox.show("Hello World!");
+
    Enter a property name: <textbox id="input"/>
}
+
    <button label="Retrieve" onClick="result.appendChild(new Label(System.getProperty(input.getValue())))"/>
</zscript>
+
    <vlayout id="result"/>
</window>
+
</window>
</source>
+
</syntax>
 +
 
 +
Similarly you could change the state of a component directly. All modifications will be synchronized back to the client automatically.
 +
 
 +
<syntax lang="xml" >
 +
<window title="Property Retrieval" border="normal">
 +
    Enter a property name: <textbox id="input"/>
 +
    <button label="Retrieve" onClick="result.setValue(System.getProperty(input.getValue()))"/>
 +
    <separator/>
 +
    <label id="result"/>
 +
</window>
 +
</syntax>
 +
 
 +
==MVC: Separating code from user interface==
 +
 
 +
Embedding Java code in a ZUML page is straightforward and easy to read. However, in a production environment, it is usually better to separate the code from the user interfaces. In additions, the compiled Java code runs much faster than the embedded code which is interpreted at the run time.
 +
 
 +
To separate code from UI, we could implement a Java class (aka., the controller) that implements <javadoc type="interface">org.zkoss.zk.ui.util.Composer</javadoc>, and then handle UI in <javadoc type="interface" method="doAfterCompose(org.zkoss.zk.ui.Component)">org.zkoss.zk.ui.util.Composer</javadoc>. For example, we can redo the previous example by registering an event listener in <javadoc type="interface" method="doAfterCompose(org.zkoss.zk.ui.Component)">org.zkoss.zk.ui.util.Composer</javadoc>, and then retrieve the result and instantiate a label to represent it in the event listener as follows.
 +
 
 +
<syntax lang="java">
 +
package foo;
 +
import org.zkoss.zk.ui.Component;
 +
import org.zkoss.zk.ui.util.Composer;
 +
import org.zkoss.zk.event.EventListener;
 +
import org.zkoss.zul.Label;
 +
 
 +
public class PropertyRetriever implements Composer {
 +
    public void doAfterCompose(Component target) { //handle UI here
 +
        target.addEventListener("onClick", new EventListener() { //add a event listener in Java
 +
            public void onEvent(Event event) {
 +
                String prop = System.getProperty(target.getFellow("input").getValue());
 +
                target.getFellow("result").appendChild(new Label(prop));
 +
            }
 +
        });
 +
    }
 +
}
 +
</syntax>
 +
 
 +
As shown, an event listener could be registered by use of <javadoc type="interface" method="addEventListener(java.lang.String, org.zkoss.zk.ui.event.EventListener)">org.zkoss.zk.ui.Component</javadoc>. An event listener must implement <javadoc type="interface">org.zkoss.zk.ui.event.EventListener</javadoc>, and then handle the event in <javadoc type="interface" method="onEvent(org.zkoss.zk.ui.event.Event">org.zkoss.zk.ui.event.EventListener</javadoc>.
 +
 
 +
Also notice that a component assigned with an identifier could be retrieved by use of <javadoc type="interface" method="getFellow(java.lang.String)" type="interface">org.zkoss.zk.ui.Component</javadoc>.
 +
 
 +
Then, we could associate the controller (<code>foo.PropertyRetriever</code>) with a component by use of the <code>apply</code> attribute as shown below.
 +
 
 +
<syntax lang="xml">
 +
<window title="Property Retrieval" border="normal">
 +
    Enter a property name: <textbox id="input"/>
 +
    <button label="Retrieve" apply="foo.PropertyRetriever"/>
 +
    <vlayout id="result"/>
 +
</window>
 +
</syntax>
 +
 
 +
==MVC: Automate the access with data binding==
 +
 
 +
Implementing and registering event listeners is a bit tedious. Thus, ZK provides a feature called autowiring. By extending from <javadoc>org.zkoss.zk.ui.util.GenericForwardComposer</javadoc>, ZK will looks for the members if their names match the identifiers of components. For example, we could rewrite <code>foo.PropertyRetriever</code> by utilizing the autowriing as follows.
 +
 
 +
<syntax lang="java">
 +
package foo;
 +
import org.zkoss.zk.ui.Component;
 +
import org.zkoss.zk.ui.util.GenericForwardComposer;
 +
import org.zkoss.zul.*;
 +
 
 +
public class PropertyRetriever extends GenericForwardComposer {
 +
    Textbox input;
 +
    Vlayout result;
 +
 
 +
    public retrieve$onClick(Event event) {
 +
        //handle onClick of the retrieve button
 +
        String prop = System.getProperty(input.getValue());
 +
        result.appendChild(new Label(prop));
 +
    }
 +
}
 +
</syntax>
 +
 
 +
and the ZUL page is as follows.
  
[[Image:getting_started_app_3.JPG]]
+
<syntax lang="xml">
 +
<window title="Property Retrieval" border="normal" apply="foo.PropertyRetriever">
 +
    Enter a property name: <textbox id="input"/>
 +
    <button label="Retrieve" id="retrieve"/>
 +
    <vlayout id="result"/>
 +
</window>
 +
</syntax>
  
Notes:
+
As shown above, <code>input</code> and <code>result</code> are automatically assigned such that we could access the real components directly.
*The scripts embedded in ZUML pages are running at the server, the default language is java.
+
Also <code>retrieve$onClick</code> indicates an event listener will be registered to the component called <code>retrieve</code> to handle the <code>onClick</code> event.
  
==Access Component by ID==
+
<blockquote style="border:1px solid orange">
After you assign the <tt>id</tt> attribute of a component, then you can easily access it by <tt>id</tt> . Like the following code, you can change the <tt>label</tt> of a  <tt>button</tt> by writing <tt>zscript</tt> .
+
Notice that MVC is recommended for a production application. On the other hand, to maintain readability, most examples in our documents embed code directly in ZUML pages.
 +
</blockquote>
  
<source lang="xml" >
+
==Express data with variable resolver and EL expressions==
<window title="ZK app 4">
 
<button id="btn" label="Before" onClick="change()"/>
 
<zscript>
 
void change(){
 
btn.label="After";
 
}
 
</zscript>
 
</window>
 
</source>
 
  
[[Image:getting_started_app_4.JPG]]
+
In a ZUML page, we could locate data with a variable resolver (<javadoc type="interface">org.zkoss.xel.VariableResolver</javadoc>), and then express it with [[ZK_Developer's_Guide/Fundamental_ZK/ZK_User_Interface_Markup_Language/Expression_Language_(EL)|EL expressions]].
  
In this example, we set the id of the button as 「btn」, then you can treat it as a declared global instance.
+
For example, assumes we have a class called <code>foo.User</code>, and we can retrieve a list of users by its static method called <code>getAll()</code>. Then, we can implement a variable resolver as follows.
  
==Assign component's attribute value without hard coding==
+
<syntax lang=" java">
Like JSP(JavaServer Pages), you could use EL expressions in ZUML pages. EL expressions use the syntax <tt>${expr}</tt>. In the following sample, we set the label value of  <tt>btn_2</tt> to the label value of <tt>btn_1</tt> .
+
package foo;
 +
public UserResolver implements org.zkoss.xel.VariableResolver {
 +
    public Object resolveVariable(String name) {
 +
        return "users".equals(name) ? Users.getAll(): null;
 +
}
 +
</syntax>
  
<source lang="xml" >
+
And, we can list all users as follows.
<window title="ZK app 5">
 
<button id="btn_1" label="Say Hello"/>
 
<button id="btn_2" label="${btn_1.label}"/>
 
</window>
 
</source>
 
  
[[Image:getting_started_app_5.JPG]]
+
<syntax lang="xml">
 +
<?variable-resolver class="foo.UserResolver"?>
 +
<grid>
 +
    <columns>
 +
        <column label="Name" sort="auto"/>
 +
        <column label="Title" sort="auto"/>
 +
        <column label="Age" sort="auto"/>
 +
    </columns>
 +
    <rows>
 +
        <row forEach="${users}">
 +
            <label value="${each.name}"/>
 +
            <label value="${each.title}"/>
 +
            <label value="${each.age}"/>
 +
        </row>
 +
    </rows>
 +
</grid>
 +
</syntax>
  
Chapter. ZK User interface Markup Language will provide more details on EL expressions. The Developer's Reference and JSP 2.0 tutorials or guides are also good references if you want to know even more.
+
where we assume <code>foo.User</code> has three methods: <code>getName()</code>, <code>getTitle()</code> and <code>getAge()</code>. <code>forEach</code> is used to instantiate components by iterating through a collection of objects.
  
==Design pattern: MVC==
+
[[File:DgGettingStartedUsers.png]]
If you prefer the [http://en.wikipedia.org/wiki/Model-view-controller MVC](Model-View-Controller) approadch, i.e. you prefer not to embed the handling codes in the <tt>window</tt> (the view), you can implement a class to handle events. In the example below, <tt>onClick</tt> event of the button is forwarded to <tt>window</tt> , and handled by applied class <tt>MyComposer</tt> .
 
  
<source lang="xml" >
+
==Automate the access with data binding==
<window id="win" title="ZK app 6" apply="MyComposer">
 
<button label="Say Hello" forward="onSayHello" />
 
</window>
 
</source>
 
  
 +
EL expressions are convenient but it is limited to display the read-only data. If we allow the end users to modify data, we could use the data binder to handling the display and modification for us. We need to provide the model (POJO) with proper getter and setter methods (such as <code>getName()</code> and <code>setName(String)</code>).
  
<source lang="java" >
+
First, we declare a initial class <javadoc>org.zkoss.zkplus.databind.AnnotateDataBinderInit</javadoc>. Then, express the data (read-only or writable) with annotation expressions<ref>Annotation expressions can be used by another tools, not limited to the data binder.</ref>.
//MyComposer.java
+
The annotation expression is similar to EL expressions, exception it starts with <code>@{</code>.
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"));
 
}
 
}
 
</source>
 
  
[[Image:getting_started_app_6.JPG]]
+
<syntax lang="xml">
 +
<?init class="org.zkoss.zkplus.databind.AnnotateDataBinderInit"?>
 +
<?variable-resolver class="foo.VariableResolver"?>
 +
<grid model="@{users}">
 +
    <columns>
 +
        <column label="Name" sort="auto"/>
 +
        <column label="Title" sort="auto"/>
 +
        <column label="Age" sort="auto"/>
 +
    </columns>
 +
    <rows>
 +
        <row self="@{each='user'}">
 +
            <textbox value="@{user.name}"/>
 +
            <textbox value="@{user.title}"/>
 +
            <intbox value="@{user.age}"/>
 +
        </row>
 +
    </rows>
 +
</grid>
 +
</syntax>
  
For more information, please refer to our smalltalk.
+
where a special annotation expression, <code>self="@{each='user'}"</code>, is used to iterate through a collection of users.
  
==Other Feature==
+
[[File:DgGettingStartedUsers2.png]]
ZK has many other features to help you develop your web application easily. Like Data-Binding, Live Data. Please visit our live demo and play around. You'll find the beauty of simple.
 
  
'''Notes'''
+
Notice that developers need not to handle the display and modification. They only need to prepare a POJO (such as <code>foo.User</code>). Any modification made to each input (by the end user) will be stored back to the object (<code>foo.User</code>) automatically, assuming the POJO has the required setter methods, such as <code>setName(String)</code>.
  
 +
<blockquote>
 +
----
 
<references/>
 
<references/>
 +
</blockquote>
  
 
== Quiz ==
 
== Quiz ==
#What event is triggered when a <tt>button</tt> is clicked? Hint: onXXX?
+
#What event is triggered when a button is clicked?
#What element should be used if you want to write java code in your ZUML?
+
#What element should be used if you want to embed Java code in ZUML?
#What's the benefit to assign id to a component?
+
#Why to assign an identifier to a component?
#<tt>${expr}</tt> is the syntax of?
+
#What does <code>${expr}</code> mean?
#What design pattern is mentioned here?
+
#Is it better to embed Java code in ZUML or to use MVC in a production application?
 
 
  
{{DevelopersGuidePageFooter}}
+
{{ZKDevelopersGuidePageFooter}}

Latest revision as of 10:39, 19 January 2022

Getting Started


Stop.png This documentation is for an older version of ZK. For the latest one, please click here.


This chapter describes how to write your first ZUML (ZK User interface Markup Language) page, and demonstrates some ZK's features in simple examples.

Hello World!

After ZK is installed on your favorite Web server[1], writing applications is straightforward. Just create a ZUML file, say hello.zul[2], under one of the Web application's directories just as you would do for an HTML file.

<syntax lang="xml" >

<window title="My First ZK Application" border="normal">
	Hello World!
</window>

</syntax>


Then, go to the corresponding URL, say http://localhost/myapp/hello.zul, and you'll see your first ZK application running.

DgGettingStartedHello.zul.png

In a ZUML page, an XML element describes what component to create while the XML attributes are used to assign values to a component's properties. In this example, a window component is created and its title is set to "My First ZK Application" and its border is set to normal.

The text enclosed in the XML elements is also interpreted as a special component called label. Thus, the above example is equivalent to the following.

<syntax lang="xml" >

<window title="My First ZK Application" border="normal">

<label value="Hello World!"/> </window> </syntax>


  1. For more information, please refer to ZK Installation Guide.
  2. The other way to try examples is to use ZK Sandbox to run them.

Say Hello in Ajax way

Let us put some interactivity into it.

<syntax lang="xml" >

<button label="Say Hello" onClick='Messagebox.show("Hello World!")'/>

</syntax>

Then, when you click the button, you'll see the following:

DgGettingStartedHello2.png

The onClick attribute is a special attribute used to add an event listener to the component such that it is invoked when an end user clicks the component. The attribute value could be any legal Java code. Notice that it is not JavaScript, and we have to use the double quotes (") to represent a string. Furthermore, to specify a double quote in an XML attribute, we could use single quotes (') to enclose it[1].

Here we invoke Messagebox.show(String) to show a message box as depicted above.

The Java code is interpreted by BeanShell at run time. In additions to event handling, we could embed the code in a ZUML page by specifying it in a special element called zscript. For example, we could define a function to simply the code as follows.

<syntax lang="xml" >

<window title="My First ZK Application" border="normal">
	<button label="Say Hello" onClick='alert("Hello World!")'/>
	<zscript>
		void alert(String message){ //declare a function
			Messagebox.show(message);
		}
	</zscript>
</window>

</syntax>

In fact, alert is a built-in function that you can use directly in the embedded Java code.


  1. If you are not familiar with XML, you might take a look at the XML section.

It is Java and runs at the server

The embedded Java code runs at the server so it could access any resource available at the server. For example,

<syntax lang="xml" > <window title="Property Retrieval" border="normal">

   Enter a property name: <textbox/>
   <button label="Retrieve" onClick="alert(System.getProperty(self.getPreviousSibling().getValue()))"/>

</window> </syntax>

where self is a built-in variable that references the component receiving the event.

If we entered java.version and then clicked the button, the result is as follows.

DgGettingStartedProperty.png

Identify a component

A component is a POJO, so you can reference it any way you like. However, ZK provides a convenient way to identify and to retrieve a component: identifier. For example, the above code can be simplified if we named the textbox as input by assigning id to it, as follows.

<syntax lang="xml" > <window title="Property Retrieval" border="normal">

   Enter a property name: <textbox id="input"/>
   <button label="Retrieve" onClick="alert(System.getProperty(input.getValue()))"/>

</window> </syntax>

Once an identifier is assigned, it can be referenced directly in a ZUML page (such as onClick in the above example). In pure Java, it can be retrieved by use of Component.getFellow(String).

<syntax lang="xml"> Window win = new Window(); win.setId("main"); //assign an identifier ... Grid grid = (Grid)wnd.getFellow("a_grid"); //retrieve a component by identifier </syntax>

A component is a POJO

A component is a POJO. You could instantiate and manipulate directly. For example, we could generate the result by instantiating a component to represent it, and then append it to another component (an instance of vlayout).

<syntax lang="xml" > <window title="Property Retrieval" border="normal">

   Enter a property name: <textbox id="input"/>
   <button label="Retrieve" onClick="result.appendChild(new Label(System.getProperty(input.getValue())))"/>
   <vlayout id="result"/>

</window> </syntax>

Similarly you could change the state of a component directly. All modifications will be synchronized back to the client automatically.

<syntax lang="xml" > <window title="Property Retrieval" border="normal">

   Enter a property name: <textbox id="input"/>
   <button label="Retrieve" onClick="result.setValue(System.getProperty(input.getValue()))"/>
   <separator/>
   <label id="result"/>

</window> </syntax>

MVC: Separating code from user interface

Embedding Java code in a ZUML page is straightforward and easy to read. However, in a production environment, it is usually better to separate the code from the user interfaces. In additions, the compiled Java code runs much faster than the embedded code which is interpreted at the run time.

To separate code from UI, we could implement a Java class (aka., the controller) that implements Composer, and then handle UI in Composer.doAfterCompose(Component). For example, we can redo the previous example by registering an event listener in Composer.doAfterCompose(Component), and then retrieve the result and instantiate a label to represent it in the event listener as follows.

<syntax lang="java"> package foo; import org.zkoss.zk.ui.Component; import org.zkoss.zk.ui.util.Composer; import org.zkoss.zk.event.EventListener; import org.zkoss.zul.Label;

public class PropertyRetriever implements Composer {

   public void doAfterCompose(Component target) { //handle UI here
       target.addEventListener("onClick", new EventListener() { //add a event listener in Java
           public void onEvent(Event event) {
               String prop = System.getProperty(target.getFellow("input").getValue());
               target.getFellow("result").appendChild(new Label(prop));
           }
       });
   }

} </syntax>

As shown, an event listener could be registered by use of Component.addEventListener(String, EventListener). An event listener must implement EventListener, and then handle the event in EventListener.onEvent(org.zkoss.zk.ui.event.Event.

Also notice that a component assigned with an identifier could be retrieved by use of Component.getFellow(String).

Then, we could associate the controller (foo.PropertyRetriever) with a component by use of the apply attribute as shown below.

<syntax lang="xml"> <window title="Property Retrieval" border="normal">

   Enter a property name: <textbox id="input"/>
   <button label="Retrieve" apply="foo.PropertyRetriever"/>
   <vlayout id="result"/>

</window> </syntax>

MVC: Automate the access with data binding

Implementing and registering event listeners is a bit tedious. Thus, ZK provides a feature called autowiring. By extending from GenericForwardComposer, ZK will looks for the members if their names match the identifiers of components. For example, we could rewrite foo.PropertyRetriever by utilizing the autowriing as follows.

<syntax lang="java"> package foo; import org.zkoss.zk.ui.Component; import org.zkoss.zk.ui.util.GenericForwardComposer; import org.zkoss.zul.*;

public class PropertyRetriever extends GenericForwardComposer {

   Textbox input;
   Vlayout result;
   public retrieve$onClick(Event event) {
       //handle onClick of the retrieve button
       String prop = System.getProperty(input.getValue());
       result.appendChild(new Label(prop));
   }

} </syntax>

and the ZUL page is as follows.

<syntax lang="xml"> <window title="Property Retrieval" border="normal" apply="foo.PropertyRetriever">

   Enter a property name: <textbox id="input"/>
   <button label="Retrieve" id="retrieve"/>
   <vlayout id="result"/>

</window> </syntax>

As shown above, input and result are automatically assigned such that we could access the real components directly. Also retrieve$onClick indicates an event listener will be registered to the component called retrieve to handle the onClick event.

Notice that MVC is recommended for a production application. On the other hand, to maintain readability, most examples in our documents embed code directly in ZUML pages.

Express data with variable resolver and EL expressions

In a ZUML page, we could locate data with a variable resolver (VariableResolver), and then express it with EL expressions.

For example, assumes we have a class called foo.User, and we can retrieve a list of users by its static method called getAll(). Then, we can implement a variable resolver as follows.

<syntax lang=" java"> package foo; public UserResolver implements org.zkoss.xel.VariableResolver {

   public Object resolveVariable(String name) {
       return "users".equals(name) ? Users.getAll(): null;

} </syntax>

And, we can list all users as follows.

<syntax lang="xml"> <?variable-resolver class="foo.UserResolver"?> <grid>

   <columns>
       <column label="Name" sort="auto"/>
       <column label="Title" sort="auto"/>
       <column label="Age" sort="auto"/>
   </columns>
   <rows>
       <row forEach="${users}">
           <label value="${each.name}"/>
           <label value="${each.title}"/>
           <label value="${each.age}"/>
       </row>
   </rows>

</grid> </syntax>

where we assume foo.User has three methods: getName(), getTitle() and getAge(). forEach is used to instantiate components by iterating through a collection of objects.

DgGettingStartedUsers.png

Automate the access with data binding

EL expressions are convenient but it is limited to display the read-only data. If we allow the end users to modify data, we could use the data binder to handling the display and modification for us. We need to provide the model (POJO) with proper getter and setter methods (such as getName() and setName(String)).

First, we declare a initial class AnnotateDataBinderInit. Then, express the data (read-only or writable) with annotation expressions[1]. The annotation expression is similar to EL expressions, exception it starts with @{.

<syntax lang="xml"> <?init class="org.zkoss.zkplus.databind.AnnotateDataBinderInit"?> <?variable-resolver class="foo.VariableResolver"?> <grid model="@{users}">

   <columns>
       <column label="Name" sort="auto"/>
       <column label="Title" sort="auto"/>
       <column label="Age" sort="auto"/>
   </columns>
   <rows>
       <row self="@{each='user'}">
           <textbox value="@{user.name}"/>
           <textbox value="@{user.title}"/>
           <intbox value="@{user.age}"/>
       </row>
   </rows>

</grid> </syntax>

where a special annotation expression, self="@{each='user'}", is used to iterate through a collection of users.

DgGettingStartedUsers2.png

Notice that developers need not to handle the display and modification. They only need to prepare a POJO (such as foo.User). Any modification made to each input (by the end user) will be stored back to the object (foo.User) automatically, assuming the POJO has the required setter methods, such as setName(String).


  1. Annotation expressions can be used by another tools, not limited to the data binder.

Quiz

  1. What event is triggered when a button is clicked?
  2. What element should be used if you want to embed Java code in ZUML?
  3. Why to assign an identifier to a component?
  4. What does ${expr} mean?
  5. Is it better to embed Java code in ZUML or to use MVC in a production application?



Last Update : 2022/01/19

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