Table of Contents

1. Introduction
1.1 Taglib
1.2 Composer
1.3 Builder
1.4 Selector
2. Getting Started
2.1 Hello World
2.2 Say Hello in Ajax way
2.3 Identify a component
2.4 A component is a POJO
2.5 Separating code from user interface
3. Composer
3.1 Creating a composer
3.2 Apply a composer
3.3 Auto-wired Component
3.4 Redirects
3.5 Data Binding
3.6 Unit Test
3.7 Render Errors
3.8 ZK's Data Binding
4. Builder
4.1 appendChild
4.2 leftShift
4.3 Event listening
4.4 Client-side event listening
5. Selector
5.1 Selector overview
5.2 Base Selector
5.3 Selector combinations
5.4 Pseudo selectors
6. Event Handling
6.1 Event Listening
6.2 Client-side Event Listening
7. Scaffolding Templates
7.1 Static Scaffolding
7.2 Customizing the scaffolding templates
8. Integration
8.1 ZK EE
8.2 ZK Themes
8.3 ZK Extensions Component

1. Introduction

ZK UI plugin,the same as the ZKGrails plugin, seamlessly integrates ZK with Grails' infrastructures.

The difference is it uses the Grails' infrastructures more, such as gsp, controllers rather than zk's zul.

ZK UI Grails plug-ins brings powerful features as follows

1.1 Taglib

Use Tag Libraries
<z:window title="My First ZK UI Application" border="normal">
    Hello World!
</z:window>

1.2 Composer

Provides a Composer Artefacts simplify the integration between grails and zk

Usage:

grails create-composer [name]

1.3 Builder

A groovy way to create zk components, following groovy Builder paradigm

Controller

def index = {
    def window = new Window(title: "listbox demo", border: "normal")
    window << {
        listbox {
            listhead(sizable: true) {
                listheader(label: "name", sort: "auto")
                listheader(label: "gender", sort: "auto")
            }
            listitem {
                listcell(label: "Mary")
                listcell(label: "FEMALE")
            }
            listitem {
                listcell(label: "John")
                listcell(label: "MALE")
            }
            listitem {
                listcell(label: "Jane")
                listcell(label: "FEMALE")
            }
            listitem {
                listcell(label: "Henry")
                listcell(label: "MALE")
            }
            listfoot {
                listfooter {
                    label(value: "This is footer1")
                }
                listfooter {
                    label(value: "This is footer2")
                }
            }
        }
    }
    [window:window]
}

View

<z:render comp="${window}"/>

1.4 Selector

Provides a very convenient API for extracting and manipulating zk component, using the jquery-like methods.

View

<z:window id="window">
    <z:textbox name="t1" value="value1"/>
    <z:textbox id="t2" value="value2"/>
    <z:textbox value="value3"/>
</z:window>

Selector code

assert 3 == window.select("textbox").size()
assert "value2" == window.select("#t2")[0].value
assert "value1" == window.select("textbox[name=t1]")[0].value

2. Getting Started

2.1 Hello World

DOCTYPE

The html pages generated by gsp must generate the doc type as follows.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

Importing resources

Add the tag <z:resources/> to the head of the layout/main.gsp or any page that you want to use ZK UI Grails plug-ins.
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
  <z:resources/>

Hello World!

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Hello World Demo</title>
    <z:resources/>
</head>

<body> <z:window title="My First ZK UI Application" border="normal"> Hello World! </z:window> </body> </html>

2.2 Say Hello in Ajax way

Let us put some interactivity into it.
<z:button label="Say Hello" onClick="Messagebox.show('Hello World! Time now is:'+new Date())"/>
Then, when you click the button, you'll see the following:

The onClick attribute is a special attribute used to add an event listener to the component such that it is invoked when an end user clicks the component. The attribute value could be any legal groovy code.

Here we invoke Messagebox.show(String) to show a message box as depicted above.

Notice that it is not JavaScript,It is Groovy and runs at the server

2.3 Identify a component

A component is a POJO, so you can reference it any way you like. However, ZK provides a convenient way to identify and to retrieve a component: identifier. For example, we named the textbox as input by assigning id to it, as follows.

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

2.4 A component is a POJO

A component is a POJO. You could instantiate and manipulate directly. For example, we could generate the result by instantiating a component to represent it, and then append it to another component (an instance of vlayout).

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

Similarly you could change the state of a component directly. All modifications will be synchronized back to the client automatically.

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

2.5 Separating code from user interface

Embedding Groovy code in a gsp 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 Groovy code runs much faster than the embedded code which is interpreted at the run time.

To separate code from UI, we could implement a Composer

use create-composer command

grails create-composer zkuidemo.PropertyRetriever

A composer called PropertyRetrieverComposer will be created in the grails-app/composers directory

Modify the generated PropertyRetrieverComposer as follows

package zkuidemo

import org.zkoss.zk.ui.Component import org.zkoss.zk.ui.event.Event import org.zkoss.zul.Label

class PropertyRetrieverComposer {

def afterCompose = {Component target -> target.addEventListener("onClick", new org.zkoss.zk.ui.event.EventListener() { //add a event listener in Groovy public void onEvent(Event event) { String prop = System.getProperty(target.getFellow("input").getValue()) target.getFellow("result").appendChild(new Label(prop)) } }); } }

The above code can be simplified as follows

package zkuidemo

import org.zkoss.zk.ui.Component import org.zkoss.zk.ui.event.Event import org.zkoss.zul.Label

class PropertyRetrieverComposer {

def afterCompose = {Component target -> target.addEventListener("onClick") {Event event -> String prop = System.getProperty(target.getFellow("input").value) target.getFellow("result").appendChild(new Label(prop)) } } }

Then, we could associate the Composer (zkuidemo.PropertyRetrieverComposer) with a component by use of the apply attribute as shown below.

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

3. Composer

A composer is responsible to initialize a component (or a component of tree) when ZK loader is composing a component. It is the controller in the MVC pattern, while the component is the view,which separate the code from the user interfaces.

3.1 Creating a composer

Composers can be created with the create-composer target. For example try running the following command from the root of a Grails project:
grails create-composer window

The command will result in the creation of a composer at the location grails-app/composers/WindowComposer.groovy:

class WindowComposer {
    def afterCompose = {Component comp ->
        // initialize components here
    }
}
WindowComposer by default provide a afterCompose closure to initialize components.

The create-composer command is merely for convenience and you can just as easily create composers using your favorite text editor or IDE

3.2 Apply a composer

Each component Taglib has a apply attribute,so you can place the composer here
<z:window id="myWindowComposer" apply="package.WindowComposer"></z:window>

In the WindowComposer side

def afterCompose = {Component comp ->
    assert comp.id=="myWindowComposer"
    assert (comp instanceof org.zkoss.zul.Window)
}

3.3 Auto-wired Component

If apply a composer to a Component that implement a IdSpace Interface,such as org.zkoss.zul.Window. The Component's children can be auto-wired to composer's fields

The following is an example. The onChange event received by Textbox mytextbox will be forwarded to target Window mywin as a new target event onChange_mytextbox and the Textbox component with id name "mytextbox" and Label with id name mylabel are injected into the "mytextbox" and "mylabel" fields respectively(so you can use mytextbox and mylabel variable directly in onChange_mytextbox without problem).

Composer

class MyComposer{
    Textbox mytextbox
    Window self //embeded object, the supervised window "mywin"
    Page page //the ZK page
    Label mylabel

def afterCompose = {Component comp -> assert mytextbox.id=="mytextbox" assert mylabel.id=="mylabel" }

def onChange_mytextbox(Event event) { mylabel.setValue("You just entered: "+ mytextbox.getValue()) } }

View

<z:window id="mywin" apply="MyComposer">
    <z:textbox id="mytextbox"/>
    <z:label id="mylabel"/>
</z:window>

3.4 Redirects

Actions can be redirected using the redirect method present in all composers

The parameters of redirect is same as controller's redirect

Composer

class MyComposer{
    Button mybutton

def afterCompose = {Component comp ->

}

def onClick_mybutton(Event event) { redirect(controller: 'demo', action: 'index', id: 1) } }

following code same as onClick_button above

def afterCompose = {Component comp ->
    mybutton.addEventListener('onClick'){
        redirect(controller: 'demo', action: 'index', id: 1)
    }
}

View

<z:window id="mywin" apply="MyComposer">
    <z:button label="mybutton"/>
</z:window>

3.5 Data Binding

To uses Grails' underlying data binding capability,zkui injection a getParams method to Component.

Domain Class

class Person {
    String firstName
    String lastName
    String fullName
    static constraints = {
    }
}

View

<z:window id="mywin" apply="MyComposer">
    <z:textbox name="firstName"/>
    <z:textbox name="lastName"/>
    <z:textbox name="fullName"/>
    <z:button label="submit"/>
</z:window>

Composer

class MyComposer{
    Button submit
    def afterCompose = {Component mywin ->
        submit.addEventListener('onClick'){
            def person=new Person(mywin.params)
            …
        }
    }
}

A bindData method same as in controller also provide to Composer

def p = new Person()
bindData(p, mywin.params)

3.6 Unit Test

When use grails create-composer create a composer,a unit class that is a sub-class of ComposerUnitTestCase also created

It provides a mockComposer methods for mocking zkui's Selector,Builder and so on.

mockComposer(MyComposer)
def myComposer=new MyComposer
...

3.7 Render Errors

zkui injection a renderErrors method to Component.

If you have Domain class

class Book{
    String author
    String title
}

In View

<z:window id="formWindow" title="demo" apply="your.Composer">
    <z:textbox name="author"/>
    <z:textbox name="title"/></z:window>

Then in your.Composer use renderErrors

if (!book.save()) {
            formWindow.renderErrors(bean: book)
 }

In addition,you can also use grails's traditional renderErrors

In your.Composer

if (!book.save()) {
    flash.book = book
    redirect(controller: "book", action: "edit", id: book.id)
 }

In your view

<g:hasErrors bean="${flash.book}">
<div class="errors">
    <g:renderErrors bean="${flash.book}" as="list" />
</div>
</g:hasErrors>

3.8 ZK's Data Binding

Data binding is a mechanism that automates the data-copy plumbing code (CRUD) between UI components and the data source. Application developers only have to tell the data binding manager about the associations between UI components and the data source. Then, the data -binding manager will do all the loading (loading data from the data source to UI components) and saving (saving data from UI component into the data source) jobs automatically.

Activates Data Binding Manager

<z:window  apply="org.zkoss.demo.MyComposer,org.zkoss.zkplus.databind.AnnotateDataBindingComposer">
</z:window>

For more information, please refer to the relative blog post Databinding Composer

Associate UI Components with Data Source

After activating the data-binding manager, you have to define the required UI objects and then associate them with the data source.

In the gsp view:

<z:window id="win" apply="test.TestComposer,org.zkoss.zkplus.databind.AnnotateDataBindingComposer">
    <z:textbox value="@{win#composer.username}"/>
<z:/window>

In the test.TestComposer:

class TestComposer{

def username="test"

def afterCompose = {Component comp -> … } }

See more ZK Developer's Reference/Data Binding

4. Builder

Builders are internal DSLs that provide ease in working with certain types of problems.It is very useful for work with nested,hierarchical structures, such as tree structures, XML representations,or HTML representations.

Let’s take a look at an example of one way to create zk component in Groovy—using a builder:

4.1 appendChild

appendChild is dynamic method that ZKUI injection to zk Component to begin builder,which accepts a Closure parameter.
def window = new Window(title: "listbox demo", border: "normal")
window.appendChild {
    listbox {
        listhead(sizable: true) {
            listheader(label: "name", sort: "auto")
            listheader(label: "gender", sort: "auto")
        }
        listitem {
            listcell(label: "Mary")
            listcell(label: "FEMALE")
        }
        listitem {
            listcell(label: "John")
            listcell(label: "MALE")
        }
        listitem {
            listcell(label: "Jane")
            listcell(label: "FEMALE")
        }
        listitem {
            listcell(label: "Henry")
            listcell(label: "MALE")
        }
        listfoot {
            listfooter {
                label(value: "This is footer1")
            }
            listfooter {
                label(value: "This is footer2")
            }
        }
    }
}

4.2 leftShift

ZKUI also provides a convenient method leftShift( << ),so you can modify the above code like:
def window = new Window(title: "listbox demo", border: "normal")
window << {
    listbox {
       …
    }
}

4.3 Event listening

If the parameter on onEvent it's a Closure, then it's a server side event
window << {
    button(label: 'button', onClick: {
        Messagebox.show("hello word! from Server")
    })
}

4.4 Client-side event listening

If the parameter on onEvent it's a String, that is a client side event
window << {
    button(label: 'buutton', onClick: "alert('Say hello word! from JS')")
}

Add a prefix client_ is useful when you also use server side event that avoid naming conflicts

window << {
    button(label: 'buutton', client_onClick: "alert('Say hello word! from JS')",onClick:{
        Messagebox.show("hello word! from Server")
    })
}

5. Selector

5.1 Selector overview

ZK UI Plugin support a CSS (or jquery) like selector syntax to find matching components, that allows very powerful and robust queries.

It's inspired by the jsoup

The select method is injected to Component,which returns a list of Component.

View code

<z:window id="window" apply="MyComposer">
    <z:textbox name="t1" value="value1"/>
    <z:textbox id="t2" value="value2"/>
    <z:textbox value="value3"/>
</z:window>

Composer code

class MyComposer{

def afterCompose = {Component window -> assert 3 == window.select("textbox").size() // select method returns List<Component> assert "value2" == window.select("#t2")[0].value assert "value1" == window.select("textbox[name=t1]")[0].value }

}

5.2 Base Selector

5.3 Selector combinations

5.4 Pseudo selectors

6. Event Handling

6.1 Event Listening

Declare an Event Handler in gsp

An event handler can be declared in a gsp page by specifying an event attribute(An event attribute is an attribute starting with on). For example,

<z:button label="hi" onClick='alert("Hello")'/>
where the content of the event handler is the code snippet in Groovy. The event handler will be interpreted at the run time.

Important Builtin Variables

Listen by Use of an Event Listener

An event listener is a class implementing EventListener. For example,

class MyListener implements EventListener {
    void onEvent(Event event) {
        Messages.show("Hello")
    }
}

Then, you can register an event listener to the component that might receive the event by use of Component.addEventListener(String, EventListener). For example,

button.addEventListener("onClick", new MyListener())

This is a typical approach to handle events. However, it is a bit tedious to register event listeners one-by-one if there are a lot of listeners. Rather, it is suggested to use the following method:

button.addEventListener("onClick"){Event event->
    Messages.show("Hello")
}

Composer and Event Listener Autowiring

With Auto-wired Component, you generally don't need to register event listeners manually. Rather, they could be registered automatically by use of the auto-wiring feature of a composer. For example

class MyComposer{
    void onClick_hi() {
        Messsagebox.show("Hello")
    }
    void onClick_bye() {
        Messsagebox.show("Bye")
    }
}

As shown above, the method to listen an event shall be named by starting with the event name, separating with _, and ending with the component's ID. The composer will search all matched methods and register the event listener automatically. Then, in the gsp page, you can specify the apply attribute to associate the composer with a component.

<z:window apply="MyComposer">
    <z:textbox/>
    <z:button id="hi"/>
    <z:button id="bye"/>
</z:window>

If the listener needs to access the event, just declare it as the argument:

void onClick_hi(MouseEvent event) {
  Messsagebox.show("Hello, " + event.getName())
}
Though not limited, a composer is usually associated with an ID space (such as Window) to handle events and component within the give ID space. You could associate any component that properly represents a scope of your application to manage. See more Auto-wired Component

Declare a Event Handler in zkui's Builder

see Event listening

6.2 Client-side Event Listening

ZK allows applications to handle events at both the server and client side. Handling events at the server side, as described in the previous sections, are more common, since the listeners can access the backend services directly. However, handling event at the client side improves the responsiveness. For example, it is better to be done with a client-side listener if you want to open the drop-down list when a comobox gains focus. A good rule of thumb is to use server-side listeners first since it is easier, and then improve the responsiveness of the critical part, if any, with the client-side listener.

Declare a Client-side Listener in gsp

Declaring a client-side listener in a gsp is similar to declaring a server-side listener, except

For example,

<z:combobox client_onFocus="this.open()"/>

The Relationship between Client and Server-side Event Listener

It is allowed to register both the client and server-side event listeners. They will be both invoked. Of course, the client-side listener is called first, and then the server-side listener. For example,
<z:div>
  <z:combobox client_onFocus="this.open()" onFocus="self.parent.appendChild(new Label('focus'))"/>
</z:div>
If you want to stop the event propagation such that the server won't receive the event, you could invoke Event.stop(Map). For example, the server-side listener won't be invoked in the following example:
<z:div>
  <z:combobox client_onFocus="this.open(); event.stop();" onFocus="self.parent.appendChild(new Label('focus'))"/>
</z:div>

Declare a Client-side Listener in Groovy

The other way to declare a client-side listener at the server is Component.setWidgetListener(String, String). For example,
combobox.setWidgetListener("onFocus", "this.open()")
Notice that it is Groovy and running at the server.

Register a Client-side Listener in Client-Side JavaScript

Listening an event at the client could be done by calling Widget.listen(Map, int). For example,
<z:window>
    <z:bandbox id="bb"/>
    <z:script defer="true">
        this.$f().bb.listen({onFocus: function () {this.open();}});
    </z:script>
</z:window>
where

Declare a Client-side Listener in zkui's Builder

see Client-side event listening

7. Scaffolding Templates

Zkui supports a feature known as scaffolding which involves the generation of a CRUD (Create/Read/Update/Delete) interface for a given domain class

7.1 Static Scaffolding

Same as Grails's generate-all command,zkui use zkui-generate-all to generates views,composer and a controller for the given domain class

To zkui's scaffolding work,you need modify the default layout/main.gsp
  1. Add the tag <z:resources/> to the head
  2. Remove <link rel="stylesheet" href="${resource(dir:'css',file:'main.css')}" />
  3. Generate the doc type as follows

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

The complete layout/main.gsp Examples

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title><g:layoutTitle default="Grails"/></title>
    <z:resources/>
    <g:layoutHead/>
</head>
<body>
<div id="grailsLogo"><a href="http://grails.org"><img src="${resource(dir: 'images', file: 'grails_logo.png')}"
                                                      alt="Grails" border="0"/></a></div>
<g:layoutBody/>
</body>
</html>

7.2 Customizing the scaffolding templates

The templates used by zkui to generate the controller, views and composer can be customized by installing the templates with the zkui-install-templates command.

8. Integration

8.1 ZK EE

ZK UI supports ZK Enterprise features.

Just put the zk ee jar to libs or put jar dependencies in grails-app/conf/BuildConfig.groovy

You can also install the Enterprise edition by

$ grails install-plugin zk-ee

This plugin contains addition jars required for enabling ZK Enterprise features.

8.2 ZK Themes

How to use

You can simply put theme jar in lib directory.

Or add dependencies in grails-app/conf/BuildConfig.groovy

First, add zkoss' maven Dependency Repositories

repositories {
        …
        mavenRepo "http://mavensync.zkoss.org/maven2/"
        …
}

Second,specify dependencies

dependencies {
        // there are three theme 'breeze', 'sapphire', 'silvertail'
        def zkThemeVersion="5.0.9"
        def zkTheme="breeze"
        runtime "org.zkoss.theme:${zkTheme}:${zkThemeVersion}"
    }

How to switch different themes dynamically

The default theme provider checks the current theme settings in order of preferences;

First priority: Cookie

Set cookie zktheme=name

For instance, write cookie zktheme=breeze, breeze theme will be activated

Second priority: Library property

The default theme provider will obtain the current theme setting from library property if cookie is empty.
<library-property>
     <name>org.zkoss.theme.preferred</name>
     <value>name</value>
</library-property>
For example, the following code will activiate the breeze theme.
<library-property>
     <name>org.zkoss.theme.preferred</name>
     <value>breeze</value>
</library-property>

Third priority: System's default them

The default theme provider maintains a default theme. If theme provider can't find theme setting in cookie or library property, default theme will be activated.

Dynamically switch themes using cookie

Here are a list of cookie sample codes that you can choose from.

Breeze

Themes.setTheme(Executions.getCurrent(), "breeze")
Executions.sendRedirect(null)

Sapphire

Themes.setTheme(Executions.getCurrent(), "sapphire")
Executions.sendRedirect(null)

Silvertail

Themes.setTheme(Executions.getCurrent(), "silvertail")
Executions.sendRedirect(null)

Classic blue

Themes.setTheme(Executions.getCurrent(), "classicblue")
Executions.sendRedirect(null)

Dynamically switch themes using library property

Breeze

Library.setProperty("org.zkoss.theme.preferred", "breeze")
Executions.sendRedirect(null)

Sapphire

Library.setProperty("org.zkoss.theme.preferred", "sapphire")
Executions.sendRedirect(null)

Silvertail

Library.setProperty("org.zkoss.theme.preferred", "silvertail")
Executions.sendRedirect(null)

Classic blue

Library.setProperty("org.zkoss.theme.preferred", "classicblue")
Executions.sendRedirect(null)

Retrieve web app supported theme names

String names = Library.getProperty("org.zkoss.theme.names");

Reference

ZK Themes GetStarted

8.3 ZK Extensions Component

You can extends the org.grails.plugins.zkui.AbstractTagLib implement the Extensions Component's Taglib same as:

import org.grails.plugins.zkui.AbstractTagLib

class CalendarsTagLib extends AbstractTagLib { static namespace = "z"

def calendars = { attrs, body -> doTag(attrs, body, "calendars") }

}

and put the Calendar jar to lib