How to Wrap a jQuery UI Widget

From Documentation
DocumentationSmall Talks2010DecemberHow to Wrap a jQuery UI Widget
How to Wrap a jQuery UI Widget

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


Introduction

ZK5 has adapted the famous jQuery as underlying javascript library. jQuery UI is also looking very promising. In this article, we'll see how jQuery UI's widgets can be easily wrapped to zk widget now, and enjoy the power of ZK.

Demo

<datepicker id="target" numberOfMonths="2,2"/>
<button label="setNumberOfMonths(1)" onClick="target.setNumberOfMonths(1)"/>


In above example, we declare datepicker in zul, and then modify its property in Java.

Benefit

Any pure client widget can now easily connect to server. ZK provides many server side ability. Such as DataModel, Databindng, Event Handling.

You can use jQuery UI widget in more simplified syntax in zul, expression language is available too. In extreme cases, you can even use only Java without any markup language or JavaScript, just like ZK always do. You can also modify widget option at run time with Java.

And the best of all, you can modify the content of underlying data model with Java. Then the widget content will be updated accordingly.

Through databinding, your interaction with client UI widget can automatically sync with java bean in server.[1]

  1. under construction.

How to wrap

Since it is only a wrapping, it's far more easy than implementing a whole new actual ZK component.

setup files

  • lang-addon.xml : Define component-name,component-class,widget-class, and load needed CSS file
  • zk.wpd : Define widget package and load needed javascript file.
  • zk.xml : Settings to make debug Javascript possible. Includes debug-js, org.zkoss.web.classWebResource.cache

Please download source code at jQuery4j. It's concrete to work.

JavaScript part

In most common cases, you have to implement 4 methods:

$define

It's the catcher to set initial options from renderProperties() in server. Also It's the catcher of setter function from server to modify widget option after it is initialized.

redraw

Provide html content as jQuery UI expected. The rest job will be delegated to jQuery UI in bind_.

bind_

Client event handler may send Event back to server.[1]. Get options sended from renderProperties() in java. And call jQuery UI api to init it.[2]

  1. May search "fire" in *.js
  2. If an field of option is undefined, jQuery UI will use its default value

unbind_

Release jQuery UI widget, and zk widget.

Java part

Jobs includes updating data to client, and handle client event.

getter, setter of fields

smartUpdate() inside setter function will effect at client side #define. Setter function may do some check to see if the input value is acceptable. Some datatype conversion may need extra work. For example "2,2" inside <datepicker numberOfMonths="2,2"/> is String, and need to be converted int[].

renderProperties

It's used to initialize widget properties. Properties rendered will be catched by $define in client side, value would be available at client side redraw, bind_

Event Handling

You may use ZK defined event, or define your own event. To make your own event work, you have to do following things:

In Server side

  • addClientEvent(): Adds an event that the client might send to the server
  • service(): Processes an AU request. Event reported from client is handled here first. Update field in server side, postEvent() for further event handling.
  • Register event handler at controller for test: Event without event handler may be not send to save network bandwidth.

In Client side

  • call fire("eventname",DataObject):It will send event to notify server[1]
  1. eventName please follow onXXX naming convention.

Code example

Because the field related code is much the same, you may define some template for different data type. It's more easy to code and less error.

For example, related code for a boolean option field disabled

In Java:

	private boolean _disabled = false;
	
	public boolean getDisabled() {
		return _disabled;
	}
	
	public void setDisabled(boolean disabled) {
		if(_disabled != disabled){
			_disabled = disabled;
			smartUpdate("disabled", _disabled);					
		}
	}
	
	//inside renderProperties
	if(_disabled)
		render(renderer, "disabled", _disabled);
		(*if false, try renderer.render("disabled", _disabled))

In javascript

		
	//inside $define
	disabled :  function(){
		$(this.$n('cnt')).datepicker('option','disabled',this._disabled);
	},
	
	//options for init inside bind_
	,disabled: this._disabled

Execution sequence for both server and client

For example <datepicker disabled="true"/> sets the option disabled in zul, the execution sequence would be like:

  1. setDisabled:Modify _disabled variable in server.
  2. renderProperties: Render the _disabled property to client side
  3. $define:catch renderProperties(), and set client side variables of widget _disabled
  4. redraw:_disabled is available now. [1]
  5. bind_:Use client side variable _disabled to initialize jQuery UI widget.
  1. If it's _model, can be used to change html output here. Please refer to source code of accordion, search "model")

Test

To test ZK component functionality , you may test several use case:


<datepicker id="target" numberOfMonths="2,2"/>

Above example can test if rendering is OK, and if String conversion to field is OK.

<button label="setNumberOfMonths(1)" onClick="target.setNumberOfMonths(1)"/>

Above example can test if the setter function works fine.[1]

	
Datepicker target;	
public void onSelection$target(Event e) {
	System.out.println("Datepicker selection happen : "+ e);
}

Above example can tell if event is send accordingly.

  1. If the jQuery UI option not work as we think, you may test it in pure html first

Demo Model Usage

<zscript>
<![CDATA[
	import org.zkoss.jquery4j.jqueryui.accordion.AccordionModel;    
	String[][] model = {{"t1","c1"},{"t2","c2"}};
	String[][] model2 = {{"tc1","cc1"},{"tc2","cc2"},{"tc3","cc3"}};
	AccordionModel tm = new AccordionModel(model);
	AccordionModel tm2 = new AccordionModel(model2);
	]]>
</zscript>

<accordion id="target" model="${tm}"/>
<button label="setModel(date)">
	<attribute name="onClick"><![CDATA[		
		target.setModel(tm2);
		]]>
	</attribute>    
</button>

In above example, you can see the content of accordion is changed as we set different model to it.

Differences between wrapped widget and ZK widget

  • Childable: Currently wrapped jQuery UI widget must be leaf node of component tree. We're trying to found a way to implement such childable feature.
  • styling: Since the HTML structure of widget is managed by jQuery UI, its styling does not follow ZK's rule. You can use jQuery UI Themeroller to customize

Summary

Although jQuery UI has only 8 widgets now, but it has planned to provide more in roadmap. In jQuery4j, we already wrapped all 8 widgets.

There is still jobs to perfect this project. Including databinding, and childable component.

It's fun to have many other little widgets to enrich ZK. It's easier to wrap jQuery UI widget than jQuery widget than javascript widget. Since the former followes more coding discipline, less "surprise" to overcome. Sometimes, widget from different source may conflict. For example, a fancy calculator jQuery Widget conflict with jQuery UI library, because jQuery UI library rewrites some jQuery function show().

It also provides another way to implement your own ZK component. You may implement jQuery UI widget first, and then wrap it to ZK component.

See Also

Download

jQuery4j : Link /src,/src/archive as java src folder in Eclipse


Comments



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