Client Side Programming

From Documentation
DocumentationSmall Talks2010AprilClient Side Programming
Client Side Programming

Author
Peter Kuo, Engineer, Potix Corporation
Date
April 20, 2010
Version
ZK 5.0 and above

Introduction

In ZK 5 we continue to focus on our strong Server-side approach which boosts your productivity but now provides developers the option to control the client side programming. We have dubbed this blending of technology, Server+client Fusion.

In order to execute application-specific code at the client, ZK introduces the concept of the Client Namespace [1]. With the Client Namespace, developers are able to listen to any client-side event, override ZK methods and execute any custom client-side code.


  1. For ZK 3.6 and prior, please use Client Side Actions instead.

Before writing JavaScript in a ZUL file

Define ZK Client Namespace

In order to write client-side code, you are required to specify the XML namespace which is named http://www.zkoss.org/2005/zk/client. In the following example, you can see the onClick event is handled by client side JavaScript.

<button label="client" xmlns:w="http://www.zkoss.org/2005/zk/client" w:onClick="alert('clicked')"/>

How to Get Widget Reference in JavaScript

When the client event is invoked, you can reference the widget using this. In the below example this refers to the label.

<window xmlns:w="http://www.zkoss.org/2005/zk/client">
  <label value="change me by click" w:onClick="this.setValue('clicked');"/> 
</window>

widget can retrieve other widgets using the function $f. This works in a similar manner as getFellow.

In additions, you can use jQuery to select a DOM element of a widget[1]. For example jq("@window") will select DOM elements of all window widget. And, jq("$win1") will select DOM elements of all widgets whose ID is win1. (see jq).

<window xmlns:w="http://www.zkoss.org/2005/zk/client">
	<vbox>
		<label id="labelone" value="click to change"
			w:onClick="this.setValue('changed by click label');" />

		<button label="button"
			w:onClick="this.$f('labelone').setValue('changed by button');" />

		<html><![CDATA[
		<a href="javascript:;" onclick="zk.Widget.$(jq('$labelone')[0]).setValue('changed with jq');">not widget</a>
		]]></html>		
	
	</vbox>
</window>

zk.Widget.$ is a utility to return particular zk widget by given id of dom element. (see Widget).


  1. Since ZK 5.0.2

Execute JavaScript After All Widgets Are Loaded

Set defer attribute of script to "true", if you want to access widgets. It means deferring the execution of the script codes until the widget is instantiated and mounted. Note that script here is a zk component, not an HTML tag. Similarly, defer here is not in the same context as HTML . More detail at Script.

<script defer="true">
..........
</script>

Things you can do

Define a Client-side Listener of ZK Widget event

For example, handle onClick event of a label component's corresponding widget at the client side.

<window xmlns:w="http://www.zkoss.org/2005/zk/client">
  <label value="change me by click" w:onClick="this.setValue('clicked');"/> 
</window>

In an event listener, you can access the widget by using this as shown above. In addition, you can access the event (an instance of Event) by using event.

You can find more detail at ZK5: Client Computing with ZUML

Override a Widget Method

For example, override the setValue implementation of a label widget.

<window xmlns:w="http://www.zkoss.org/2005/zk/client">
      <label>
            <attribute w:name="setValue">
            function (value) {
                  this.$setValue(value); //call the original method
                  if (this.desktop) {
                        this._flag = !this._flag;
                        this.setStyle('background:'+(this._flag ? 'red':'green'));
                  }
            }
            </attribute>
      </label>
</window>

You can find more detail at ZK5: Client Computing with ZUML.

EL expressions is allowed [1][2] to simplify the passing of data from server to client. For example, you could pass a Java bean's property to the client as shown below.

w:setValue='function (value) { this.$setValue(value + "${foo.description}")}';
  1. EL expressions are allowed since ZK 5.0.2
  2. EL is evaluated when rendering a page. In other words, it is evaluated before sending the JavaScript code to the client for execution later.

Override a Default Widget Method

In previous section, we showed how to override method of a particular widget we declared. But how to override the default widget method for all such widgets? We can modify it by overwriting the widget's prototype implementation. The following is a sample to modify the default setValue of label

<window xmlns:w="http://www.zkoss.org/2005/zk/client">
	<label id="labelone" value="label one"/>
	<label id="labeltwo" value="label two"/>
	<script defer="true">
		old = zul.wgt.Label.prototype.setValue;			
		zul.wgt.Label.prototype.setValue = function (){
			arguments[0]="modified prototype"+arguments[0];
			old.apply(this,arguments);
		}					
	</script>
	<button label="change" onClick='labelone.setValue((new Date()).toString());labeltwo.setValue((new Date()).toString());'/>		
</window>

Override a Default Widget Method for Whole Application

In additions to specifying the JavaScript code or file in each page, you can configure ZK to load one or more particular JavaScript files.

First, you have to modify zk.xml to specify a so-called lang-addon XML file. For example,

<zk>
......
	<language-config>
		<addon-uri>/WEB-INF/mylabel-lang-addon.xml</addon-uri>
	</language-config>	
......
</zk>

Then, you can specify the JavaScript files to load with each ZK page in this XML file as follows.

<?xml version="1.0" encoding="UTF-8"?>
<language-addon>
	<language-name>xul/html</language-name>
	<javascript src="/mylabel.js" charset="UTF-8"/>	
</language-addon>

The content of the JavaScript file, of course, could be anything you want. For example, if you want to customize the behavior of Label, the JavaScript file could be as follows:

zk.afterLoad("zul.wgt",function(){
	old = zul.wgt.Label.prototype.setValue;			
	zul.wgt.Label.prototype.setValue = function (){
		arguments[0]="lang-addon "+arguments[0];
		old.apply(this,arguments);
	}					
});

Notice that it is important to use zk.afterLoad(String, Function) to specify the customization code, since ZK JavaScript packages are loaded only when required. In other words, the customization code has to wait until the package is loaded. In this example, we have to wait for the zul.wgt package being loaded to execute the customization code.

Define a New Widget Method

For example, in ZK 5.0 and Server+Client Fusion, we defined an update function for listbox

<zk xmlns:w="http://www.zkoss.org/2005/zk/client">
....
<listbox id="list" rows="10" width="300px">
	<attribute w:name="update"><![CDATA[
	....
	]]></attribute>
</listbox>

Define a DOM Attribute

[Since 5.0.3]

Sometimes we need to specify a DOM attribute that is not generated by a ZK widget. It can be done by use the client-attribute namespace: <cdoe>http://www.zkoss.org/2005/zk/client/attribute". For example, if you want to generate the onload attribute for the iframe component, then you can do as follows:

<iframe src="http://www.google.com" width="100%" height="300px"
 xmlns:wa="http://www.zkoss.org/2005/zk/client/attribute"
 wa:onload="alert(window.location.href)"/>

The generate DOM element will then have an attribute called onload.

Specify a Different Widget Class

You could specify your own implementation instead of the default widget class (at the client) as follows.

<zk xmlns:w="http://www.zkoss.org/2005/zk/client">
  ...
  <button w:use="foo.MyButton"/>
</zk>

where foo.MyButton is a widget you implement. For example,

zk.$package("foo").MyButton = zk.$extends(zul.wgt.Button, {
  setLabel: function (label) {
   this.$supers("setLabel", arguments);
   //do whatever you want
  }
});

Watch': ZK Client Engine Event

To implement a ZK widget, traditional DOM events are not enough. Therefore, ZK defines extra widget related events like onHide,onFloatUp and system-level events such as watch. ZK provide its mechanism to fire and listen to watch.

<window xmlns:w="http://www.zkoss.org/2005/zk/client">
	<button label="show" onClick="b1.setVisible(true);" />
	<button label="hide" onClick="b1.setVisible(false);" />
	<!--
	onShow is not called when first time rendering.
	It is called while setVisible="false", and then setVisible="true"	
	-->
	<button label="if onShow" id="b1"
		style="position:relative;zoom:1">
		<attribute w:name="onShow">
			alert("listened to onShow");
		</attribute>
		<attribute w:name="bind_">
			function () { this.$bind_(); zWatch.listen({onShow: this});}
		</attribute>
	</button>
</window>


Use Third Party JavaScript Library

ZK 5.0 and jQuery part 2 demonstrates how to utilize jQuery UI Tools for low-level interaction, animation and more.

Listen to DOM event

For more sophisticated control, you can listen to DOM events. The following example demonstrates two different ways to handle the onblur event.

<window title="listen dom event" border="normal"
	xmlns:w="http://www.zkoss.org/2005/zk/client">
	<textbox value="onBlur to alert" w:onBlur="alert('onBlur by zk')" />
	<textbox value="onblur to alert">
		<attribute w:name="bind_">
			function () { 
				this.$bind_(); 
				jq(this).bind('blur',function(event){alert('blurred by jquery')});
			}
		</attribute>
	</textbox>
</window>

Animation

Please visit ZK Live Demo and search for "animations". The following is a simplified example.

<zk xmlns:w="http://www.zkoss.org/2005/zk/client">
	<button label="slideDown"
		w:onClick="jq(this.$f('t')).hide().slideDown()" />
	<div id="t">
		<button label="target" />
	</div>
</zk>
  • Since 5.0.2, there is an alternative way to look for a fellow:
this.$f().fellowId

Communicate to Server

zAu is an utility to communicate with the server. In other words, it handles AU requests and responses. The following example sends a customized onUser event to the server.

<window>
	<html onUser='l.value ="onUser "+org.zkoss.lang.Objects.toString(event.data)'><![CDATA[
	<a href="javascript:;" onclick="zAu.send(new zk.Event(zk.Widget.$(this), 'onUser',[1,2]));">onUser with [1, 2]</a>
	]]></html>		
	<label id="l"/>	
</window>

Summary

The ability to do client side programming allows developers to easily access and control ZK widgets. ZK retains its server-centric philosophy for productivity but enhances the controllability at client side with this capability; making it just as customizable as any client centric framework. The possibilities are limiteless.

Download

I've created a project named zk-sample host on google code. The related sample code can be found on its repository.

See Also

  1. ZK 5.0 and Server+Client Fusion
  2. ZK 5.0 and jQuery
  3. ZK 5.0 and jQuery part 2
  4. Client Computing with ZUML
  5. jq -- jQuery selector for ZK widget.
  6. Widget -- See the usage of $f(), $n(), bind_(), $()
  7. Client Side Actions -- Deprecated since ZK5
  8. Client Activity Watches -- onShow, onHide in ZK5
  9. JavaScript API -- Documentation for ZK JavaScript API.
  10. Customizing Error Box -- from Forum
  11. How to position image after label text on each tab of tabbox? -- from Forum, modify domContent_ is a good way to customize a little bit.

Comments



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