Tuesday, October 30, 2012

ZK Basic MVC Pattern with GenericForwardComposer



Introduction

Regarding GenericForwardComposer, from official document:
A skeletal composer that you can extend and write intuitive onXxx$myid event handler methods with auto event forwarding and "auto-wired" accessible variable objects such as embedded objects, components, and external resolvable variables in a ZK zuml page; this class will add forward condition to the myid source component and forward source onXxx event received by the source myid component to the target onXxx$myid event (as defined in this composer) of the supervised target component; of course it will also registers onXxx$myid events to the supervised component and wire all accessible variable objects to this composer by calling setXxx() method or set xxx field value directly per the variable name.

This post practice the MVC pattern with GenericForwardComposer in ZK.

Note: As said in the title, only very basic part in this article.

Pre-request

(must)
Please refer to http://ben-bai.blogspot.tw/2012/06/zk-quick-start.html
for setting up the environment to run ZK Web Application.

(optional)
Regarding ID conflict and component namespace, please refer to
http://ben-bai.blogspot.tw/2012/11/zk-id-conflict-and-component-idspace.html

The ZUL Page

note: we usually use an component that is an Id Space
such like window to apply GenericForwardComposer
to prevent id conflict

basic_GenericForwardComposer.zul

<zk>
    <!-- Tested with ZK 6.0.2 EE Eval -->

    <!-- A window, apply a custom GenericForwardComposer
        we usually use an component that is an Id Space
        such like window to apply GenericForwardComposer
        so we can maintain the subset of components separately
        without the need to worry if there is any conflicts
        with other subsets
        -->
    <window apply="test.basic.mvc.BasicGenericForwardComposer">
        Input your name then click button:
        <textbox id="tb" />
        <button id="btn" label="Say Hello" />
        <div height="50px" width="100px"
            style="margin: 10px; background-color: #A6C3EA;">
            <label id="lb" />
        </div>
    </window>
</zk>


The Composer

BasicGenericForwardComposer.java

package test.basic.mvc;

import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.util.GenericForwardComposer;
import org.zkoss.zul.Label;
import org.zkoss.zk.ui.event.InputEvent;
import org.zkoss.zk.ui.event.MouseEvent;
/**
 * Tested with ZK 6.0.2 EE Eval
 *
 */
public class BasicGenericForwardComposer extends GenericForwardComposer<Component> {

    private static final long serialVersionUID = -4734679090474506071L;
    private String _name;
    /**
     * Wire the Label with id "lb" in zul page into composer
     * so you can control it by composer directly
     * 
     * The field name of declared component (Label here)
     * will be mapped to the component id in zul page automatically,
     * 
     * e.g., Label lb will be mapped to <label id="lb" ... />
     */
    private Label lb;

    /**
     * Official: With its GenericForwardComposer.doAfterCompose(Component) method,
     * the ZK components declared in mark up are wired with the component instances
     * declared in the controller for our manipulation, while the events fired are
     * automatically forwarded to this controller for event handling.
     * 
     * In short, you can do some initiation task here
     */
    public void doAfterCompose (Component comp) throws Exception {
        super.doAfterCompose(comp);
        _name = "Default Name";
        lb.setValue("The message label");
    }

    /**
     * Declare an event listener, listen to the "onChange" event
     * of the textbox with id "tb" in zul page,
     * 
     * the function name is combined by
     * event name (onChange) + "$" + component id in zul page(tb)
     * 
     * Do NOT need to wire it before listen its event
     * 
     * @param event the input event fired by the textbox
     * 
     */
    public void onChange$tb (InputEvent event) {
        _name = event.getValue();
        if (_name == null || _name.isEmpty()) {
            _name = "Default Name";
        }
    }

    /**
     * Listen to onClick event of the buttn with id "btn"
     * @param event
     */
    public void onClick$btn (MouseEvent event) {
        // update label lb's value
        lb.setValue("Hello " + _name);
    }
}


The Result

initial page



after input name then click button



References

Small Talks/2008/August/ZK MVC Made Easy
http://books.zkoss.org/wiki/Small_Talks/2008/August/ZK_MVC_Made_Easy

ZK Developer's Reference/UI Composing/ID Space
http://books.zkoss.org/wiki/ZK_Developer's_Reference/UI_Composing/ID_Space

Class GenericForwardComposer<T extends Component>
http://www.zkoss.org/javadoc/latest/zk/org/zkoss/zk/ui/util/GenericForwardComposer.html

Download

Full project at github
https://github.com/benbai123/ZK_Practice/tree/master/Pattern/MVC/BasicMVC

2 comments:

  1. how can i bind data onClick event in generic forward composer like we do in viewModel using @BindingParam

    ReplyDelete
    Replies
    1. ZK MVC do not support this feature, you can try put your value in a hidden label then get value from that label in controller instead.

      Delete