Using a ListModel and RowRenderer

From Documentation
Revision as of 03:27, 23 June 2011 by PJ li (talk | contribs)

Stop.png This article is out of date, please refer to http://books.zkoss.org/zkessentials-book/master/ for more up to date information.

Data presentation in ZK involves preparing the Model and Renderer in association with the View (ZK components). Once an association is established among these three parts, the data presented in ZK components are automatically updated whenever the data model is changed. In the previous section, we declared the basic UI skeleton, now we'll look into how to prepare a data model and write a renderer to populate the Grid component.
ZKEssentials DisplayInGrid ViewModelRenderer.png

Where the View, Model, and Renderer Come Together

To associate our Product View (Grid component) with a Model and a Renderer, we'll implement a controller class which extends the ZK utility class GenericForwardComposer. In its GenericForwardComposer.doAfterCompose(Component) method, the ZK components declared in mark up are wired with the component instances declared in the controller for our manipulation, while the events fired are automatically forwarded to this controller for event handling. Therefore, in our controller class, we override and call GenericForwardComposer.doAfterCompose(Component) method of its super class and implement the code that assigns a model and renderer to our Product View Grid.


ProductViewCtrl.java

public class ProductViewCtrl extends GenericForwardComposer {

	private Grid prodGrid;
	
 	@Override
	public void doAfterCompose(Component comp) throws Exception {
		super.doAfterCompose(comp);
		
		//create model
        prodGrid.setModel(...); //assign model to Grid

		//create renderer
        prodGrid.setRowRenderer(...);//assign renderer to Grid
		
        ...
	}
}

Notice the Grid reference "prodGrid" in ProductViewCtrl.java is auto-wired with the Grid declared in mark up whose ID is "prodGrid".

<div id="PrdoDiv" style="background:#E6D92C; height:100%" apply="demo.web.ui.ctrl.ProductViewCtrl">
	<grid id="prodGrid">
		<columns sizable="true">
			  <column image="/image/Bullet-10x10.png" align="center"  width="100px"/>
			  <column label="Name" width="100px"/>
			  <column label="Price" width="50px"/>
			  <column label="Quantity" width="50px"/>
			  <column label="Arrive Date" width="110px" />
			  <column label="operation" />
		</columns>
	</grid>
</div>

Wrapping Data Object with ListModel

The implementations of ZK's ListModel interface provide a wrapper for Java Collections to work with ZK's data modeling mechanisms. For Grid and Listbox components, we use the ListModelList implementation; addition or removal of entries in the ListModelList would cause the associated Listbox to update its content accordingly.
In the snippet below, the ListModelList takes in a product list fetched from a DAO object as its argument. At line 8, we assign the ListModelList object as the model for the Product View Grid by using Grid's setModel method.

ProductViewCtrl.java

public void doAfterCompose(Component comp) throws Exception {
		...
		
		ProductDAO prodDao = new ProductDAO();
		List<Product> prods = prodDao.findAllAvailable();
		
		ListModelList prodModel = new ListModelList(prods);
		prodGrid.setModel(prodModel);

        ...
		});
	}

Using a RowRenderer to Populate Data

To populate each row with data, we create an anonymous RowRenderer class and implement its RowRenderer.render(Row row, Object data) method. Here the ZK framework supplies us with the row instance and the data object obtained through the iteration of the data model ListModelList.

At line 5, we cast the data object back to the Product object so we could extract information from it and render it in each row; that is, inside the render method, we associate the data fields of the Product object to a Row object, in the order we wish them to appear across the Grid columns.

We are required to place an image of the product in the first column, hence at line 7, we create an instance of the Image class, configure its dimensions, and finally set the row object as its parent component. From line 11 through 14, we extract the Product's name, price, quantity, and manufactured date and wrap these data fields with the Label components and set the row object as their parent component. Line 15 calls the initOperation method in the same class to create and return a Cell component which is set as the child component for the last column of the row; more of its implementation is shown in the next section.

public void doAfterCompose(Component comp) throws Exception {
		...
		prodGrid.setRowRenderer(new RowRenderer() {
			public void render(Row row, Object data) throws Exception {
				final Product prod = (Product)data;
				
				Image img = new Image(prod.getImgPath());
				img.setWidth("70px");
				img.setHeight("70px");
				img.setParent(row);
				new Label(prod.getName()).setParent(row);
				new Label(""+prod.getPrice()).setParent(row);
				new Label(""+prod.getQuantity()).setParent(row);
				new Label(YYYY_MM_DD_hh_ss.format(prod.getCreateDate())).setParent(row);
				initOperation(prod).setParent(row);
			}
			...
			
		});
	}

The renderer is a series of instructions assigning the UI components with values; using a View-Model-Renderer approach, any changes in the data model translates to updates in the UI component when the renderer code is run.


Last Update : 2011/06/23

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