Composite Component

From Documentation


Composite Component


Like a macro component, a composite component is an approach to compose a component based on a template. Unlike a macro component, a composite component has to create and wire the child components by itself, and handle ID space if necessary. The advantage is that a composite component can extend from any component, such as Row, such that it is easier to fit to any situation (and no need of the inline concept).

In short, it is suggested to use a macro component if applicable (since it is easier), while using a composite component otherwise.


If you'd like to assemble UI at runtime (aka., templating), please refer to the Templating section for more information.

Implement a Composite Component

First, you have to decide which component to extend from. Div is a common choice as it is a simple component. However, here our example extends from Row, so it can be used under Rows, which the regular macros cannot.

Second, you have to implement a template (in a ZUML document) to define what child components the composite component has. Then, you have to implement a Java class to put them together.

Implement a Template

The implementation of a template is straightforward. There is nothing special to handle. Since it is rendered by Execution.createComponents(String, Component, Map), you could pass whatever data you prefer to it (thru the arg argument).

Suppose we have a template as follows, and it is placed at /WEB-INF/composite/username.zul.

<zk>
  Usename: <textbox id="mc_who"/>
</zk>

Implement a Java Class

To implement a Java class we shall:

  1. Extend from the component class you want.
  2. (Optional) Implement IdSpace to make it an ID space owner.
  3. Render the template in the constructor by use of Executions.createComponents(String, Component, Map) or others.
  4. (Optional) Wire fellows and event listeners after rendering with the use of Components.wireVariables(Component, Object, char, boolean, boolean) (wiring variables) and Components.addForwards(Component, Object, char) (wiring event listener).

For example,

package foo;

import org.zkoss.zk.ui.IdSpace;
import org.zkoss.zul.Row;
import org.zkoss.zul.Textbox;

public class Username extends Row implements IdSpace {
    private Textbox mc_who; //will be wired when Components.wireVariables is called
    public Username() {
        //1. Render the template
        Executions.createComponents("/WEB-INF/composite/username.zul", this, null);

        //2. Wire variables (optional)
        Components.wireVariables(this, this, '$', true, true);
            //ignore zscript and variable resolvers for better performance (optional)

        //3. Wire event listeners (optional)
        Components.addForwards(this, this, '$');
    }
    public String getWho() {
        return mc_who.getValue();
    }
    public void setWho(String who) {
        mc_who.setValue(who);
    }
    //public void onOK() {..} //Add event listeners if required, and wired by Components.addForwards
}

After Executions.createComponents(String, Component, Map) is called, all components specified in the template will be instantiated and become the child component of the composite component (Row). Notice that the URI must match the location of the template correctly.

Depending on the implementation you want, you could wire the data members (mc_who) by calling Components.wireVariables(Component, Object, char, boolean, boolean). This method will search all data members and setter methods and wire the component with the same ID. Similarly, Components.addForwards(Component, Object, char) is used to wire event listeners.

In this example, we specify true to the third and fourth arguments of Components.wireVariables(Component, Object, char, boolean, boolean), so that, with the aim of improving performance, it won't search variables defined in zscript and variable resolvers.

For more information, please refer to the Wire Variables and Wire Event Listeners sections.

ID Space

Unless you extends a component that is an ID space owner (such as Window), all child components specified in the template will be in the same ID space as its parent. It might be convenient at the first glance. However, it will cause the ID conflict if we have multiple instances of the same composite component. Thus, it is generally suggested to make the composite component as a space owner

It can be done easily by implementing an extra interface IdSpace. No method needs to be implemented.

public class Username extends Row implements IdSpace {
...

Of course, if you prefer not to have an additional ID space, you don't need to implement IdSpace.

Use Composite Component

Like macros and any primitive component, you have to declare it before using it. It can be done by use of the component directives. Then, we could use it the same way (they are actually primitive components). For example,

<?component name="Username" extends="row" class="foo.Username"?>

<grid>
    <rows>
      <username who="Joe"/>
      <username who="Hellen"/>
    </rows>
</grid>

Version History

Last Update : 2011/07/21


Version Date Content
     



Last Update : 2011/07/21

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