Composite Components in the MVC
This article is out of date, please refer to http://books.zkoss.org/zkessentials-book/master/ for more up to date information.
In this section, we'll see how to use ZK's Composite Component pattern to implement a product order component that consists of a label, a spinner, and a button in the Product View.
Declaring a Composite Component
A composite component is an advanced template that affords developers the ability to extend from any component. A composite component consists of a Java class which extends from a component, in this case the ProductOrder component extends from Cell as it will be placed into a grid row. The Cell will therefore contain multiple components.
ProductOrder also implements IdSpace and AfterCompose; these two interfaces enable the component to take on additional behaviours. By implementing AfterCompose, when the composite component is created it enbables developers to perform actions such as wiring of variables or registering event listeners. In the case of the ProductOrder the snippet below shows the afterCompose method:
public class ProductOrder extends Cell implements IdSpace, AfterCompose {
...
public void afterCompose() {
// 1. Render the ZUML fragment
Executions.createComponents("/WEB-INF/composite/productorder.zul",
this, new HashMap<String, Object>() {
private static final long serialVersionUID = 7141348964577773718L;
{
put("maximumQuantity", getMaximumQuantity());
}
});
// 2. Wire variables, components and event listeners (optional)
Selectors.wireVariables(this, this, null);
Selectors.wireComponents(this, this, false);
Selectors.wireEventListeners(this, this);
}
...
}
Rendering the Composite Component
The snippet above shows two things happening, firstly the composite component renders a ZUML fragment which will be contained within itself. Taking a look at the Executions.createComponents function call on line 7, the first parameter is the location of the ZUML fragment, the second parameter is the component which will become the root, in this case itself. The third component is a HashMap containing the parameters to send to the fragment, in this case the maximumQuantity, which is just a simple bean.
The fragment is shown below:
<zk>
<spinner id="spnQuantity" constraint="min 1 max ${arg.maximumQuantity}" value="1"/>
<button id="btnAdd" label="add" image="/image/ShoppingCart-16x16.png" />
<label id="lblError" />
</zk>
In the above fragment one can see how the maximum quantity, which was passed to the fragment on creation, is accessed and used using EL expressions.
Wiring Variables and Event Listeners
Finally, within the composite component, variables, components and event listeners need to be wired. This is easy to do using the following method calls in the afterCompose function.
Selectors.wireVariables(this, this, null);
Selectors.wireComponents(this, this, false);
Selectors.wireEventListeners(this, this);
<source>
===Using the Composite Component===
Having built the component it now needs to be registered with ZK, this is easily done by putting a directive at the top of the ZUL file you want to use it in. In the case of this application it is present in index.zul.
<source lang="xml">
<?component name="productOrder" class="demo.web.ui.ctrl.ProductOrder" ?>
The directive specifies a name for the component which can be referenced in the ZUL file and the appropriate class which drives the functionality. The component can now be used as follows:
<grid id="prodGrid">
<columns sizable="true">
...
</columns>
<template name="model">
<row value="${each}">
<image height="70px" width="70px"
src="${each.imgPath}" />
<label value="${each.name}" />
<label value="${each.price}" />
<label value="${each.quantity}" />
<label value="${each.createDate}" />
<productOrder maximumQuantity="${each.quantity}" product="${each}" />
</row>
</template>
</grid>
For more information on the composite component please consult the Developer's reference
This concludes this section of the document, the data is displayed correctly. The adding of products is discussed in the last chapter as it deals with communication between MVC and MVVM thus is a topic best introduced after MVVM. If you are interested you can take a look now.