One of the things I really like about ZK is its capability for designing complex UI using just ZUL. But sometimes it’s not possible to lean just on ZUL code. Somehow you’re force to code a Renderer to circumvent certain drawbacks of the ZK framework.

One of this cases, which tends to happen rather to say often, is to render a Listbox** or a **Grid feeded by live-data while establishing at the same time some properties of the items being rendered. For instance, imagine you need to render a list of customers. For each customer there’s an extra column containing a button for editing customer’s personal data in an independent dialog window. Only users with granted permissions can edit customer’s personal data. It’s not a very ellaborate example but illustrates quite well a case where most likely you may need a Renderer.

<grid id=”gridCustomers”
        fixedLayout=”true”
        model=”@{customersController.customers}”>
    
        <column label=”Code” />
        <column label=”Name” />
        <column label=”Surname'” />
        <column label=”” />
    

    
        <row self=”@{each=’customer’}” value=”@{customer}” >
            <label id=”code” value=”@{customer.code}” />
            <label value=”@{customer.name}” />
            <label value=”@{customer.surname}” />
            <button sclass=”icon”
                image=”/common/img/ico_edit1.png”
                hoverImage=”/common/img/ico_edit.png”
                tooltiptext=”Edit”
                onClick=”customersController.edit(self.parent.value)” />
        </row>
    

</grid>

Why? The difficult part here is to set the attribute disabled for element edit button. There’s no way in ZUL for calling a method plus assigning its returned value to an attribute of a ZUL component. For instance,

<button disabled=”customersController.hasPermissions(self.parent.value)” />

The code above doesn’t work as disabled is defined as an attribute. Although attributes can be bound to an element (via a pair of get/set methods) using bindings, they cannot trigger methods in the controller in the same way events do.

However it’s possible to bind events and business-logic methods together.

<button onclick=”customersController.edit(self.parent.value)” />

The code above works as onclick is defined as an event. Events can trigger methods, whenever an event happens its associated method is executed.

Refactoring ZUL code into a Renderer is time-consuming and provides a much less elegant solution than doing it directly using ZUL. Struggling my head a bit about this problem, I managed to find a solution which with some little Java code, doesn’t require to refactor all the ZUL code into a Renderer.

The trick here is to code in ZUL as many things as you can. For those properties you cannot code in ZUL, simply overload the event onInitRender() *of the element you need to tune and *modify it directly from  Java code. Here’s an example:

public class CustomersController extends GenericForwardComposer {

   private Grid gridCustomers;

   public void doAfterCompose(Component comp) throws Exception {
      super.doAfterCompose(comp);
      gridCustomers.addEventListener("onInitRender", new EventListener() {
         @Override
         public void onEvent(Event event) throws Exception {
            gridCustomers.renderAll();
            final Rows rows = gridCustomers.getRows();
            for (Iterator i = rows.getChildren().iterator(); i.hasNext(); ) {
               final Row row = (Row) i.next();
               final Customer customer = (Customer) row.getValue();
               Button btnEdit = (Button) row.getChildren().get(3);
                  btnEdit.setDisabled(hasPermissions(customer));
               }
            }
      });
   }
}

The event onInitRender is triggered when the component gridCustomers starts to be rendered. At this time, none of its subcomponents have been rendered yet, so any attempt of modifying any element within gridCustomers will result into an error,* **gridCustomers.renderAll()* forces its children subcomponents to be rendered, making it possible to modify any element within gridCustomers. After that, the code above fetches the 4th column, **btnEdit, for every row and set its attribute disabled to the value returned by the function hasPermissions(customer). With this little trick, the problem has been solved.

Leaning on ZUL code can really fast your development pace and increase your productivity, besides leaving your code cleaner and easier to understand. However, sometimes it’s not possible to code an UI just by using ZUL, so a Renderer may be required. This solution shows how it’s possible to still use ZUL code while relying on some Java code for doing the hard parts, avoiding all the trouble of coding a Renderer.