Using a ListModel and RowRenderer

From Documentation

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

Using a ListModel and RowRenderer

Data presentation in ZK involves preparing the Model and Renderer in association with the View (ZK components). Once an association is established between 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.

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 {
		super.doAfterCompose(comp);
		
		ProductDAO prodDao = new ProductDAO();
		List<Product> prods = prodDao.findAllAvailable();
		
		ListModelList prodModel = new ListModelList(prods);
		prodGrid.setModel(prodModel);

		});
	}

Using a RowRenderer to Populate Data

public void doAfterCompose(Component comp) throws Exception {
		super.doAfterCompose(comp);
		
		ProductDAO prodDao = new ProductDAO();
		List<Product> prods = prodDao.findAllAvailable();
		
		ListModelList prodModel = new ListModelList(prods);
		prodGrid.setModel(prodModel);
		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);
			}
			
			private Cell initOperation(final Product prod){
				Cell cell = new Cell();
				final Spinner spinner = new Spinner(1);
				spinner.setConstraint("min 1 max "+prod.getQuantity());
				spinner.setParent(cell);
				
				Button button = new Button("add");
				button.setImage("/image/ShoppingCart-16x16.png");
				button.setParent(cell);
				
				final Label errorLb = new Label();
				errorLb.setParent(cell);
				
				button.addEventListener(ON_CLICK, new EventListener() {
					public void onEvent(Event event) throws Exception {
						ShoppingCartCtrl ctrl = ShoppingCartViewCtrl.getInstance(desktop);
						try{
							ctrl.addItem(prod, spinner.getValue());	
							errorLb.setValue("");
						}catch(WrongValueException e){
							errorLb.setValue(e.getMessage());
						}
					}
				});//end of class....
				return cell;
			}
		});
	}