Controller"

From Documentation
Line 106: Line 106:
 
For involving the life cycle, you could override <javadoc method="doBeforeCompose(org.zkoss.zk.ui.Page, org.zkoss.zk.ui.Component, org.zkoss.zk.ui.metainfo.ComponentInfo)" type="interface">org.zkoss.zk.ui.util.ComposerExt</javadoc> and/or <javadoc method="doBeforeComposeChildren(org.zkoss.zk.ui.Component)" type="interface">org.zkoss.zk.ui.util.ComposerExt</javadoc>.
 
For involving the life cycle, you could override <javadoc method="doBeforeCompose(org.zkoss.zk.ui.Page, org.zkoss.zk.ui.Component, org.zkoss.zk.ui.metainfo.ComponentInfo)" type="interface">org.zkoss.zk.ui.util.ComposerExt</javadoc> and/or <javadoc method="doBeforeComposeChildren(org.zkoss.zk.ui.Component)" type="interface">org.zkoss.zk.ui.util.ComposerExt</javadoc>.
  
== Fine-grained Control with FullComposer ==
+
== Fine-grained Full Control with FullComposer ==
  
 
In addition to controlling the give component, a composer can monitor the instantiation and exceptions for each child and descendant component. It can be done by implementing <javadoc type="interface">org.zkoss.zk.ui.util.ComposerExt</javadoc>. <javadoc>org.zkoss.zk.ui.util.GenericForwardComposer</javadoc> does not implement this interface by default. Thus, you have to implement it explicitly.
 
In addition to controlling the give component, a composer can monitor the instantiation and exceptions for each child and descendant component. It can be done by implementing <javadoc type="interface">org.zkoss.zk.ui.util.ComposerExt</javadoc>. <javadoc>org.zkoss.zk.ui.util.GenericForwardComposer</javadoc> does not implement this interface by default. Thus, you have to implement it explicitly.

Revision as of 11:15, 11 November 2010

Overview

The controller is a Java program that is used to glue UI (view) and Data (model) together.

For a simple UI, there is no need of controller. For example, the data of a Listbox could be abstracted by implementing ListModel.

For typical database access, the glue logic (i.e., control) can be handled by a generic feature called Data Binding. In other words, the read and write operations can be handled automatically by a generic Data Binding, and you don't need to write the glue logic at all.

In this section we will discuss how to implement a custom controller (aka., a composer).



Custom Controller

A custom controller is also know as a composer (in ZK). To implement a composer, you could extend from GenericForwardComposer, or implement Composer from scratch. Then, specify it in the element it wants to handle in a ZUML document.

To implement the logic to glue UI and data, a composer usually do:

  • Post-process components after ZK Loader renders a ZUML document. It can be done by overriding Composer.doAfterCompose(Component).
  • Handle events and manipulate components if necessary.

In additions, a composer can be used to involve the lifecycle of ZK Loader for doing:

  • Exception handling
  • Component Instantiation monitoring and filtering

A composer be configured as page-level or system-level, such that it will be called when ZK Loader has processed a ZUML document.

GenericForwardComposer

Implementing Composer is straightfoward: just override Composer.doAfterCompose(Component) and do whatever you want.

However, it is suggested to extend from GenericForwardComposer since the default implementation of GenericForwardComposer.doAfterCompose(Component) wires variables and event listener automatically.

For example,

package foo;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.util.GenericForwardComposer;
import org.zkoss.zul.*;

public class MyComposer extends GenericForwardComposer {
    Textbox input;
    Label output;

    void onClick$submit() {
        output.setValue(input.getValue());
    }
    void onClick$reset() {
        output.setValue("");
    }
}

where input will be wired to a fellow named input, and onClick$submit will be registered as an event listener for an event named onClick and to a fellow named submit.

To associate a composer to a component, just specify the apply attribute to the element you want to control. For example,

<grid apply="foo.MyComposer">
    <rows>
        <row>
            <textbox id="input"/>
            <button label="Submit" id="submit"/>
            <button label="Reset" id="reset"/>
        </row>
    </rows>
</grid>

If you have to post-process the components after ZK Loader initializes them, you could override GenericForwardComposer.doAfterCompose(Component). It is important to call back super.doAfterCompose(comp). Otherwise, the wiring won't work.

public void doAfterCompose(Component comp) {
   super.doAfterCompose(comp); //wire variables and event listners
   //do whatever you want (you could access wired variables here)
}

where comp is the component that the composer is applied to. In this example, it is the grid. As the name indicates, doAfterCompose is called after the grid and all its descendants are instantiated.

The apply Attribute

If you could specify multiple composers, just separate them with comma. They will be called from left to right.

In additions to the class name, you could specify an instance too. For example, suppose you have an instance called fooComposer, then

<grid apply="${fooComposer}">

If a class name is specified, each time the component is instantiated, an instance of the class is instantiated too. Thus, you don't have to worry about the concurrency issue. However, if you specify an instance, it will be used directly. Thus, you have to either create an instance for each request, or make it thread-safe.

Composer with More Control

A composer could also handle the exceptions, if any, involve the life cycle of rendering, and monitor and even control how a child component is instantiated. It can be done by implementing the corresponding interfaces.

Exception and Lifecycle Handling with ComposerExt

If you want a composer to handle the exception and/or involve the life cycle of rendering, you could also implement ComposerExt. Since GenericForwardComposer already implements this interface, you only need to override the method you care if you extends from it.

For example, we could handle the exception by overriding ComposerExt.doCatch(Throwable) and/or ComposerExt.doFinally().

For involving the life cycle, you could override ComposerExt.doBeforeCompose(Page, Component, ComponentInfo) and/or ComposerExt.doBeforeComposeChildren(Component).

Fine-grained Full Control with FullComposer

In addition to controlling the give component, a composer can monitor the instantiation and exceptions for each child and descendant component. It can be done by implementing ComposerExt. GenericForwardComposer does not implement this interface by default. Thus, you have to implement it explicitly.

There is no method need to implement in this interface. It is like a decorative interface to indicate that it requires the fine-grained full control. In other words, all methods declared in Composer and ComposerExt will be invoked one-by-one against each child and descendant component.

For example, suppose we have a composer implementing both Composer and FullComposer, and it is assigned as followed

<panel apply="foo.MyComposer">
    <div>
        <datebox/>
        <textbox/>
    </div>
</panel>

then, Composer.doAfterCompose(Component) will be called for datebox, textbox, div and then panel (in the order of child-first-parent-last). If FullComposer is not implemented, only panel will be called.

Page-level Composer

System-level Composer

Version History

Last Update : 2010/11/11

Version Date Content
     


Last Update : 2010/11/11


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