MVVM Extension: Access UI Components Inside ViewModel

From Documentation

WarningTriangle-32x32.png This page is under construction, so we cannot guarantee the accuracy of the content!

DocumentationSmall Talks2012JanuaryMVVM Extension: Access UI Components Inside ViewModel
MVVM Extension: Access UI Components Inside ViewModel

Author
Hawk Chen, Engineer, Potix Corporation
Date
?
Version
ZK 6

Preface

Developing an application in MVVM pattern has several advantages including the clear separation between View and back-end and how you can easily perform a unit test. However, sometime developers want more control of components like dynamically creating components, or to customize load on demand. Sometimes it's just personal preference. This article will show you how you can access UI components inside a ViewModel to customize components with a little bit of extra work. But we don't encourage this approach.

Extend Case Scenario: Popup Detail

In search example mentioned in previous article, MVVM in ZK 6 - Design your first MVVM page, users see an item's description in detail only when they click a item in the listbox (as the below image shows). It is more convenient to show the description when the mouse hover an item without clicking it. We'll implement this feature through MVVM with autowiring components.

Smalltalks-mvvm-in-zk6-view-example.png

Add Popup

Add a popup component to display item description.

searchMvvmAutowire.zul

	<popup id="msgPopup">
		<label id="msg"></label>
	</popup>

Enable Autowire of ViewModel

A ViewModel is a POJO basically, it doesn't have any ability to wire UI components. We empower ViewModel to wire components with @init.

SearchAutoWireVM.java

public class SearchAutowireVM{
	//other variables
	//UI component
	@Wire("#msgPopup")
	Popup popup;
	@Wire("#msg")
	Label msg;

	@Init
	public void init(BindContext ctx){
		//Returns associated root component of the binder
		Component component = ctx.getBinder().getView();
		Selectors.wireVariables(component, this);
		//wire event listener
//		Selectors.wireEventListeners(component, this);
	}
	//...
}

We annotate a method public void init(BindContext) with @Init, then the binder will invoke this method and pass in BindContext when it initializes the ViewModel. Inside the method, Selectors.wireVariables(component, this) will wire those variables with @Wire. Selectors.wireEventListeners(component, this) wires those methods with annotation @Listen as event listeners. There is no event listener in this example, so we comment out this method calling. Here we use "wire by selector", "#msgPopup" means wiring a component with id "msgPopup". This feature is provided by SelectorComposer mentioned by another small talk.

Popup Message

Manipulate popup component to display a popup message at the end of listitem.

SearchAutoWireVM.java

	@Command
	public void popupMessage(@Param("target")Component target, @Param("content")String content){
		msg.setValue(content);
		popup.open(target,"end_before");
	}

Those variables, "msg" and "popup" are components that are wired by @Wire. @Param("target") declares that the binder shall a argument with key "target" from ZUL. The target is the target component which the popup message displays on. The content is the message to display.


Bind command to mouse over event on listitem.

searchMvvmAutowire.zul

<listbox model="@load(vm.items)" selectedItem="@bind(vm.selected)" hflex="true" height="300px">
	<listhead>
		<listheader label="Name"/>
		<listheader label="Price" align="center" />
		<listheader label="Quantity" align="center"  />
	</listhead>
	<template name="model" var="item">
		<listitem onMouseOver="@command('popupMessage', target=self, content=item.description)">
			<listcell label="@bind(item.name)"/>
			<listcell label="@bind(item.price)@converter('formatedNumber', format='###,##0.00')"/>
			<listcell label="@bind(item.quantity)" sclass="@bind(item.quantity lt 3 ?'red':'')"/>
		</listitem>
	</template>
</listbox>

We should pass 2 arguments with key "target" and "content" respectively upon the command method's signature. The order of argument is unimportant but the key and type should correspond to command method's arguments.


Final Result

Smalltalks-mvvm-in-zk6-autowire-popup-description.png

When mouse hover an item, a popup of description for that item displays at the end of the row. Users can read the detail of an item instantly without clicking them one by one.

Conclusion

Follow rigid principle of MVVM pattern is encouraged, but this approach we introduce here is an alternative if it suits you. Although it couples the ViewModel with View, it's easy to get back to MVVM (Just remove annotations in Java and add ZK bind expressions on the ZUL). Developers can choose the way according to their context and environment.


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



Comments



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