Using a ListModel and RowRenderer"

From Documentation
m
m
Line 67: Line 67:
 
<br>
 
<br>
 
At line 5, we cast the data object back to the Product object so we could extract information from it and render them 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.<br>
 
At line 5, we cast the data object back to the Product object so we could extract information from it and render them 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.<br>
 
+
<br>
 
We are required to place an image of the product in the first column, hence at line 7, we create an instance of the <javadoc>org.zkoss.zul.Image</javadoc> 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 <javadoc>org.zkoss.zul.Label</javadoc> 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 <javadoc>org.zkoss.zul.Cell</javadoc> component which is set as the child component for the last column of the row.
 
We are required to place an image of the product in the first column, hence at line 7, we create an instance of the <javadoc>org.zkoss.zul.Image</javadoc> 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 <javadoc>org.zkoss.zul.Label</javadoc> 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 <javadoc>org.zkoss.zul.Cell</javadoc> component which is set as the child component for the last column of the row.
 
<source lang="java">
 
<source lang="java">
Line 91: Line 91:
 
}
 
}
 
</source>
 
</source>
In the '''initOperation''' method, <javadoc>org.zkoss.zul.Spinner</javadoc> and <javadoc>org.zkoss.zul.Button</javadoc> are created programmatically to allow end users to select the quantity of the items to be purchased;  
+
In the '''initOperation''' method, <javadoc>org.zkoss.zul.Spinner</javadoc> and <javadoc>org.zkoss.zul.Button</javadoc> are created programmatically to allow end users to select and submit the quantity of the items to be purchased; the <javadoc>org.zkoss.zul.Cell</javadoc> is set as the parent component for these components. The <javadoc>org.zkoss.zul.Cell</javadoc>
 
<source lang="java">
 
<source lang="java">
 
         private Cell initOperation(final Product prod){
 
         private Cell initOperation(final Product prod){

Revision as of 10:41, 13 October 2010

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 {
		...
		
		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 a RowRenderer 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 them 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.

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);
			}
			...
			
		});
	}

In the initOperation method, Spinner and Button are created programmatically to allow end users to select and submit the quantity of the items to be purchased; the Cell is set as the parent component for these components. The Cell

        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());
			     }
			     }
			});
			return cell;
			}