The Story

Before ZK 6.0, the custom renderer must be implemented through Java. Although Java is very powerful and anything can be achieved with it, it is still tedious and not always the most feasible solution having to create and maintain an additional Java class every single time. Speaking in terms of the MVC concept, in many cases, it makes much more sense to place ZUL as it is closer to "View" rather than the "Control" in the Java code.

With ZK 6.0, a new concept called "template" is introduced. It allow UI designers to specify templates right in a ZUML page, the model can then be rendered based on the template without any Java code.

What Is a Template

A template is a segment of a ZUML page enclosed with the template element as shown below.

The template can contain any ZUML elements users desire, including other templates. When ZK interprets a template, it does not interpret its content immediately, rather, it first stores it as an instance of org.zkoss.zk.ui.util.Template into the component, such that it can be retrieved later to create components by the application or the component to create its child component(s).

Listbox Model Rendering with Template

With 6.0, the custom renderer can be done with a template without any Java code. For example, when wanting to render a two-dimensional array, the follow can be done to achieve the desired outcome

As illustrated above, custom rendering is defined by a template called model. The template's name is important because users are allowed to associate multiple templates to one component. Furthermore, when the template is rendered, a variable called each is assigned with the data being rendered.

Additionally, if value="${each}" is not specified to the listitem (Listitem.setValue(Object)) in the template, the renderer will automatically assign the data being rendered to the listitem in order for users to conveniently retrieve back the data when necessary.

↑ There are several ways to assign a model to a UI component. Please refer to ZK Developer's Reference for detailed information.

Nested Listboxes

The template can be applied recursively. Here is an example of a listbox-in-listbox:

To access the data of the outer template from the inner template, use the parent listitem's Listitem.getValue() where the data is stored by default. Please look at line 8 of the following example, data can be retrieved from the outer model by travelling the component tree

where books is assumed as an instance of ListModel that contains a list of the Book instances while each Book instances has at least three getter methods: getIsbn, getName and getDescription.

Notice that the template named model must be associated with the grid, i.e., it must be a direct child element of the grid element as shown above. A common mistake is to put it under the rows element. Remember the template is a ZUML fragment telling the grid how to render a row, and the template itself is not a component.

Tree Model Rendering with Template

Similarly, users can also define a customer rendering with a template for a tree:

Using Template in Application

"Template" is a generic feature and its use is not limited to custom model rendering. Users are able to use "template" in ZK applications too.

Each template is stored as part of a component and can be retrieved it by invoking the getTemplate method. To create the component tree defined in the template, just invoke the Template.create(Component parent, Component insertBefore, VariableResolver resolver) method. For example,

comp.getTemplate("foo").create(comp, null, null, null);

The third argument of the create method is a variable resolver (VariableResolver). Depending on the requirement, you could pass any implementation you like. For example, the implementation of a listbox actually utilizes it to return the data being rendered; the code is similar to the following (for easy understanding, the code has been simplified).

For more detailed information about the variable resolver, please refer to ZUML Reference.