ZK 5.0 and jQuery part 2

From Documentation
DocumentationSmall Talks2009JulyZK 5.0 and jQuery part 2
ZK 5.0 and jQuery part 2

Author
Timothy Clare, Technology Evangelist, Potix Corporation
Date
July 13, 2009
Version
ZK 5.0 preview release


Introduction

ZK5 now uses jQuery client side opening up a wide range of possibilities. One of the biggest benefit to use jQuery is that there are a lot of excellent plug-ins, in this article we will demonstrate the implementation of a client side effect using jQuery UI Tools which provides abstractions for low-level interaction, animation and more.

This is the second part of a two part series, the first part is located here and looks at a much more simple effect.


ZUL file outline

The ZUL file is sectioned into 3 parts, firstly we have the client side scripting, which is surrounded by <script> tags and the script directive (<?script src=... ?>).

        <!-- CLIENT SIDE FUNCTIONALITY!	-->
	<?script src="jquery-ui-1.7.2.custom.min.js"?>
	<script>
		<![CDATA[
			function updateWithExplosion (value, fromServer, updateColor) {
				
				if(this.desktop) {
					jq(this).effect("explode", 
							{}, 
							500);
				}
				
				this.$setValue(value, fromServer);
				
				if (this.desktop) {	
					if (updateColor) {
						jq(this.getCaveNode().parentNode.parentNode).css({background: ((value<0) ? 'red':'green')});
						this.setStyle('color: #FFFFFF');
					}
					jq(this).show("drop", {direction : "up"}, 1000);
				}
			}
			
			
			function updateWithColorAndExplosion (value, fromServer) {
				updateWithExplosion.call(this, value, fromServer, true);
			}
		]]>
	</script>

Secondly, the server side code is housed within <zscript> tags. Please be very careful as these can be confused with <script> tags.

<!-- SERVER SIDE FUNCTIONALITY! -->
	<zscript>
		<![CDATA[
			public void updateStocks() {
				Object[] values = getStockValues();
				Label stockPrice = stockGrid.getFellow(values[0]);
				Label stockDifference = stockGrid.getFellow(values[1]);

				int newValue = ((Number)values[2]).intValue();
				int difference = newValue - Integer.parseInt(stockPrice.getValue());				

				stockPrice.setValue(Long.toString(newValue));
				stockDifference.setValue(Long.toString(difference));
			}
			
			public Object[] getStockValues() {
				int randomControl = (int)Math.ceil(Math.random() * 3);
				return new Object[] {"stockPrice" + randomControl,
					"stockDifference" + randomControl,
					(int)Math.ceil((Math.random() * 10) + 95)};
			}
		]]>
	</zscript>


Then finally we have the ZUML markup describing the GUI.

<!-- ZUL MARKUP (UI IMPLEMENTATION!) -->
	<timer id="updateTimer" delay="3000" repeats="true" onTimer="updateStocks()" />
	
	<grid id="stockGrid" fixedLayout="true">
		<columns>
			<column label="Stock name" />
			<column label="Stock value" />
			<column label="Stock difference" />
		</columns>
		<rows>
			<row>
				<label id="stockName1" value="Ultra Corp: " />
				<label id="stockPrice1" value="100" w:setValue="updateWithExplosion"/>
				<label id="stockDifference1" value="0"  w:setValue="updateWithColorAndExplosion"/>
			</row>
			<row>
				<label id="stockName2" value="Amazing Corp: " />
				<label id="stockPrice2" value="100" w:setValue="updateWithExplosion"/>
				<label id="stockDifference2" value="0" w:setValue="updateWithColorAndExplosion"/>
			</row>
			<row>
				<label id="stockName3" value="Great Corp: " />
				<label id="stockPrice3" value="100" w:setValue="updateWithExplosion"/>
				<label id="stockDifference3" value="0" w:setValue="updateWithColorAndExplosion"/>
			</row>
		</rows>
	</grid>

The application's premise

The premise of the application is to highlight jQuery functionality within ZK 5 and what it can be used for. In this example we demonstrate how to override the setValue function of certain components at the client. By doing this we can add effects to the data as it changes, this data can be set by the server or the client. Within the example the data is provided by javascript at the client.

Demo

Constructing the example

To get started we need to include jQuery UI within the page, this is accomplished by ZK's script component, shown below.

<?script src="/scripts/tools.expose-1.0.3.js"?>

We are then able to use the methods provided by the jQuery UI library.

The setValue function

The setValue function is used to change the value of a Label. If we want to apply a special client side effect to the value when it changes we need to override the setValue operation at the client.

Overriding the setValue function at the client

Using a client side namespace

It is necessary when implementing client side functionality to declare a namespace. By declaring a client side namespace, these events will be resolved at the client rather than server side. Without this namespace applied to your events ZK will think that your code is Java and should be executed at the server.


Defining a namespace

Defining a namespace is easy, you only need to add the following as an attribute to any ZK tag you want to.

xmlns:w=http://www.zkoss.org/2005/zk/client

In the case of our example, this is added to the ZK tag so the namespace is available to all components.

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


Overriding the setValue function

In this example we are using Labels to display the information and hence need to override the label』s setValue function. This is achieved by declaring an attribute and setting its name to setValue along with using the declared namespace. The markup to do this is as follows, please note that the attribute is prefixed with w: which is the name of our namespace.


<label id="stockPrice1" value="100" w:setValue="updateWithExplosion"/>


Creating the overriding functions

There are two functions within the example which are used, one is named updateWithExplosion and the other is updateWithColorAndExplosion. To override setValue we have to produce a function with the following skeleton:

function NAME (value, fromServer) {

        this.$setValue(value, fromServer);
				
	if (this.desktop) {	
		jq(this).WHATEVER_EFFECT
	}
}


The two functions do differ in their structure to accommodate an extra parameter, however this does not affect the overriding mechanism. For example updateExplosion requires an extra argument to be passed, when using this method to override the setValue function the extra parameter 「updateColor」 will always be undefined.

function updateWithExplosion (value, fromServer, updateColor) {
				
	if(this.desktop) {
	
        	jq(this).effect("explode", 
				{}, 
				500);
	}
				
	this.$setValue(value, fromServer);
				
	if (this.desktop) {	
		if (updateColor) {
			jq(this.getCaveNode().parentNode.parentNode).css({background: ((value<0) ? 'red':'green')});
			this.setStyle('color: #FFFFFF');
		}
	
        	jq(this).show("drop", {direction : "up"}, 1000);
	}
}

The code above demonstrates that if the third parameter is passed and is true then the color of the cell background is changed. This is accomplished by using another function named updateWithColorAndExplosion:

function updateWithColorAndExplosion (value, fromServer) {
	updateWithExplosion.call(this, value, fromServer, true);
}


The function is interesting from the perspective that it uses the javascript call method to execute updateWithExplosion. You may also notice that when using 「call」 the first parameter is 「this.」 Within javascript the type of 「this」 depends on the scope, in this case the type of 「this」 needs to be preserved as the widget. If this call was not made then the type of 「this」 within the function updateWithExplosion would become the script object.

Updating the data

The data is updated using a timer component and server-side code to set the values of the stock. On page load the timer will start, then every three seconds it will call the function updateStocks() which will then update the stocks and send the new information to the client.

<timer id="updateTimer" delay="3000" repeats="true" onTimer="updateStocks()" />
public void updateStocks() {
	Object[] values = getStockValues();
	Label stockPrice = stockGrid.getFellow(values[0]);
	Label stockDifference = stockGrid.getFellow(values[1]);

	int newValue = ((Number)values[2]).intValue();
	int difference = newValue - Integer.parseInt(stockPrice.getValue());				

	stockPrice.setValue(Long.toString(newValue));
	stockDifference.setValue(Long.toString(difference));
}
			
public Object[] getStockValues() {
	int randomControl = (int)Math.ceil(Math.random() * 3);
	return new Object[] {"stockPrice" + randomControl,
					"stockDifference" + randomControl,
					(int)Math.ceil((Math.random() * 10) + 95)};
}

In a real application this data would be retrieved from the database and the timer can be replaced by our server push mechanism, please take a look here for more details.

Source

Download the source code here




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