MVVM in ZK6:in Contrast to MVC

From Documentation
DocumentationSmall Talks2011DecemberMVVM in ZK6:in Contrast to MVC
MVVM in ZK6:in Contrast to MVC

Author
Hawk Chen, Engineer, Potix Corporation
Date
December 16, 2011
Version
ZK 6

Introduction: MVVM in ZK6 - In Contrast to MVC

In the article MVVM in ZK 6 - Design Your First MVVM Page, Dennis demonstrated how users can build ZK applications using the MVVM pattern. It’s a big change from using a composer. In this article, we are going to build the same application, an item search application, as described in the article mentioned above, but instead, using a composer.The style of manipulating UI components in a composer is more like the MVP (Model-View-Presenter) pattern which is, a variant of MVC. The composer plays the role as “Presenter” in the MVP pattern. It handles events from users' interaction, retrieves data from “Model”, and updates “View“ by manipulating UI components directly.

Implementation Steps

  1. Write a ZUL
  2. searchMvc.zul

    <zk>
    <style>
    .z-listcell.red .z-listcell-cnt, .z-label.red{
    	color:red;
    }
    </style>
    <window id="searchWin" title="Search Storage Item" border="normal" width="600px"
    	apply="org.zkoss.bind.examples.search.mvp.SearchPresenter" >
    	<vbox hflex="true">
    		<hbox>
    			Filter : 
    			<textbox id="filterBox" value="*" instant="true"/> 
    			<button id="searchButton" label="Search" />
    		</hbox>
    		<listbox id="itemListbox" hflex="true" height="300px">
    			<listhead>
    				<listheader label="Name"/>
    				<listheader label="Price" align="center" width="80px" />
    				<listheader label="Quantity" align="center" width="80px" />
    			</listhead>
    		</listbox>
    		<groupbox id="detailBox" visible="false" hflex="true" mold="3d">
    			<caption id="detailCaption" />
    			<grid hflex="true" >
    				<columns>
    					<column width="120px"/>
    					<column/>
    				</columns>
    				<rows>
    					<row>Description <label id="descriptionLabel"/></row>
    					<row>Price <label id="priceLabel" /></row>
    					<row>Quantity <label id="quantityLabel" /></row>
    					<row>Total Price <label id="totalPriceLabel" /></row>
    				</rows>
    			</grid>
    		</groupbox>
    	</vbox>
    </window>
    </zk>
    
    • The ZUL has little difference from the one in the MVVM pattern; the only difference is that it does not contain ZK bind annotations.

  3. Create a Composer
  4. SearchPresenter.java

    public class SearchPresenter extends SelectorComposer<Component>{
    	//the search result
    	private ListModelList<Item> items;
    
    	//the selected item
    	private Item selected;
    	//UI component
    	@Wire("#filterBox")
    	private Textbox filterBox;
    	@Wire("button")
    	private Button searchButton;
    	@Wire("listbox")
    	private Listbox itemListbox;
    	@Wire("groupbox")
    	private Groupbox detailBox;
    	@Wire("caption")
    	private Caption detailCaption;
    	@Wire("#descriptionLabel")
    	private Label descriptionLabel;
    	@Wire("#priceLabel")
    	private Label priceLabel;
    	@Wire("#quantityLabel")
    	private Label quantityLabel;
    	@Wire("#totalPriceLabel")
    	private Label totalPriceLabel;
    
    	@Override
    	public void doAfterCompose(Component comp) throws Exception {
    		super.doAfterCompose(comp);
    		doSearch();
    		itemListbox.setModel(items);
    		itemListbox.setItemRenderer(new ItemRenderer());
    	}
    	
    	protected SearchService getSearchService(){
    		return new FakeSearchService();
    	}
    	
    	@Listen("onClick = button")
    	public void doSearch(){
    		items = new ListModelList<Item>();
    		items.addAll(getSearchService().search(filterBox.getValue()));
    		itemListbox.setModel(items);
    		detailBox.setVisible(false);
    	}
    	
    	@Listen("onChange = #filterBox")
    	public void changeButtonStatus(){
    		searchButton.setDisabled(filterBox.getValue().length()==0);
    	}
    	@Listen("onSelect = listbox")
    	public void selectItem(){
    		selected = items.get(itemListbox.getSelectedIndex());
    		//display item detail
    		detailBox.setVisible(true);
    		detailCaption.setLabel(selected.getName());
    		descriptionLabel.setValue(selected.getDescription());
    		priceLabel.setValue(ItemRenderer.priceFormatter.format(selected.getPrice()));
    		quantityLabel.setValue(Integer.toString(selected.getQuantity()));
    		quantityLabel.setSclass(selected.getQuantity()<3?"red":"");
    		totalPriceLabel.setValue(ItemRenderer.priceFormatter.format(selected.getTotalPrice()));
    	}
    }
    

    The following points can be seen from the above sample code

    • The composer doesn't have a lot of getter and setters, but developers have to declare a lot of variables corresponding to UI components.
    • A lot of coding is needed when using public void selectItem() to display details of an item whereas ZK bind saves us a lot of effort for doing the same thing
    • No need to implement Converter

  5. Implement Listbox Rendering
  6. ItemRenderer.java

    public class ItemRenderer implements ListitemRenderer<Item>{
    
    	static DecimalFormat priceFormatter = new DecimalFormat("$ ###,###,###,##0.00");
    
    	public void render(Listitem item, Item data){
    		
    		Listcell nameCell = new Listcell();
    		nameCell.setLabel(data.getName());
    		Listcell priceCell = new Listcell();
    		priceCell.setLabel(priceFormatter.format(data.getPrice()));
    		Listcell quantityCell = new Listcell();
    		quantityCell.setLabel(Integer.toString(data.getQuantity()));
    		if (data.getQuantity()<3){
    			quantityCell.setSclass("red");
    		}
    		
    		item.appendChild(nameCell);
    		item.appendChild(priceCell);
    		item.appendChild(quantityCell);
    		
    	}
    }
    

Comparison

As ViewModel does not hold references to ZK components after requirements and functions are confirmed, UI designers and programmers can work in parallel. This pattern is very suitable for the “design by contract” approach. This approach reduces errors that are caused by frequent UI requirement changes; even if the UI design is modified afterwards, as long as the . the modification does not change the contract (confirmed functions), it won't affect programmer’s work.

ZK MVVM forces developers to write presentation logic on ZUL with ZK Bind annotations. This pattern clearly separates the responsibility of ZUL and ViewModel and as ZK Bind annotations can be applied to components' attributes, developers can as a result achieve many dynamically interaction effects by altering components' attributes. On the other hand, In MVC, developers are required to write them in the composer which makes it is harder to maintain the presentation logic, but the upside is that developers are offered more flexibility. For example,

  • To disable search button when textbox is empty
  • In MVVM you do this: search.zul
    <button label="Search" disabled="@load(empty vm.filter)" />
    

    In MVC you do this:

    SearchPresenter.java

    	@Listen("onChange = #filterBox")
    	public void changeButtonStatus(){
    		searchButton.setDisabled(filterBox.getValue().length()==0);
    	}
    

    In MVC, you still need to write two variables for textbox and button component respectively whereas in MVVM, with ZK Bind annotation, only one line of code is required. It is also easier to maintain and understand a custom view layout that is written in ZUL using ZK Bind annotation than that is implemented in a renderer class.

  • To customize item display
  • In MVVM you do this: search.zul
    			<template name="model" var="item">
    				<listitem >
    					<listcell label="@load(item.name)"/>				
    					<listcell label="@load(item.price) @converter('formatedNumber', format='###,##0.00')"/>
    					<listcell label="@load(item.quantity)" sclass="@load(item.quantity lt 3 ?'red':'')"/>	
    				</listitem>
    			</template>
    

    In MVC, you do this:

    public class ItemRenderer implements ListitemRenderer<Item>{
    
    	public void render(Listitem item, Item data){
    		//...other code		
    		int quantity = data.getQuantity();
    		if ( complexRule(quantity)){
    			//set color 1
    		}else if ( anotherComplexRule(quantity)){
    			//set color 2
    		}else {
    			//set color 3
    		}
    		//...other code	
    	}
    }
    

As you can see, using the tag <template> to customize listitem is a more readable approach than using ItemRenderer.java . However, in practice, sometimes <template> cannot satisfy users' needs and it becomes easier to write complex presentation logic in Java than in EL. For example, as you can see from above code snippet, if a developer wanted to implement a function where complex business logic is based upon in order to display quantity in different colours, it would be more practical to use ItemRenderer.java .




Of course, if developers are required to have more control on ZK components like for example creating child components dynamically then it is better to use the composer with auto-wired components.

In ZK MVVM, developers are not required to declare variables for each ZK components, components are manipulated through ZK Bind annotation that is assigned to components' attributes. However, in MVC with the composer approach, developers are not required to provide a lot of setters and getters; they change View content by manipulating ZK components manually.

In terms of testing, unit test can be done on ViewModel easily because it’s separated with ZUL while composers can only be tested through browsers.

To summarize, a comparison table is illustrated below

  • Comparison Table
MVVM
MVC
Coupling with View Loose Tight
Where Presentation Logic Locates  ZUL Java
Controller Implementation A POJO   A class that extends ZK's composer  
How to Update UI    Use ZK Bind annotation to notify the binder    Manipulate UI components
Controller is unit testable Yes No

Conclusion

Adopting which pattern depends on the developer's context and requirement.

If you need

  • A clear separation between the View layer and its back-end
  • perform unit test on every layer of application

then, MVVM would be the more suitable pattern to utilize.


If you prefer

  • more flexibility
  • and can handle complex presentation logic

then, MVC would be the more suitable pattern to use.

Download

zkbind-examples ( with source code)

See Also

  1. Envisage ZK 6: The Next Generation Data Binding System
  2. Hello ZK MVVM
  3. MVVM in ZK 6 - Design your first MVVM page
  4. MVVM in ZK 6 - Design CRUD page by MVVM pattern


Comments



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