Beautifying the Page
You can modify the appearance of ZUL components using Cascading Style Sheets (CSS), in a way similar to HTML documents. For instance, you can make the font of the message thicker with:
<label id="messageBoard" value="${helloMsg}" style="font-weight: bold"/>
However, directly defining the style for each control is not the best practice. As with HTML, you can define sets of styles for ZUL documents that can be used by passing identifiers (see Listing Five, also online).
Multiple Document Interface
Displaying child windows is an important technique for constructing complicated UIs in rich client applications. For example, the process allows the separation of some controls into wizards, which help to fill out a form. Unfortunately, such techniques are unavailable in classic web applications. ZK supports the concept by allowing for one page to consist of many nested windows, which also can be modal. Each of these windows is placed in a separated CSS layer and, with help of a mouse, users can move, resize, or close them. For each window, a server creates its own event-handling thread. To use this technique in ZUL, you apply the <window> tag declared with parameter mode set to overlapped or modal; see Listing Six (online).
Visualizing Tabular Data
Creating tables in ZK is simplified using the forEach attribute, which can be applied to any ZUL component. It accepts values of type java.util.Collection or arrays. Using this attribute causes a tag that is owner of the attribute to be displayed multiple times. Listing Seven (available online) is an example of this technique.
Listing Seven includes a script that prepares data for tables (the default scripting language in ZK is BeanShell, which mimics Java; you can also use Groovy or Ruby). It is executed each time ZK loads the page. Then, Listing Seven defines a table and its headers (tags <grid> and <columns>) followed by a definition of table rows. Every control that has a <row> tag as its parent is interpreted as a definition of one table cell. The forEach attribute causes multiplication of the row definition for every element of array tabularData. The variable each takes subsequent values from the array backing the loop. This variable is defined in zscript, but it also accessible from EL expressions.
Tables With Dynamic Content
Now assume that you want to display a list of objects with mutable content; for instance, a list controlled by user-defined filtering. In Swing applications, you define a model and a view. Then you modify only the model, which automatically notifies the view about its changes, allowing the view to update displayed data. This is a benefit of the MVC pattern, implemented by JTable. In ZK, you proceed in a similar way, and a table is updated without reloading the whole pageonly the necessary fragment of HTML code is changed (see Listing Eight, available online).
Tables With Nested Controls
You often need to add more interactivity to the UI table cells than just plain labels provide. For example, you might want to edit data directly in a table, or add special columns with edit or delete buttons. If you assume that a table will have invariable data, you can embed controls as in Listing Nine (available online).
Figure 3 shows the result of running this page. In this example, you can see some other techniques that are characteristic of the ZK environment. Similar to JSP, some default objects are available on ZUL pages. In the example, I used:
- session, modeled on javax.servlet.http.HttpSession.
- page, representing the object of the current page.
- self, which points to the component where an event happened.
Another defined variable inside the forEach loop is forEachStatus.index, which counts loop iterations. ZUL also offers the ability to define values of any component attribute in a special tag named <attribute>. In the example, I used it to simplify a script that reacts to an onClick event. For every ZUL component, it is possible to define its own new attributes with the help of a <customattributes> tag. Such attributes can bear any Java objects as values. In the example, it allowed me to store the number of a row, and then identify it when the Delete key was clicked.
An interesting functionality of the ZK framework is a class imitating the JOptionPane from the Swing library, which displays standard dialogs. In ZK, you can use org.zkoss.zul.MessageBox for this purpose. It is especially helpful in web programming because it lets you mix program logic with basic user interaction. Anyone who wants to ask for confirmation of a current operation after checking some conditions in business logic will appreciate this functionality.
At the end of the example code handling the onClick event, there is a redirection to another page (in this case, to force refresh, it is the same page). Here, I use a static sendRedirect method of the org.zkoss.zk.ui.Executions class, which is analogous to sendRedirect from javax.servlet.http.HttpServletResponse.
Tables, Nested Controls, and Dynamic Content
By defining a model, you make the ZK table responsible for visualization. In this case, however, you can't specify in ZUL which controls you want to use. ZK can still help with a technique that defines a custom renderer of the table rows view (Listing Ten, available online).
The method render of class zkdemo.ui.view.GridRowRenderer is responsible for typesetting an individual table row. For that purpose, it must create child components for the org.zkoss.zul.Row object, which visualizes cells in this row. In the example program, this takes place in the beginning of this method, where labels are created inside a for loop. The rest of the method creates an additional button together with its ON_CLICK event handler. To complete the example, you only need the ZUL table that will set the type of its rows (Listing Eleven, available online).
In this example, I also used an alternative method for building a UI in ZK, based on a specialized API. For every ZUL tag, there is a corresponding class with properties that reflect the tag attributes, making it possible to create whole pages in Java alone. Sometimes, this technique offers more flexibility than using XML.