Tutorial"

From Documentation
Line 2: Line 2:
 
For a real world example, please refer to [[ZK_Getting_Started/Create_a_Real_World_application_step_by_step|Create a Real World application step by step]].
 
For a real world example, please refer to [[ZK_Getting_Started/Create_a_Real_World_application_step_by_step|Create a Real World application step by step]].
 
==Hello World!==
 
==Hello World!==
After ZK is installed on your favorite Web server<ref>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.
+
 
 +
After ZK is installed on your favorite Web server<ref>Please refer to [[ZK Installation Guide]].</ref>, writing applications is straightforward. Just create a ZUML file, name it as 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" >
 
<source lang="xml" >
Line 11: Line 12:
  
  
Then, go to the corresponding URL, say http://localhost/myapp/hello.zul, and you'll see your first ZK application running.
+
Then, go to the corresponding URL, which is http://localhost/myapp/hello.zul, and you'll see your first ZK application running.
  
 
[[Image:dgGettingStartedHello.zul.png]]
 
[[Image:dgGettingStartedHello.zul.png]]
  
In a ZUML page, an XML element describes what component<ref>Interface : <javadoc type="interface">org.zkoss.zk.ui.Component</ref> to create while the XML attributes are used to assign values to a component's properties. In this example, a <tt>window</tt> component is created and its <tt>title</tt> is set to <tt>"My First ZK Application"</tt> and its <tt>border</tt> is set to <tt>normal</tt>.
+
On a ZUML page, an XML element describes what component<ref>Interface : <javadoc type="interface">org.zkoss.zk.ui.Component</ref> to create while the XML attributes are used to assign values to a component's properties. In this example, a <tt>window</tt> component is created and its <tt>title</tt> is set to <tt>"My First ZK Application"</tt> and its <tt>border</tt> is set to <tt>normal</tt>.
  
 
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 <tt>label</tt>. Thus, the above example is equivalent to the following.
Line 47: Line 48:
 
Here we invoke <javadoc method="show(java.lang.String)">org.zkoss.zul.Messagebox</javadoc> to show a message box as depicted above.
 
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, you could embed the code in a ZUML page by specifying it in a special element called <tt>zscript</tt>. For example, you could define a function to simply the code as follows.
+
The Java code is interpreted by [http://www.beanshell.org/ BeanShell] at run time. In addition to event handling, you could embed the code in a ZUML page by specifying it in a special element called <tt>zscript</tt>. For example, you could simply define a function to the code as follows.
  
 
<source lang="xml" >
 
<source lang="xml" >
Line 67: Line 68:
 
</blockquote>
 
</blockquote>
  
==It is Java and runs at the server==
+
==It is Java and runs on the server==
The embedded Java code runs at the server so it could access any resource available at the server. For example,
+
The embedded Java code runs on the server so it could access any resource available on the server. For example,
  
 
<source lang="xml" >
 
<source lang="xml" >
Line 77: Line 78:
 
</source>
 
</source>
  
where <tt>self</tt> is a built-in variable that references the component receiving the event.
+
where <tt>self</tt> is a built-in variable that referring the component receiving the event.
  
If you enter <tt>java.version</tt> and then clicked the button, the result is as follows.
+
If you enter <tt>java.version</tt> and then click the button, the result is as follows.
  
 
[[Image:DgGettingStartedProperty.png]]
 
[[Image:DgGettingStartedProperty.png]]
Line 87: Line 88:
 
[[Image:architecture-s.png]]
 
[[Image:architecture-s.png]]
  
A ZK application runs at the server. It could access the backend resources, assemble UI with components, listen to user's activity, and then manipulate components to update UI. All are done at the server. The synchronization of the states of the components between the browser and the server is done automatically by ZK, and transparent to the application.
+
A ZK application runs on the server. It could access the backend resources, assemble UI with components, listen to users' activity, and then manipulate components to update UI. All are done on the server. The synchronization of the states of the components between the browser and the server is done automatically by ZK, and transparent to the application.
  
When running at the server, the application can access the full stack of Java technology. User activities are, including Ajax and Server Push, abstracted to event objects. UI are composed by POJO-like components. It is the most productive approach to develop a modern Web application.
+
When running on the server, the application can access the full stack of Java technology. Users' activities, including Ajax and Server Push, are abstracted to event objects. UI are composed of POJO-like components. It is the most productive approach to develop a modern Web application.
  
With ZK's Server+client Fusion architecture, your application won't stop at the server. The application could enhance the interactivity by adding optional client-side functionality, such as client-side event handling, visual effect customizing, and even UI composing without the server-side code. ZK is the only framework to enable the seamless fusion ranging from pure server-centric, to pure client-centric. You have the best of two worlds: productivity and flexibility.
+
With ZK's Server+client Fusion architecture, your application won't stop on the server. The application could enhance the interactivity by adding optional client-side functionality, such as client-side event handling, visual effect customizing, and even UI composing without the server-side code. ZK is the only framework to enable the seamless fusion from pure server-centric to pure client-centric. You have the best of two worlds: productivity and flexibility.
  
 
==Identify a component==
 
==Identify a component==
  
A component is a POJO, so you can reference it any way you like. In additions, ZK provides a convenient way to identify and to retrieve a component: identifier. For example, the above code can be simplified if you name the textbox as <tt>input</tt> by assigning <tt>id</tt> to it, as follows.
+
A component is a POJO, so you can reference it any way you like. In additions, ZK provides a convenient way to identify and to retrieve a component: identifier. For example, the code above can be simplified if you name the textbox as <tt>input</tt> by assigning an <tt>id</tt> to it, as follows.
  
 
<source lang="xml" >
 
<source lang="xml" >
Line 104: Line 105:
 
</source>
 
</source>
  
Once an identifier is assigned, it can be referenced directly in a ZUML page (such as <tt>onClick</tt> 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>.
+
Once an identifier is assigned, it can be referenced directly in a ZUML page (such as <tt>onClick</tt> in the above example). In pure Java, it can be retrieved using <javadoc method="getFellow(java.lang.String)">org.zkoss.zk.ui.Component</javadoc>.
 
<source lang="java">
 
<source lang="java">
 
Window win = new Window();
 
Window win = new Window();
Line 128: Line 129:
 
</source>
 
</source>
  
Once appended, the components will be shown up at the browser automatically. Similarly, if components are detached, they are removed from the browser automatically.  In additions, you could change the state of a component directly. All modifications will be synchronized back to the browser automatically.  
+
Once appended, the components are shown up in the browser automatically. Similarly, if components are detached, they are removed from the browser automatically.  In additions, you could change the state of a component directly. All modifications will be synchronized back to the browser automatically.  
  
 
<source lang="xml" >
 
<source lang="xml" >
Line 145: Line 146:
 
==MVC: Separate code from user interface==
 
==MVC: Separate 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.
+
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 addition, the compiled Java code runs much faster than the embedded code which is interpreted at the run time.
  
 
To separate code from UI, you can 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, you 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.
 
To separate code from UI, you can 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, you 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.
Line 168: Line 169:
 
</source>
 
</source>
  
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>.
+
As shown, an event listener could be registered by the 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>.
+
Also notice that a component assigned with an identifier could be retrieved by the use of <javadoc type="interface" method="getFellow(java.lang.String)" type="interface">org.zkoss.zk.ui.Component</javadoc>.
  
Then, you could associate the controller (<tt>foo.PropertyRetriever</tt>) with a component by use of the <tt>apply</tt> attribute as shown below.
+
Then, you could associate the controller (<tt>foo.PropertyRetriever</tt>) with a component using the <tt>apply</tt> attribute as shown below.
  
 
<source lang="xml">
 
<source lang="xml">
Line 184: Line 185:
 
==MVC: Autowire UI objects to data members==
 
==MVC: Autowire UI objects to data members==
  
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, you could rewrite <tt>foo.PropertyRetriever</tt> by utilizing the autowriing as follows.
+
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 looks for the members if their names match the identifiers of components. For example, you could rewrite <tt>foo.PropertyRetriever</tt> by utilizing the autowriing as follows.
  
 
<source lang="java" title="PropertyRetriever.java">
 
<source lang="java" title="PropertyRetriever.java">
Line 224: Line 225:
 
==Express data with variable resolver and EL expressions==
 
==Express data with variable resolver and EL expressions==
  
In a ZUML page, you could locate data with a variable resolver (<javadoc type="interface">org.zkoss.xel.VariableResolver</javadoc>), and then express it with [[ZK Developer's Reference/UI Composing/ZUML/EL Expressions|EL expressions]].
+
On a ZUML page, you could locate data with a variable resolver (<javadoc type="interface">org.zkoss.xel.VariableResolver</javadoc>), and then express it with [[ZK Developer's Reference/UI Composing/ZUML/EL Expressions|EL expressions]].
  
For example, assumes we have a class called <tt>foo.User</tt>, and we can retrieve a list of users by its static method called <tt>getAll()</tt>. Then, we can implement a variable resolver as follows.
+
For example, assumes that we have a class called <tt>foo.User</tt>, and we can retrieve a list of users by its static method called <tt>getAll()</tt>. Then, we can implement a variable resolver as follows.
  
 
<source lang=" java">
 
<source lang=" java">
Line 257: Line 258:
 
</source>
 
</source>
  
where we assume <tt>foo.User</tt> has three methods: <tt>getName()</tt>, <tt>getTitle()</tt> and <tt>getAge()</tt>. <tt>forEach</tt> is used to instantiate components by iterating through a collection of objects.
+
There are three methods that we can assume <tt>foo.User</tt>: <tt>getName()</tt>, <tt>getTitle()</tt> and <tt>getAge()</tt>. <tt>forEach</tt> is used to instantiate components by iterating through a collection of objects.
  
 
[[File:DgGettingStartedUsers.png]]
 
[[File:DgGettingStartedUsers.png]]
Line 263: Line 264:
 
==Automate the access with data binding==
 
==Automate the access with data binding==
  
EL expressions are convenient but it is limited to display the read-only data. If you allow the end users to modify data or we'd like to change the display based on user's selection, you could use the data binder to handling the display and modification automatically for us. All you need to do is to provide the model (POJO) with proper getter and setter methods (such as <tt>getName()</tt> and <tt>setName(String)</tt>).
+
EL expressions are convenient but they are limited to display the read-only data. If you allow the end users to modify data or we'd like to change the display based on users' selection, you could use the data binder to handle the display and modification automatically for us. All you need to do is to provide the model (POJO) with proper getter and setter methods (such as <tt>getName()</tt> and <tt>setName(String)</tt>).
  
 
First, you could declare an 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>.
 
First, you could declare an 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>.
The annotation expression is similar to EL expressions, exception it starts with <tt>@{</tt>.
+
The annotation expression is similar to EL expressions, but it starts with <tt>@{</tt>.
  
 
<source lang="xml">
 
<source lang="xml">
Line 291: Line 292:
 
[[File:DgGettingStartedUsers2.png]]
 
[[File:DgGettingStartedUsers2.png]]
  
Notice that developers need not to handle the display and modification. They only need to prepare a POJO (such as <tt>foo.User</tt>). Any modification made to each input (by the end user) will be stored back to the object (<tt>foo.User</tt>) automatically, assuming the POJO has the required setter methods, such as <tt>setName(String)</tt>.
+
Please notice that developers need not to handle the display and modification. They only need to prepare a POJO (such as <tt>foo.User</tt>). Any modification made to each input (by the end user) is stored back to the object (<tt>foo.User</tt>) automatically, assuming the POJO has the required setter methods, such as <tt>setName(String)</tt>.
  
 
<blockquote>
 
<blockquote>
Line 326: Line 327:
 
</source>
 
</source>
  
A richlet (<javadoc type="interface">org.zkoss.zk.ui.Richlet</javadoc>) is a small Java program that creates all necessary user interfaces for a given page in response to user's request. Here we extends from a skeleton called <javadoc>org.zkoss.zk.ui.GenericRichlet</javadoc>. Then, we create all required components straightforwardly in <javadoc method="service(org.zkoss.zk.ui.Page)">org.zkoss.zk.ui.Richlet</javadoc>.
+
A richlet (<javadoc type="interface">org.zkoss.zk.ui.Richlet</javadoc>) is a small Java program that creates all necessary user interfaces for a given page in response to users' request. Here we extends from a skeleton called <javadoc>org.zkoss.zk.ui.GenericRichlet</javadoc>. Then, we create all required components straightforwardly in <javadoc method="service(org.zkoss.zk.ui.Page)">org.zkoss.zk.ui.Richlet</javadoc>.
  
 
==Add client-side functionality==
 
==Add client-side functionality==
  
In additions to handling events and components at the server, ZK also provides an option allowing developers to control UI at the client. We have dubbed this blending of technology, Server+client Fusion.  
+
In addition to handling events and components on the server, ZK also provides an option allowing developers to control UI from the client side. We have dubbed this blending of technology, Server+client Fusion.  
  
 
For example, we could re-implement the Hello World example with client-side code as follows.
 
For example, we could re-implement the Hello World example with client-side code as follows.
Line 338: Line 339:
 
</source>
 
</source>
  
where we declare a [http://www.w3schools.com/xml/xml_namespaces.asp XML namespace] named <code>client</code> to indicate the event handler shall be evaluated at the client. In additions, <javadoc method="alert(_global_.String, _global_.Map)" directory="jsdoc">_global_.jq</javadoc> is a client-side method equivalent to <javadoc method="show(java.lang.String)">org.zkoss.zul.Messagebox</javadoc>.
+
where we declare a [http://www.w3schools.com/xml/xml_namespaces.asp XML namespace] named <code>client</code> to indicate the event handler shall be evaluated at the client. In addition, <javadoc method="alert(_global_.String, _global_.Map)" directory="jsdoc">_global_.jq</javadoc> is a client-side method equivalent to <javadoc method="show(java.lang.String)">org.zkoss.zul.Messagebox</javadoc>.
  
All components are available and accessible at the client. For example, here is a number guessing game that manipulates UI at the client.
+
All components are available and accessible to the client. For example, here is a number guessing game that manipulates UI from the client side.
  
 
<source lang="xml">
 
<source lang="xml">

Revision as of 03:52, 20 June 2011

This tutorial guides you through the most fundamental features of ZK to help you understand ZK faster. For a real world example, please refer to Create a Real World application step by step.

Hello World!

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

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


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

DgGettingStartedHello.zul.png

On a ZUML page, an XML element describes what component[3] 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.

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

  1. Please refer to ZK Installation Guide.
  2. The other way to try examples is to use ZK Sandbox to run them.
  3. Interface : <javadoc type="interface">org.zkoss.zk.ui.Component

Say Hello in Ajax way

Let us put some interactivity into it.

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

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(EventListener) 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 you have to use the double quotes (") to represent a string. Furthermore, to specify a double quote in an XML attribute, you 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 addition to event handling, you could embed the code in a ZUML page by specifying it in a special element called zscript. For example, you could simply define a function to the code as follows.

 <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>

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 background section.

It is Java and runs on the server

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

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

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

If you enter java.version and then click the button, the result is as follows.

DgGettingStartedProperty.png

Architecture overview

Architecture-s.png

A ZK application runs on the server. It could access the backend resources, assemble UI with components, listen to users' activity, and then manipulate components to update UI. All are done on the server. The synchronization of the states of the components between the browser and the server is done automatically by ZK, and transparent to the application.

When running on the server, the application can access the full stack of Java technology. Users' activities, including Ajax and Server Push, are abstracted to event objects. UI are composed of POJO-like components. It is the most productive approach to develop a modern Web application.

With ZK's Server+client Fusion architecture, your application won't stop on the server. The application could enhance the interactivity by adding optional client-side functionality, such as client-side event handling, visual effect customizing, and even UI composing without the server-side code. ZK is the only framework to enable the seamless fusion from pure server-centric to pure client-centric. You have the best of two worlds: productivity and flexibility.

Identify a component

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

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

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 using Component.getFellow(String).

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

A component is a POJO

A component is a POJO. You could instantiate and manipulate them directly. For example, you could generate the result by instantiating components to represent it, and then append them to another component.

<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>

Once appended, the components are shown up in the browser automatically. Similarly, if components are detached, they are removed from the browser automatically. In additions, you could change the state of a component directly. All modifications will be synchronized back to the browser automatically.

<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>

A component is a LEGO brick

Instead of introducing different components for different purposes, our components are designed to be building blocks. You are free to compose them together to realize sophisticated UI without customizing any components. For example, you could put anything in a grid, including grid itself; anything in any layout, including layout itself. Please refer to our demo for great examples.

MVC: Separate 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 addition, the compiled Java code runs much faster than the embedded code which is interpreted at the run time.

To separate code from UI, you can implement a Java class (aka., the controller) that implements Composer, and then handle UI in Composer.doAfterCompose(Component). For example, you 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.

package foo;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.util.Composer;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zul.Label;

public class PropertyRetriever implements Composer {
    public void doAfterCompose(final 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(((Textbox)target.getFellow("input")).getValue());
                target.getFellow("result").appendChild(new Label(prop));
            }
        });
    }
}

As shown, an event listener could be registered by the 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 the use of Component.getFellow(String).

Then, you could associate the controller (foo.PropertyRetriever) with a component using the apply attribute as shown below.

<window title="Property Retrieval" border="normal">
    Enter a property name: <textbox id="input"/>
    <button label="Retrieve" apply="foo.PropertyRetriever"/>
    <vlayout id="result"/>
</window>

MVC: Autowire UI objects to data members

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

package foo;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.util.GenericForwardComposer;
import org.zkoss.zul.*;

public class PropertyRetriever extends GenericForwardComposer {
    Textbox input; // Autowired by same component type/ID
    Vlayout result; // Autowired by same component type/ID

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

and the ZUL page is as follows.

<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>

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

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

Express data with variable resolver and EL expressions

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

For example, assumes that 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.

package foo;
public class UserResolver implements org.zkoss.xel.VariableResolver {
    public Object resolveVariable(String name) {
        return "users".equals(name) ? Users.getAll(): null;
    }
}

And, we can list all users as follows.

<?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>

There are three methods that we can assume foo.User: 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 they are limited to display the read-only data. If you allow the end users to modify data or we'd like to change the display based on users' selection, you could use the data binder to handle the display and modification automatically for us. All you need to do is to provide the model (POJO) with proper getter and setter methods (such as getName() and setName(String)).

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

<?init class="org.zkoss.zkplus.databind.AnnotateDataBinderInit"?>
<?variable-resolver class="foo.UserResolver"?>
<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>

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

DgGettingStartedUsers2.png

Please 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) is 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.

Define UI in pure Java

Instead of the ZUML page, developers could define UI in pure Java. For example, you could implement the property-retrieval example as follows.

public class PropertyRetrieval extends GenericRichlet {
	public void service(Page page) throws Exception {
		final Window main = new Window("Property Retrieval", "normal", false);
		main.appendChild(new Label("Enter a property name: "));

		final Textbox input = new Textbox();
		input.setId("input");
		main.appendChild(input);

		final Button button = new Button("Retrieve");
		button.addEventListener("onClick",
			new EventListener() {
				public void onEvent(Event event) throws Exception {
					Messagebox.show(System.getProperty(input.getValue()));
				}
			});
		main.appendChild(button);

		main.setPage(page); //attach so it and all descendants will be generated to the client
	}
}

A richlet (Richlet) is a small Java program that creates all necessary user interfaces for a given page in response to users' request. Here we extends from a skeleton called GenericRichlet. Then, we create all required components straightforwardly in Richlet.service(Page).

Add client-side functionality

In addition to handling events and components on the server, ZK also provides an option allowing developers to control UI from the client side. We have dubbed this blending of technology, Server+client Fusion.

For example, we could re-implement the Hello World example with client-side code as follows.

<button label="Say Hello" w:onClick='jq.alert("Hello World!")' xmlns:w="client"/>

where we declare a XML namespace named client to indicate the event handler shall be evaluated at the client. In addition, jq.alert(String, Map) is a client-side method equivalent to Messagebox.show(String).

All components are available and accessible to the client. For example, here is a number guessing game that manipulates UI from the client side.

<window title="Guess a number" border="normal">
	<vlayout>
    Type number between 0 and 99 and then press Enter to guess:
    <intbox w:onOK="guess(this)" xmlns:w="client"/>
    </vlayout>
    <script><![CDATA[
	var num = Math.floor(Math.random() * 100);
	function guess(wgt) {
		var val = wgt.getValue(),
			mesg = val > num ? "smaller than " + val:
				val < num ? "larger than "+val: val + " is correct!";
		wgt.parent.appendChild(new zul.wgt.Label({value: mesg}));
		wgt.setValue("");
	}
    ]]></script>
</window>

where onOK is an event fired when the user presses Enter, and script is used to embed the client-side code (in contrast to zscript for embedding the server-side code).

DgGettingStartedGuessNumber.png


Last Update : 2011/06/20