3 Composer - Reference Documentation
Authors: groovyquan
Version: 0.5.1
Table of Contents
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
class WindowComposer { def afterCompose = {Component comp -> // initialize components here } }
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 aapply
attribute,so you can place the composer here
<z:window id="myWindowComposer" apply="package.WindowComposer"> … </z:window>
def afterCompose = {Component comp -> assert comp.id=="myWindowComposer" assert (comp instanceof org.zkoss.zul.Window) }
3.3 Auto-wired Component
If apply acomposer
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 fieldsThe 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()) } }
<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 composersThe parameters ofredirect
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 asViewonClick_button
abovedef afterCompose = {Component comp -> mybutton.addEventListener('onClick'){ redirect(controller: 'demo', action: 'index', id: 1) } }
<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 = { } }
<z:window id="mywin" apply="MyComposer"> <z:textbox name="firstName"/> <z:textbox name="lastName"/> <z:textbox name="fullName"/> <z:button label="submit"/> </z:window>
class MyComposer{
Button submit
def afterCompose = {Component mywin ->
submit.addEventListener('onClick'){
def person=new Person(mywin.params)
…
}
}
}
bindData
method same as in controller
also provide to Composerdef 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 createdIt provides amockComposer
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 }
<z:window id="formWindow" title="demo" apply="your.Composer"> <z:textbox name="author"/> <z:textbox name="title"/> … </z:window>
your.Composer
use renderErrorsif (!book.save()) {
formWindow.renderErrors(bean: book)
}
renderErrors
In your.Composer
if (!book.save()) { flash.book = book redirect(controller: "book", action: "edit", id: book.id) }
<g:hasErrors bean="${flash.book}"> <div class="errors"> <g:renderErrors bean="${flash.book}" as="list" /> </div> </g:hasErrors>
3.8 ZK's old 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>
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>
class TestComposer{ def username="test" def afterCompose = {Component comp ->
…
}
}
3.9 The Next Generation Data Binding System
Introduction
ZK Bind is a whole new data binding system with new specifications and implementations.For detailsEnvisage ZK 6: The Next Generation Data Binding System3.10 An Annotation Based Composer For MVC
The Story
Think of an extremely ordinary scenario, where you want to clear all the texts in a form by clicking a button.
class SomeFormComposer { Textbox usenameTb Textbox passwordTb Textbox retypepwTb // … // … Textbox memoTb def afterCompose = {Component comp -> // initialize components here } def onClick_clearBtn(Event event) { usenameTb.setValue("") passwordTb.setValue("") retypepwTb.setValue("") // … // … memoTb.setValue("") } }
class FormComposer { @Wire("textbox, intbox, decimalbox, datebox") List<InputElement> inputs @Listen("onClick = button[label='Clear']") def onClear(MouseEvent event) { for (InputElement i: inputs) i.setText("") } }
The jQuery/CSS3-like Component Selector
In the previous example, Selector is shown as a part of the parameters in AnnotationWire and
Listen.@Wire("textbox, intbox, decimalbox, datebox") @Listen("onClick = button[label='Clear']")
// Collects all the textboxes, intboxes, decimalboxes, and dateboxes as a List and wire to inputs @Wire("textbox, intbox, decimalbox, datebox") List<InputElement> inputs// Collects all the buttons whose label is "Clear", and adds EventListeners for them @Listen("onClick = button[label='Clear']") def onClear(MouseEvent event) { // … }
Syntax
The syntax of Selector is closely analogous to CSS3 selector. Component type, class, attribute, pseudo class are used to describe properties of a component. For example:// Matches any Button component "button"// Matches any Component with ID "btn" "#btn"// Matches any Button with ID "btn" "button#btn"// Matches any Button whose label is "Submit" "button[label='Submit']"
// Matches any Button who has a Window ancestor "window button"// Matches any Button whose parent is a Window "window > button"// Matches any Button whose previous sibling is a Window "window + button"// Matches any Button who has a Window as a senior sibling "window ~ button"// Matches any Button whose parent is a Div and grandparent is a Window "window > div > button"
Comparison with CSS3 Selector
Syntax | In CSS 3 Selector | In Component Selector | Comment |
---|---|---|---|
tagname | DOM element type | Component type | |
#id | DOM ID | Component ID | |
.class | CSS class | SClass / ZClass | |
attr='value' | DOM attribute | getAttr() or dynamic attribute | If getAttr() is not a method on such component, it is skipped |
:pseudo-class | Pseudo class | Pseudo class | :root, :empty, :first-child, :last-child, :only-child, :nth-child(), :nth-last-child() |
::pseudo-element | Pseudo element | N/A | |
> + ~ | Combinator | Combinator | Identical to CSS 3 combinators |
For more
Envisage ZK 6: An Annotation Based Composer For MVC3.11 Support extends GenericForwardComposer or other Composer
In Grails ZK UI 0.5,support extends GenericForwardComposer or other Composer,so can take advantage of the GenericForwardComposerIn grails-app/composersclass TestComposer extends GenericForwardComposer { TestComposer() { super('_' as char) } @Override void doAfterCompose(Component comp) { super.doAfterCompose(comp) // initialize components here }}
class TestComposer { def afterCompose = {comp -> // initialize components here } }