You are on page 1of 29

ZK Component Development

Essentials
For ZK 5.0.7

PDF generated using the open source mwlib toolkit. See http://code.pediapress.com/ for more information.
PDF generated at: Wed, 11 May 2011 09:41:04 CST
Contents
Articles
ZK Component Development Essentials 1
ZK Component Overview 1
What is a ZK component 1
How does a ZK Component work 2
Development Tools 3
Creating a simple ZK Component 3
ZK's JavaScript Extension 3
Implementing the Component 4
Implementing a Component Property 5
Render All Properties to the Client 6
Putting it all Together 7
Implementing the Widget 8
Implementing a Widget Property 9
Putting it all Together 10
Rendering Widgets 11
Implementing Molds 11
The Redraw Method 12
Creating the Configuration Files 12
The language-addon 12
The Widget Package Descriptor 13
Handling Events 15
How we Implement the Event 15
Overriding bind and unbind 16
Registering Appropriate Listeners 17
Client-Server Communication 18
Server-side Listeners 20
Declaring an Important Event 21
Packing as a Jar 21
Conclusion 25

References
Article Sources and Contributors 26
Image Sources, Licenses and Contributors 27
ZK Component Development Essentials 1

ZK Component Development Essentials


Documentation:Books/ZK_Component_Development_Essentials

If you have any feedback regarding this book, please leave it here.
<comment>http://books.zkoss.org/wiki/ZK_Component_Development_Essentials2</comment>

ZK Component Overview
This section provides an overview to ZK Component development.

What is a ZK component
Each UI object in ZK consists of a component and a widget.

Component
A component is a Java object running at the server which represents a UI object which can be manipulated by a Java
application. A component has all the behavior of a UI object except it has no visual part.

Widget
A widget is a JavaScript object running at the client. This object represents the UI object which interacts with the
user. Therefore, a widget usually has a visual appearance, and handles events happening at the client.
Having established that there are two parts to a ZK Component one needs to explore how these parts interact to form
a fully interactive user experience.
How does a ZK Component work 2

How does a ZK Component work


A component and a widget work hand in hand to deliver a rich UI experience to a user. The widget traps the user
activity and sends an appropriate request to the component. The component then interacts with the developer’s
Application and responds appropriates telling the widget to update. This interaction is demonstrated in the following
diagram.

For example, when an application invokes the setLabel method to change the label of a button component, the
setLabel method of corresponding button widget (aka., peer widget) will be invoked at the client to change the visual
appearance (as shown below).

When the user clicks the button widget, the onClick event will be sent back to the server and notify the application
(as demonstrated below).

In additions to manipulate a component at the server, it is also possible to control a widget at the client. For example,
an application may hide or change the order of grid columns at the client, while the application running at the server
handles the reloading of the grid’s content. This technique is called Server+client fusion. It can be used to improve
responsiveness and reduce network traffic.
Development Tools 3

Development Tools
Here is a list of development tools. Though optional, they are helpful in many situations.

Tool Description

[1] A component development tool providing wizards to simplify the creation of components.
ZK CDT

[2] A JavaScript debugger. It is an addon for Firefox. It is not built-in, so you have to download and install it
Firebug
separately.

Internet Explorer 9 Developer It is built-in and you could start it by pressing F12.
Tools

References
[1] http:/ / code. google. com/ a/ eclipselabs. org/ p/ zk-cdt/
[2] http:/ / getfirebug. com/

Creating a simple ZK Component


This section provides instructions on how to create a ZK component.

ZK's JavaScript Extension


To make it easier for JavaScript objects to represent widgets ZK has introduced a class concept to JavaScript. Here is
a brief introduction on defining a class in JavaScript.
To define a new class in JavaScript, we use _global_.Map, _global_.Map) zk.$extends(zk.Class, _global_.Map,
_global_.Map) [1].

zk.$package('com.foo');

com.foo.Location = zk.$extends(zk.Object, {
x: 0,
y: 0,
distance: function (loc) {
return Math.sqrt(Math.pow(this.x - loc.x, 2) + Math.pow(this.y -
loc.y, 2));
}
},{
find: function (name) {
if (name == 'ZK')
return new com.foo.Location(10, 10);
throw 'unknown: "+name;
}
})

The first argument of _global_.Map, _global_.Map) zk.$extends(zk.Class, _global_.Map, _global_.Map) [1] is the
base class to extend from. In this case, we extend from Object [2], which is the root of the class hierarchy. The
ZK's JavaScript Extension 4

second argument consists of the (non-static) members of the class. In this case, we define two data members (x and
y) and one method (distance).
The third argument is optional and if omitted means that the extended class will contain no static members. In the
example we define a static method (<mp>find</mp>). For now this is all that is required for us to create our first
component so let’s move onto talk about the component implementation.

References
[1] http:/ / www. zkoss. org/ javadoc/ latest/ jsdoc/ _global_/ zk. html#$extends(zk. Class,
[2] http:/ / www. zkoss. org/ javadoc/ latest/ jsdoc/ zk/ Object. html#

Implementing the Component


As previously mentioned a ZK Component consists of a server-side component usually written in Java and a client
based widget written in JavaScript. Firstly let’s discuss the creation of the server-side component.
The component’s Java class must extend AbstractComponent [1] or one of its derivative classes. There are several
derived classes all providing different levels of functionality. The derived classes are shown below.

For tutorial purpose, we use HtmlBasedComponent [2], which is the base class for HTML-based component.
To implement a component class, we need to decide on
• The class name. Let’s name it <mp>com.foo.SimpleLabel</mp>
• The properties to support. In this case, we'd like to implement a property called value, which is the visual content
at the client.
Let’s investigate the component properties.
Implementing the Component 5

References
[1] http:/ / www. zkoss. org/ javadoc/ latest/ zk/ org/ zkoss/ zk/ ui/ AbstractComponent. html#
[2] http:/ / www. zkoss. org/ javadoc/ latest/ zk/ org/ zkoss/ zk/ ui/ HtmlBasedComponent. html#

Implementing a Component Property


A property usually has a getter and a setter. The getter is straightforward:

private String _value = ""; //a data member

public String getValue() {


return _value;
}

The setter is similar except we have to notify the client. This is achieved by using the java.lang.Object)
AbstractComponent.smartUpdate(java.lang.String, java.lang.Object) [1] function.

public void setValue(String value) {


if (!_value.equals(value)) {
_value = value;
smartUpdate("value", _value);
}
}

The java.lang.Object) AbstractComponent.smartUpdate(java.lang.String, java.lang.Object) [1] function causes ZK


Client Engine to call the <mp>setValue</mp> method of the peer widget (the first argument is the property name).
Then, the widget can manipulate the DOM tree from there.

References
[1] http:/ / www. zkoss. org/ javadoc/ latest/ zk/ org/ zkoss/ zk/ ui/ AbstractComponent. html#smartUpdate(java. lang. String,
Render All Properties to the Client 6

Render All Properties to the Client


When a component is attached to a page at the first time, the renderProperties(org.zkoss.zk.ui.sys.ContentRenderer)
[1]
method is called to render all properties that will be sent to the client for creating a peer widget. All required
properties have to be rendered such that the client can create a peer widget with the same set of properties.
Implementing renderProperties(org.zkoss.zk.ui.sys.ContentRenderer) [1] is straightforward. As shown below, all you
need to do is to invoke <mp>super.renderProperties</mp> to render all inherited properties (such as width and
height), and then the render method to render the property defined in this class.

protected void renderProperties(org.zkoss.zk.ui.sys.ContentRenderer


renderer)
throws java.io.IOException {
super.renderProperties(renderer);
render(renderer, "value", _value);
}

Why renderProperties and smartUpdate?


A common question is why renderProperties(org.zkoss.zk.ui.sys.ContentRenderer) [1] (and redraw(java.io.Writer)
[2]
) is required to render value again, when we notify the client with boolean) smartUpdate(java.lang.String, boolean)
[1]
in setValue?
The simple answer is renderProperties is used to send all properties at once, when a component is going to be
attached to the page at the client. On the other hand, boolean) smartUpdate(java.lang.String, boolean) [1] is used to
send a property that was modified after the peer widget is attached at the client. ZK will minimize the traffic by
removing unnecessary boolean) smartUpdate(java.lang.String, boolean) [1] (if renderProperties is called).
Once a widget is attached to the page at the client, renderProperties won’t be called. If you want to regenerate all
properties and rerender it at the client, you can invoke the invalidate method. Note that if you update a property
multiple times in the same execution (with boolean) smartUpdate(java.lang.String, boolean) [1]), only the last value
will be sent to the client. If you prefer to send them all (rather than overwriting), then you can set the 3rd argument
append to true (java.lang.Object, boolean) smartUpdate(java.lang.String, java.lang.Object, boolean) [1]). For example
you may use this when adding a listener for a certain event and you do not want to overwrite the present listener this
is achieved by passing true as the third argument of boolean) smartUpdate(java.lang.String, boolean) [1]. The table
below outlines the differences.

smartUpdate smartUpdate (append, 3rd argument true)

Sent to client if invalidated or new created No No

Sent to client if the component is No No


removed

Sent to client if name is the same Only the last value is sent Yes
Render All Properties to the Client 7

References
[1] http:/ / www. zkoss. org/ javadoc/ latest/ zk/ org/ zkoss/ zk/ ui/ AbstractComponent. html#renderProperties(org. zkoss. zk. ui. sys.
ContentRenderer)
[2] http:/ / www. zkoss. org/ javadoc/ latest/ zk/ org/ zkoss/ zk/ ui/ AbstractComponent. html#redraw(java. io. Writer)

Putting it all Together


Finally we put all the component information together to produce the result below.

package com.foo;

public class SimpleLabel extends org.zkoss.zk.ui.HtmlBasedComponent {


private String _value = ""; // a data member

public String getValue() {


return _value;
}

public void setValue(String value) {


if (!_value.equals(value)) {
_value = value;
smartUpdate("value", _value);
}
}

protected void
renderProperties(org.zkoss.zk.ui.sys.ContentRenderer renderer)
throws java.io.IOException {
super.renderProperties(renderer);
render(renderer, "value", _value);
}
}

Having implemented the Component we now need to implement the Widget.


Implementing the Widget 8

Implementing the Widget


The widget class must extend from Widget [1] or one of its derived classes. There are several skeletal
implementations available. The skeletal implementations are shown in the image below.

For the purposes of this tutorial, we will use Widget [1]. Before we proceed, we need to decide the name of the
widget class. Let’s assume <mp>com.foo.SimpleLabel</mp>.

References
[1] http:/ / www. zkoss. org/ javadoc/ latest/ jsdoc/ zk/ Widget. html#
Implementing a Widget Property 9

Implementing a Widget Property


A property usually has a getter and a setter. The getter is straightforward:

_value: '', //default value

getValue: function () {
return this._value;
}

The setter is defined in a similar manner except we have to modify the DOM tree if it has been attached. A widget
inherits a property called node which is assigned a reference to a DOM element if the widget has been attached to the
DOM tree. If a widget is attached to DOM, <mp>this.desktop</mp> will be a reference to the desktop (Desktop [1])
it belongs. Otherwise, it is null.
How we update depends on the DOM content. In this example, we use HTML's span to enclose the value, so we only
need to change innerHTML.

setValue: function(value) {
if (this._value != value) {
this._value = value;
if (this.desktop) this.$n().innerHTML = zUtl.encodeXML(value);
}
}

References
[1] http:/ / www. zkoss. org/ javadoc/ latest/ zk/ zk/ Desktop. html#
Putting it all Together 10

Putting it all Together


The widget implementation must be placed in an independent JavaScript file. The file must be placed under the
directory, /web/js/package-path, in the Java class path. Since the widget name is SimpleLabel and the package
name is com.foo, the file path is /web/js/com/foo/SimpleLabel.js.

com.foo.SimpleLabel = zk.$extends(zk.Widget, {
_value : '', // default value

getValue : function() {
return this._value;
},

setValue : function(value) {
if (this._value != value) {
this._value = value;
if (this.desktop)
this.$n().innerHTML = zUtl.encodeXML(value);
}
}

});

Having set-up the ability to handle states we now need to create the component view. This can be accomplished
using two methods.
Rendering Widgets 11

Rendering Widgets
Rendering of widgets can be achieved using two methods. The first is named mold which enables a widget to have
multiple display types which a developer or user can select at will. The second is a redraw method which only
supports one type of view. Firstly let us discuss how to implement a mold.

Implementing Molds
A widget can have several molds. Each mold needs to be placed in an independent JavaScript file. Under a
subdirectory named mold. The full path of the directory in this example will be
/web/js/com/foo/mold/simple-label.js.
Let us assume we want to generate the following DOM content:
<mp>value</mp>
Then, the content of simple-label.js will be as follows.

function (out) {
out.push('<span', this.domAttrs_(), '>', this.getValue(), '</span>');
}

As shown above, the mold is actually a JavaScript method. More precisely, it is a method member of the widget
class (the name is assigned by ZK Client Engine automatically), so you can access the widget object by use of this.
The mold method takes an argument named out, which behaves like a writer in Java. The out object at least
implements the push and unshift method to write the content to the end or to the beginning. It is by default an array,
but the client application might use different kinds of objects.
[1]
<mp>domAttrs_</mp> is a (protected) method inherited from Widget . It returns all HTML attributes required,
such as style, id and so on. You can override it if you want.
If we do not require multiple styles per component we can just implement the redraw method directly.
The Redraw Method 12

The Redraw Method


When a widget is attached to the DOM tree, Widget.redraw(_global_.Array) [1] is called to generate the HTML
content. For example, assume you want to use <mp>HTML SPAN</mp> tag to house the content, we can do as
follows.

redraw: function (out) {


out.push('<span', this.domAttrs_(), '>', this.getValue(), '</span>');
}

The default implementation of Widget.redraw(_global_.Array) [1] delegates to a mold method depending on the
mold. In this instance we override the function to provide one implementation of redraw which doesn’t use molds.

References
[1] http:/ / www. zkoss. org/ javadoc/ latest/ jsdoc/ zk/ Widget. html#redraw(_global_. Array)

Creating the Configuration Files


In order for our component to be used in ZK applications we need to provide two component files named
language-addon and zk.wpd.

The language-addon
The language-addon contains a description of the relation between the component and widget referred to as the
component definition. The path of the file must be /metainfo/zk/lang-addon.xml and be located in the Java class
path.

<language-addon>
<addon-name>simplelabel</addon-name>
<language-name>xul/html</language-name>

<component>
<component-name>simplelabel</component-name>
<component-class>com.foo.SimpleLabel</component-class>
<widget-class>com.foo.SimpleLabel</widget-class>
<mold>
<mold-name>default</mold-name>
<mold-uri>mold/simple-label.js</mold-uri>
<css-uri>css/simple-label.css.dsp</css-uri>
</mold>
</component>
</language-addon>

The table below describes the elements used within the above XML and their descriptions.
The language-addon 13

Name Description

addon-name A unique name for this addon

language-name The language name that this addon belongs to (for instance, xul/html or
zhtml)

component-name A unique name of the component in the language of this addon

component-class The name of the component class (Java class)

widget-class The name of the widget class (JavaScript class)

mold A mold definition (optional)

mold-name The name of the mold. The default mold is named default.

mold-uri The URI of the mold

css-uri The URI of the CSS file for the mold

A component may have multiple molds which may or may not have different widget classes. To handle this you may
specify the <widget-class> inside <mold>. You can specify more than one mold.
After creating the component descriptor language-addon we need to create the widget package descriptor.
For more information, please refer to ZK Client-side Reference: Language Definition.

The Widget Package Descriptor


The Widget Package Descriptor (WPD) is a file describing the information of a package, such as its widget classes
and external JavaScript files. WPD must be named zk.wpd and placed in the same directory as the widget classes.
For example we would place it under web/js/com/foo.
Below an example zk.wpd of our SimpleLabel.

<package name="com.foo" language="xul/html">


<widget name="SimpleLabel"/>
</package>

The table below describes the elements used within the above XML and their descriptions.

Name Description

package The root element denotes the package name and the language it belongs to

widget The widget class name (without the package name). If the package contains multiple widgets list them one by one

Having created the configuration the basic implementation of our component is complete. However it doesn』t have
any interactive events. Therefore the next logical step is to start adding events to the component.
The Widget Package Descriptor 14

Package Dependence
It is common for JavaScript packages to depend on another package. For example, zul.grid depends on
zul.mesh and zul.menu. This can easily be specified by placing them within the depends attribute as
follows.

<package name="zul.grid" language="xul/html" depends="zul.mesh,zul.menu">


<widget name="Column"/>
<widget name="Columns"/>
<widget name="Grid"/>
<widget name="Row"/>
<widget name="Rows"/>
<widget name="Foot"/>
<widget name="Footer"/>
</package>

Including additonal JavaScript files


If a JavaScript package has to include other JavaScript files, this can be done easily by specifying the file with the
script element. For example, the following is the content of zul.db's WPD:

<package name="zul.db" language="xul/html" depends="zk.fmt,zul.inp">


<script src="datefmt.js"/>
<widget name="Calendar"/>
<widget name="Datebox"/>
</package>

For more information, please refer to ZK Client-side Reference: Widget Package Descriptor.
Handling Events 15

Handling Events
The next logical step is to add an event to our ZK component. To this we are going add some more functionality to
the SimpleLabel. A new div will be added which when clicked should clear the displayed text and fire a custom
event named <mp>onClear</mp>.
This means that firstly we need to change the mold of the label to include a div which can be used as a target. The
code below satisfies this requirement:

function (out) {
out.push('<span', this.domAttrs_(), '><div id="value" style="float:left;">', this.getVal
}

As you can see we have now split the contents of label into two by introducing two div tags, one will be used to
display the value and the other will be a click target.

How we Implement the Event


To implement the required event we need to follow these steps:
1. Override zk.Skipper, _global_.Array) bind_(zk.Desktop, zk.Skipper, _global_.Array) [1] and _global_.Array)
unbind_(zk.Skipper, _global_.Array) [2]
2. Register the appropriate listener

References
[1] http:/ / www. zkoss. org/ javadoc/ latest/ jsdoc/ zk/ Widget. html#bind_(zk. Desktop,
[2] http:/ / www. zkoss. org/ javadoc/ latest/ jsdoc/ zk/ Widget. html#unbind_(zk. Skipper,
Overriding bind and unbind 16

Overriding bind and unbind


The following diagrams outline when the zk.Skipper, _global_.Array) bind_(zk.Desktop, zk.Skipper,
_global_.Array) [1] and _global_.Array) unbind_(zk.Skipper, _global_.Array) [2] methods are called. Firstly let’s take
a look at how binding works.

The _global_.Array) unbind_(zk.Skipper, _global_.Array) [2] function is very similar. Upon detaching of the widget
from the DOM the _global_.Array) unbind_(zk.Skipper, _global_.Array) [2] method is called enabling us to perform
tasks such as adding and removing listeners to avoid memory leaks. The diagram below demonstrates this.

Now that we have had a brief introduction of zk.Skipper, _global_.Array) bind_(zk.Desktop, zk.Skipper,
_global_.Array) [1] and _global_.Array) unbind_(zk.Skipper, _global_.Array) [2] let’s see the methods put into action
when we bind appropriate listeners for events.
Registering Appropriate Listeners 17

Registering Appropriate Listeners


Registering listeners is a fundamental of many programming languages and event driven applications. Being an
event driven framework ZK is no different. To accomplish our goal of a clear button we need to do two things:
1. Capture clicks on our "target"
2. Fire a custom <mp>onClear</mp> event when the target is clicked

Capturing Clicks on our Target


Firstly, let’s concentrate on capturing clicks on our target div. To do so we need to register appropriate listeners in
the bind_ method and remove the listeners in the unbind_ method to avoid any memory leak. Here is the code to do
so.

bind_ : function(evt) {
this.$supers('bind_', arguments);
this.domListen_(this.$n().lastChild, "onClick",
'_doClear');
},

unbind_ : function(evt) {
this.domUnlisten_(this.$n().lastChild, "onClick",
'_doClear');
this.$supers('unbind_', arguments);
},

The key to this is the domListen method which takes the target as the first parameter, in this case we pass it the
<mp>lastChild</mp> which is our target, the name of the event you want to listen for as the second parameter and
finally the name of the callback.
Please note that you also are required to call <mp>$supers</mp> so that parent classes can register and remove their
events successfully. Now we need to move on to firing our custom <mp>"onClear"</mp> event, let’s take a look at
how to do this.

Firing a Custom Event (onClear)


The key lies in the registering the callback of the event. In our case we registered a callback named
<mp>"_doClear"</mp>. In this <mp>_doClear</mp> method we need to clear/restore the text depending on the
widget state and fire the onClear method. The code is as follows:

_doClear: function(evt) {

this._cleared = !(this._cleared);

if(this._cleared) {
this.$n().firstChild.innerHTML = this._value;
} else {
this.$n().firstChild.innerHTML = "";
}

this.fire("onClear", {cleared: this._cleared});


Registering Appropriate Listeners 18

We have a data member named _cleared which contains the state of the application. Depending on the state the
method either shows or clears the displayed value. The method <mp>onClear</mp> is then fired and the cleared
state is sent along with the instruction to fire the event.
The client side widget will now communicate with the component at the server side. This is handled by ZK. The
following section explores how this communication works.

Client-Server Communication
The following diagram outlines how communication works between a ZK Widget and Component.

zk.Object, _global_.Map, int) Widget.fire(_global_.String, zk.Object, _global_.Map, int) [1] fires a client event (an
instance of Event [2]), and the client event is converted to an AU request if all the following conditions are satisfied.
• The widget is a peer of a component, that is, it was created automatically to represent a component. Notice that
the Server states whether a widget is a peer of a component.
• The event propagation is not stopped (i.e., zk.Object, _global_.Map, int) Widget.fire(_global_.String, zk.Object,
_global_.Map, int) [1] not set.
• The event is listened by a server-side Listener [3], or it is an important event.
The above image demonstrates that the onClear event is sent to the server and processed. The code to do is located in
the component’s Java file SimpleLabel.java and is as follows.

public void service(org.zkoss.zk.au.AuRequest request, boolean


everError) {
final String cmd = request.getCommand();

if (cmd.equals(ClearEvent.NAME)) {
ClearEvent evt = ClearEvent.getClearEvent(request);
_cleared = evt.getCleared();
Events.postEvent(evt);
Client-Server Communication 19

} else
super.service(request, everError);
}

Here the ClearEvent is in fact a completely customized event created for the purposes of this component. The event
is created using its static method <mp>getClearEvent</mp>, shown below.

public static final ClearEvent getClearEvent(AuRequest request) {


final Component comp = request.getComponent();
final Map data=request.getData();

boolean cleared = AuRequests.getBoolean(data, "cleared");


return new ClearEvent(request.getCommand(), comp, cleared);
}

The retrieval of the event is easy as the ClearEvent extends Event and its constructor has the following signature
public ClearEvent(String name, Component target, boolean cleared). The only custom information is the
Boolean cleared which is the state we sent back when the event was fired. As demonstrated in the above code this is
easily acquired using the java.lang.String) AuRequests.getBoolean(java.util.Map, java.lang.String) [4].
We have now followed the process of how data is transferred between the client and server. Of course when building
component we also need to specify server side listeners to invoke Java code on calling of specific events, let’s
investigate this.

References
[1] http:/ / www. zkoss. org/ javadoc/ latest/ jsdoc/ zk/ Widget. html#fire(_global_. String,
[2] http:/ / www. zkoss. org/ javadoc/ latest/ jsdoc/ zk/ Event. html#
[3] http:/ / www. zkoss. org/ javadoc/ latest/ zk/ org/ zkoss/ zk/ ui/ Listener. html#
[4] http:/ / www. zkoss. org/ javadoc/ latest/ zk/ org/ zkoss/ zk/ au/ AuRequests. html#getBoolean(java. util. Map,
Server-side Listeners 20

Server-side Listeners
Then we move on and fire the <mp>"onClear"</mp> event. To fully understand what happens next we now need to
investigate server side listeners which handle these events. A client event will not be sent to the server if it has not
been registered. To give the developer the ability to register an event listener at the serverside we need to declare the
events. We do this using the function addClientEvent.
The following example demonstrates declaring a clear event at the server.

static {
addClientEvent(SimpleLabel.class, ClearEvent.NAME, 0);
}

We have noted that if an event is not registered at the server side then it will not be sent from the client. However, in
our example there is a problem if the event is not sent back. Let’s cast our mind back to the service method we
implemented.

public void service(org.zkoss.zk.au.AuRequest request, boolean


everError) {
final String cmd = request.getCommand();

if (cmd.equals(ClearEvent.NAME)) {
ClearEvent evt = ClearEvent.getClearEvent(request);
_cleared = evt.getCleared();
Events.postEvent(evt);
} else
super.service(request, everError);
}

Notice that on the receipt of the <mp>ClearEvent</mp> we update the <mp>_cleared</mp> property at the server
side. Imagine if this event is not sent then we have a problem as the client and server side will be out of sync. To get
around this we can register the event as important.
Declaring an Important Event 21

Declaring an Important Event


The third argument of <mp>addClientEvent</mp> is used to declare an event as import. The argument is a
combination of integer flags that indicate how to handle the event. The CE_IMPORTANT flag is used to indicate
that this event is very important and should be sent to the server even if there is no server side listener registered for
the event. For other flags, please refer to the Java API.
For example, we require the <mp>onClear</mp> event to be sent to the server at all times so we are required to
declare the following:

static {
addClientEvent(SimpleLabel.class, ClearEvent.NAME,
CE_IMPORTANT);
}

Now the ClearEvent is guaranteed to be sent to the server which solves our syncing problem. Now we have a simple
label with some additional features which works as advertised. This label has served as a good introduction to
component development with ZK.

Packing as a Jar
Jar Files
Packing a component as a Jar file will make it easy to deployment, this article is telling you steps and requirements
of it.

• Requirements of a component Jar


Configurations
Component classes
Widget Resources
Static Resources

what do they look like , example from zul.jar

Configurations
Packing as a Jar 22

File Structure The example from zul.jar

• /META-INF/
• MANIFEST.MF
• /metainfo/
• mesg/
• msg<jar name>.properties(optional)
• msg<jar name>_<locale>.properties (optional ...)
• xml/
• <component-name>.xsd (optional)
• zk/
• lang.xml (optional)
• lang-addon.xml (optional)

File descriptions
• /META-INF/
• MANIFEST.MF
• The file for jar defino
• /metainfo/
• mesg/
• msg<jar name>.properties
• These files are i18n resource files,you can define with the locale you want , the default file is
msg<jar name>.properties.
ZK Internationalization
• xml/
• <jar-name>.xsd
• The xml schema for component tags in zul
• tld
• config.xml
• For taglibs definition. (ex. zweb.jar use this for dsp.)
• zk/
• lang-addon.xml
• The language add-on define components , and it defined the component classes, javascript
widget/mold/css.
it should contains At least one lang.xml or lang-addon.xml usually you will need a
lang-addon.xml .
• lang.xml
• The language definition file with namespace (ex. http:/ / www. w3. org/ 1999/ xhtml for zhtml)

Component classes
Packing as a Jar 23

File Structure
• /package-folder
• classes

File descriptions
• The java classes of component. just like normal jar
file.

The example from zul.jar

Widget Resources

File Structure Example for box from zul.jar

• /web/
• js/
• component-package/
• mold/
• <widget-mold-js-file>
• css/
• <widget-css-dsp-file> (optional)
• <widget-css-file> (optional)
• <widget-class-js-file>
• /zk.wpd

File descriptions
• /web/
• js/
• <component-package>/
• mold/
• <widget-mold-js-file> (ex. simple-label.js )
• Widget mold file , you can write widget's html with javascript function
here.
• css/
• <widget-css-dsp-file> (ex. simple-label.css.dsp )
• The css dsp files ,in the dsp you can use some variable with zk
enviroment to write it.
• <widget-css-file> (ex. simple-label.css )
• the pure css files.
• <widget-class-file> (ex. Simple-label.js)
• The widget class you write .
• zk.wpd
• Define your component's package and widgets here, and the dependency
with other package.
Packing as a Jar 24

Static Resources

File Structure Example from


zul.jar
• /web/
• <component-package> / (optional)
• css /(optional)
• <css files>(optional)
• zk.wcs(optional)
• img /(optional)
• <img files>(optional)

File descriptions
• /web/
• <component-package>/
• css/
• <css files>
• For some static css file you might need.
• zk.wcs
• Let you can config the CSS file for particular language
• img/
• <img files>
• This is a folder for some image files , and you can access them in xxx.css.dsp files through
${c:encodeURL('~./img/<component-package>/xxx.png')}
Conclusion 25

Conclusion
At this point we have enough knowledge to go ahead and produce components for ZK. The next port of call for
advancing our skills is ZK’s source code itself which exposes hundreds of components.
Article Sources and Contributors 26

Article Sources and Contributors


ZK Component Development Essentials  Source: http://books.zkoss.org/index.php?title=ZK_Component_Development_Essentials  Contributors: Sphota, Tmillsclare, Tomyeh

ZK Component Overview  Source: http://books.zkoss.org/index.php?title=ZK_Component_Development_Essentials/ZK_Component_Overview  Contributors: Tmillsclare

What is a ZK component  Source: http://books.zkoss.org/index.php?title=ZK_Component_Development_Essentials/ZK_Component_Overview/What_is_a_ZK_component  Contributors:


Tmillsclare, Tomyeh

How does a ZK Component work  Source: http://books.zkoss.org/index.php?title=ZK_Component_Development_Essentials/ZK_Component_Overview/How_does_a_ZK_Component_work


 Contributors: Tmillsclare

Development Tools  Source: http://books.zkoss.org/index.php?title=ZK_Component_Development_Essentials/ZK_Component_Overview/Development_Tools  Contributors: Tomyeh

Creating a simple ZK Component  Source: http://books.zkoss.org/index.php?title=ZK_Component_Development_Essentials/Creating_a_simple_ZK_Component  Contributors: Tmillsclare

ZK's JavaScript Extension  Source: http://books.zkoss.org/index.php?title=ZK_Component_Development_Essentials/Creating_a_simple_ZK_Component/ZK%27s_JavaScript_Extension


 Contributors: Tmillsclare

Implementing the Component  Source: http://books.zkoss.org/index.php?title=ZK_Component_Development_Essentials/Creating_a_simple_ZK_Component/Implementing_the_Component


 Contributors: Tmillsclare

Implementing a Component Property  Source:


http://books.zkoss.org/index.php?title=ZK_Component_Development_Essentials/Creating_a_simple_ZK_Component/Implementing_the_Component/Implementing_a_Component_Property
 Contributors: Jimmyshiau, Tmillsclare

Render All Properties to the Client  Source:


http://books.zkoss.org/index.php?title=ZK_Component_Development_Essentials/Creating_a_simple_ZK_Component/Implementing_the_Component/Render_All_Properties_to_the_Client
 Contributors: Tmillsclare

Putting it all Together  Source:


http://books.zkoss.org/index.php?title=ZK_Component_Development_Essentials/Creating_a_simple_ZK_Component/Implementing_the_Component/Putting_it_all_Together  Contributors:
Tmillsclare

Implementing the Widget  Source: http://books.zkoss.org/index.php?title=ZK_Component_Development_Essentials/Creating_a_simple_ZK_Component/Implementing_the_Widget


 Contributors: Tmillsclare

Implementing a Widget Property  Source:


http://books.zkoss.org/index.php?title=ZK_Component_Development_Essentials/Creating_a_simple_ZK_Component/Implementing_the_Widget/Implementing_a_Widget_Property
 Contributors: Tmillsclare

Putting it all Together  Source:


http://books.zkoss.org/index.php?title=ZK_Component_Development_Essentials/Creating_a_simple_ZK_Component/Implementing_the_Widget/Putting_it_all_Together  Contributors:
Jumperchen, Tmillsclare

Rendering Widgets  Source: http://books.zkoss.org/index.php?title=ZK_Component_Development_Essentials/Creating_a_simple_ZK_Component/Rendering_Widgets  Contributors:


Tmillsclare

Implementing Molds  Source: http://books.zkoss.org/index.php?title=ZK_Component_Development_Essentials/Creating_a_simple_ZK_Component/Rendering_Widgets/Implementing_Molds


 Contributors: Jumperchen, Tmillsclare

The Redraw Method  Source: http://books.zkoss.org/index.php?title=ZK_Component_Development_Essentials/Creating_a_simple_ZK_Component/Rendering_Widgets/The_Redraw_Method


 Contributors: Tmillsclare

Creating the Configuration Files  Source: http://books.zkoss.org/index.php?title=ZK_Component_Development_Essentials/Creating_the_Configuration_Files  Contributors: Tmillsclare

The language-addon  Source: http://books.zkoss.org/index.php?title=ZK_Component_Development_Essentials/Creating_the_Configuration_Files/The_language-addon  Contributors:


Tmillsclare, Tomyeh, Tonyq

The Widget Package Descriptor  Source: http://books.zkoss.org/index.php?title=ZK_Component_Development_Essentials/Creating_the_Configuration_Files/The_Widget_Package_Descriptor


 Contributors: Tmillsclare, Tomyeh

Handling Events  Source: http://books.zkoss.org/index.php?title=ZK_Component_Development_Essentials/Handling_Events  Contributors: Tmillsclare

How we Implement the Event  Source: http://books.zkoss.org/index.php?title=ZK_Component_Development_Essentials/Handling_Events/How_we_Implement_the_Event  Contributors:


Tmillsclare

Overriding bind and unbind  Source:


http://books.zkoss.org/index.php?title=ZK_Component_Development_Essentials/Handling_Events/How_we_Implement_the_Event/Overriding_bind_and_unbind  Contributors: Tmillsclare

Registering Appropriate Listeners  Source:


http://books.zkoss.org/index.php?title=ZK_Component_Development_Essentials/Handling_Events/How_we_Implement_the_Event/Registering_Appropriate_Listeners  Contributors: Tmillsclare

Client-Server Communication  Source: http://books.zkoss.org/index.php?title=ZK_Component_Development_Essentials/Handling_Events/Client-Server_Communication  Contributors:


Tmillsclare

Server-side Listeners  Source: http://books.zkoss.org/index.php?title=ZK_Component_Development_Essentials/Handling_Events/Server-side_Listeners  Contributors: Tmillsclare

Declaring an Important Event  Source: http://books.zkoss.org/index.php?title=ZK_Component_Development_Essentials/Handling_Events/Declaring_an_Important_Event  Contributors:


Tmillsclare

Packing as a Jar  Source: http://books.zkoss.org/index.php?title=ZK_Component_Development_Essentials/Packing_as_a_Jar  Contributors: Char, Flyworld, Tomyeh, TonyQ

Conclusion  Source: http://books.zkoss.org/index.php?title=ZK_Component_Development_Essentials/Conclusion  Contributors: Tmillsclare


Image Sources, Licenses and Contributors 27

Image Sources, Licenses and Contributors


File:ZKComDevEss_widget_component_application.png  Source: http://books.zkoss.org/index.php?title=File:ZKComDevEss_widget_component_application.png  License: unknown
 Contributors: Tmillsclare
File:ZKComDevEss_button_labels.png  Source: http://books.zkoss.org/index.php?title=File:ZKComDevEss_button_labels.png  License: unknown  Contributors: Tmillsclare
File:ZKComDevEss_button_click.png  Source: http://books.zkoss.org/index.php?title=File:ZKComDevEss_button_click.png  License: unknown  Contributors: Tmillsclare
File:ZKComDevEss_component_hierarchy.png  Source: http://books.zkoss.org/index.php?title=File:ZKComDevEss_component_hierarchy.png  License: unknown  Contributors: Tmillsclare
File:ZKComDevEss_widget_hierarchy.png  Source: http://books.zkoss.org/index.php?title=File:ZKComDevEss_widget_hierarchy.png  License: unknown  Contributors: Tmillsclare
File:ZKComDevEss_bind_.png  Source: http://books.zkoss.org/index.php?title=File:ZKComDevEss_bind_.png  License: unknown  Contributors: Tmillsclare
File:ZKComDevEss_unbind_.png  Source: http://books.zkoss.org/index.php?title=File:ZKComDevEss_unbind_.png  License: unknown  Contributors: Tmillsclare
File:ZKComDevEss_fire_event.png  Source: http://books.zkoss.org/index.php?title=File:ZKComDevEss_fire_event.png  License: unknown  Contributors: Tmillsclare
File:Jar_File_summary.jpg  Source: http://books.zkoss.org/index.php?title=File:Jar_File_summary.jpg  License: unknown  Contributors: TonyQ
File:Jar_File_configuration1.jpg  Source: http://books.zkoss.org/index.php?title=File:Jar_File_configuration1.jpg  License: unknown  Contributors: TonyQ
File:Jar_File_component1.jpg  Source: http://books.zkoss.org/index.php?title=File:Jar_File_component1.jpg  License: unknown  Contributors: TonyQ
File:Jar_File_widget1.jpg  Source: http://books.zkoss.org/index.php?title=File:Jar_File_widget1.jpg  License: unknown  Contributors: TonyQ
File:Jar_File_static_resources1.jpg  Source: http://books.zkoss.org/index.php?title=File:Jar_File_static_resources1.jpg  License: unknown  Contributors: TonyQ

You might also like