Test Driving the MVVM Pattern with ZK Ajax
Join the DZone community and get the full member experience.
Join For FreeIntroduction
This article is the latest in a series demonstrating alternative GUI Design Patterns using the ZK RIA AJAX framework. Two previous articles used the Model-View-Presenter and Model-View-Controller patterns in the context of implementing a simple "todo reminders" screen. This article showcases the Model-View-ViewModel pattern to implement the same simple screen.
The example code for this article is with the ZkToDo2 project hosted on SourceForge under the ZKForge project. The code is built with Maven and aims to be self installing. The code will even run itself in an embedded Servlet container which Maven will download and launch. All you need is either the command-line Maven build system or a Maven plug-in for your chosen IDE. The easiest way to get started with the code is to build and run the application on the command-line using only a stock Maven distribution using the instructions here. Alternatively the steps to checkout, build, run and debug the application using Eclipse with the m2eclipse Maven Eclipse plug-in are here.
Why UI Design Patterns?
When building a system it is convenient to discuss the requirements in terms of the screens. Yet the screens of a system are likely to change all the way up to go-live and beyond. This happens because the presentation is incidental to what the user of the system is logically doing; know as the Use Case or User Story (e.g. user buys a book). Whilst features evolve slowly over time the screens may vary rapidly between project iterations. Separating business application logic from screen update logic makes for supple code.
Organising the UI business logic code into a separate layer with no compile time dependencies on UI framework code allows for easer JUnit test coverage. The separation of concerns of "Business Logic" from "Rendering Logic" makes it easier to both enhance application functionality and to re-arrange screens. In contrast putting application Use Case logic directly inside of screen rendering classes makes for a more rigid and brittle code-base.
The Model-View-ViewModel Pattern
The core concept of GUI Design Patterns is "separated presentation". The references section below includes a link to Martin Fowler's excellent discussion of this topic. Many design patterns have both a View and a Model logical layer. The well know pattern MVC introduces a Controller layer to mediate between the Model and the View. The Model-View-ViewModel pattern replaces the concept of a Controller with a ViewModel. A ViewModel is an POJO model of the application logic; it is the naked UI business logic without a screen. On top the naked logic we bind one or more active screens. The key to this approach is a UI framework Binder. This article will describe how the ZK Binder technology animates the View to render the changed state of the ViewModel. The key role of the UI framework Binder gives rise to an alternative name for this pattern: Model-View-Binder (MVB).

The diagram above shows the logical layering of the MVVM pattern. The View layer is the ZK Desktop and its supporting Binder which will be described below. Commands are fired from the View into the ViewModel in response to user actions. The changing data and state of the ViewModel is then loaded back into the View to show the effects of the commands.
The DomainModel below the ViewModel comprises of the application services, JPA entities and the related data access logic of a typical application business tier. The book "POJOs In Action" by Chris Richardson gives an excellent introduction on using test driven development to build a well layered DomainModel. The sample application uses Spring and Hibernate JPA for its internal layering and the Detached Entity pattern (no DTOs).
The Example Screen
The MVVM version of the "todo reminders" screen is defined within the single file zktodo_c.zul. Here is a screenshot:

The screen renders a collection of Reminder objects which are JPA entities stored in the database:
@Entity @Table(name = "REMINDER" public class Reminder { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "REMINDER_ID") private Long id; @Column(name = "NAME") private String name = ""; @Column(name = "PRIORITY") private int priority = 0; @Column(name = "DATE") private Date date = new Date(System.currentTimeMillis()); ... // setters and getters, equals and hashcode, constructors }The syntax of the ZUL file is a dialect of XUL:
<?init class="org.zkoss.zkplus.databind.AnnotateDataBinderInit" ?> <?init class="org.zkforge.zktodo2.binding.CommandBinderInit"?> <?variable-resolver class="org.zkoss.zkplus.spring.DelegatingVariableResolver" ?> <zk xmlns="http://www.zkoss.org/2005/zul"> <window> <listbox id="list" multiple="true" rows="12" model="@{toDoViewModel.reminders, load-after='add.onClick,update.onClick,delete.onClick'}" selectedItem="@{toDoViewModel.selectedReminder}"> <listhead> <listheader label="Item" /> <listheader label="Priority" width="80px" /> <listheader label="Opened" width="90px" /> </listhead> <listitem self="@{each=reminder}"> <listcell label="@{reminder.name}"/> <listcell label="@{reminder.priority}"/> <listcell label="@{reminder.date, converter='org.zkforge.zktodo2.DateFormatConverter'}"/> </listitem> </listbox> <vbox> <hbox> Item:<textbox cols="40" constraint="no empty" value="@{Model.selectedReminder.name, load-after='add.onClick,delete.onClick'}"/> Priority:<intbox id="priority" cols="1" constraint="no empty" value="@{toDoViewModel.selectedReminder.priority, load-after='add.onClick,delete.onClick'}" /> Date:<datebox id="date" cols="14" constraint="no empty" value="@{Model.selectedReminder.date, load-after='add.onClick,delete.onClick'}" onChange="@{Model, converter='org.zkforge.zktodo2.binding.InputEventCommandConverter'}"/> </hbox> <hbox id="buttons"> <button id="add" label="Add" width="36px" height="24px" onClick="@{toDoViewModel}"/> <button id="update" label="Update" width="46px" height="24px" onClick="@{Model}"/> <button id="delete" label="Delete" width="46px" height="24px" onClick="@{toDoViewModel}"/> </hbox> </vbox> </window> </zk>The ZK framework is built upon Java Servlet technology. The ZUL page is parsed to create it a desktop of Java components on the server. This is then rendered as DHTML to the browser. User interactions with the DHTML are fired as AJAX events back to the server. Changes to the desktop made by the Java AJAX event handler code are automatically rendered into the browser. In this manner a Rich Internet Application can be programmed directly with Java logic running on the server.
Near the top of the page the AnnotateDataBinder and CommandBinder page initiators are applied to the screen:
<?init class="org.zkoss.zkplus.databind.AnnotateDataBinderInit" ?> <?init class="org.zkforge.zktodo2.binding.CommandBinderInit"?>These binders read the declarative databindings syntax "@{binding}" within the page and bind the annotated ZK components onto our Java code. The targets of the bindings is the variable "toDoViewModel". As there is no component within the page with this ID the variable will be resolved to a Spring bean with that name. This was achieved by including the spring variable resolver near the top of the page:
<?variable-resolver class="org.zkoss.zkplus.spring.DelegatingVariableResolver" ?>
Within the spring configuration file spring-context.xml the "toDoViewModel" bean and its dependencies are defined as follow:
<bean id="toDoViewModel" class="org.zkforge.zktodo2.ZkToDoViewModel" p:reminderService-ref="reminderService" scope="desktop" /> <bean id="reminderService" class="org.zkforge.zktodo2.ReminderService" p:basicDao-ref="basicDao" /> <bean id="basicDao" class="org.zkforge.zktodo2.BasicDao" />
A key nature of the "toDoViewModel" bean is that it has "desktop" scope. Desktop scope is a custom Spring scope defined by the ZKSpring integration library. This will cause Spring to keep one and only one instance of the bean associated with the users ZK Desktop defined by the ZUL page. The model bean is provided with a service bean "reminderService". The service bean is provided with a data access bean "basicDao". The service bean and data access bean have default scope so they will be singleton objects. Setting the scopes in this manner allows the model bean to be stateful bean servicing a ZK desktop over many AJAX interactions.
The Bindings
Within the ZUL file property values in the format the "@{binding}" define how the value data, display state (e.g. visible/disabled), and command methods exposed by the ViewModel are bound to the View. The View is the combined desktop of screen Components which are described by the ZUL file. The listbox which defines the list of items has a binding for its properties "model" and "selectedItem":
<listbox model="@{toDoViewModel.reminders, load-after='add.onClick,update.onClick,delete.onClick'}" selectedItem="@{toDoViewModel.selectedReminder}">
The "model" property of the listbox the list of items to be displayed. This is bound to the "reminders" property of the "toDoViewModel" bean. Within the ViewModel class this property is a getter which queries the ReminderService:
protected ReminderService reminderService; public List<Reminder> getReminders() { return this.reminderService.findAll(); }
The "model" binding attribute above has 'load-after' attributes. These specify that the model be reloaded (and hence re-rendered) whenever the onClick events of the add, update or delete buttons have been run. This has the effect of automatically re-rendering the list when the ReminderService has been updated in response to user actions.
The rendering of the list of reminders is defined by the "@{each=loopVar}" binding:
<listitem self="@{each=reminder}"> <listcell label="@{reminder.name}"/> <listcell label="@{reminder.priority}"/> <listcell label="@{reminder.date, converter='org.zkforge.zktodo2.DateFormatConverter'}"/> </listitem>
The "each" loop iterates over the collection bound as the "model" and defines a loop variable "reminder". At each iteration a new ListItem instance is created containing three Listcells. The labels of the listcell components are bound to the properties of the current loop variable Reminder object. In this manner the list of business objects returned by the ReminderService from the database is rendered into the screen without having written any custom code. The 'load-after' attributes of the model binding cause the list to be re-fetched and re-rendered any time the add, update or delete buttons are clicked.
The "selectedItem" property of the listbox is updated whenever the user click on an item in the list. This property is bound to the "selectedReminder" property of the "toDoViewModel" bean. In the ViewModel class this property is a regular getter and setter of a member variable:
protected Reminder selectedReminder; public Reminder getSelectedReminder() { return selectedReminder; } public void setSelectedReminder(Reminder reminder) { this.selectedReminder = reminder; if( this.selectedReminder == null ){ this.selectedReminder = new Reminder(); } }
Whenever the user clicks on a different item in the list the setter of the ViewModel is invoked passing in the Reminder business object which was used to render the particular listitem. In this manner the "selectedReminder" property of the ViewModel is always the user's current selection.
The editing panel allows the user to edit the selected Reminder entity. This is easily achieved by binding the input components of the edit panel onto the "selectedItem" property of the ViewModel:
<hbox> Item:<textbox cols="40" constraint="no empty" value="@{toDoViewModel.selectedReminder.name, load-after='add.onClick,delete.onClick'}"/> Priority:<intbox id="priority" cols="1" constraint="no empty" value="@{toDoViewModel.selectedReminder.priority, load-after='add.onClick,delete.onClick'}" /> Date:<datebox id="date" cols="14" constraint="no empty" value="@{toDoViewModel.selectedReminder.date, load-after='add.onClick,delete.onClick'}" onChange="@{toDoViewModel, converter='org.zkforge.zktodo2.binding.InputEventCommandConverter'}"/> </hbox>
A Textbox is bound to the name property of the selected Reminder business object. Similarly an Intbox is bound to the priority attribute and a Datebox is bound to the date property. When a user clicks the add or delete buttons the "selectedReminder" attribute of the ViewModel will change. As the Binder knows it has changed the attribute of the model it will reload the edit panel. The bindings also include 'load-after' hints to reload the panel in response to buttons being pressed which can change the "selectedReminder" of the ViewModel.
The editing panel bindings both read and write. When the user enters data into the textbox the onChange event handler will cause the Binder to invoke the "name" setter on the currently selected Reminder bean. In this manner no code is required to cause the edit panel to update the business objects. All that work is done automatically by the Binder as dictated by the bindings in the ZUL file.
The "add", "update" and "delete" buttons are as follows:
<button id="add" label="Add" width="36px" height="24px" onClick="@{toDoViewModel}"/> <button id="update" label="Update" width="46px" height="24px" onClick="@{toDoViewModel}"/> <button id="delete" label="Delete" width="46px" height="24px" onClick="@{toDoViewModel}"/>
The onClick events are bound to methods of the ViewModel. The target method name is set by convention; the method name of the command to invoke on the ViewModel is defined by the ID property of the component. The buttons have IDs of "add", "update" and "delete" so these are the names of the methods which are invoked on the "toDoViewModel" bean:
public void delete() { if( this.selectedReminder.getId() != null ){ try { this.reminderService.delete(selectedReminder); this.selectedReminder = new Reminder(); } catch (EntityNotFoundException e) { e.printStackTrace(); } } } public void update() { if( this.selectedReminder.getId() != null ){ try { this.reminderService.merge(selectedReminder); } catch (EntityNotFoundException e) { e.printStackTrace(); } } } public void add() { if( this.selectedReminder.getId() == null ){ this.reminderService.persist(this.selectedReminder); this.selectedReminder = new Reminder(); } }
These three business methods of the ViewModel work directly with the selected Reminder entity. The selected Reminder is the one held by the "selectedItem" binding which writes to the "selectedReminder" property of the ViewModel. There is no code required to pull the correct business object out of a list; the ZK Binder technology does the work. Recall that the edit panel has 'load-after' hints to refresh the panel after both the "add" and "delete" buttons are clicked. We can see from the code above that this is required because the corresponding methods in the ViewModel change the "selectedReminder" property.
The binder is tracking the dependencies of the components which are bound to the same property; when it writes to a ViewModel property it automatically reloads all screen variables bound to the same property. When you use the edit panel the components write directly into the Reminder entity; and this is reflected instantly within the list. We only need to provide 'load-after' hints when business logic changes a bound property in a way which cannot be anticipated by the Binder.
Although not required for this screen the Binder is able to bind the "visible" and "disabled" attributes of Components onto boolean ViewModel properties. The example application has a screen weather-station-mvvm.zul which makes dynamically disables the edit panel fields based on the state of a ViewModel property. Using a "visible" binding we could also make the entire edit panel or individual fields show and hide themselves based on a boolean property of the ViewModel.
The ViewModel In Focus
The ViewModel logic presented within this article is materially different from a Presenter within the MVP pattern. It does not push business state into the screen components. Instead the business state is pulled into the View from the ViewModel by the AnnotateDataBinder. The ViewModel is also different from a Controller within the ZK MVC pattern. A ZK Controller implemented as a GenericForwardComposer subclass requires specifically named event handler methods which take the ZK Event object as a method argument. In contrast the ViewModel class is not a UI framework type; it implements no UI framework methods. Instead the CommandBinder class mediates between the event handling logic and the business methods.
Although not shown above a converter can be specified with "onClick=${bean, converter}". The converter can extract business objects from the onClick event or its target component. These resolved business objects will then be passed as arguments to the bound business method. Fully decoupling the ViewModel from the presentation framework makes it a pure Model of a logic UI independent of the presentation framework. Such a model can be exposed via a soap interface and invoked by remote programs. It can also be bound to multiple screens. An industrial administrator user might access one ZUL page optimized for a mouse and keyboard. Technicians out in the field might access the same ViewModel via a different ZUL page optimized for a rugged touch screen device with large high contrast buttons. We might have a special set of screen presenting the same ViewModel in manner which is suitable for the visually impaired.
Concluding Remarks
The screen discussed within this articles was created with remarkably few lines of code. The eclipse metrics plugin calculates the "method lines of code" count for the class ZkToDoViewModel as 28 lines. The ZkToDoViewModel class has no compile time dependencies on the ZK framework classes. We rely totally on the reflection capabilities of the ZK Binder classes to create the dynamic screen which drives the model to update the database.
The ViewModel is the naked screen behaviour and state. It is a true stateful ScreenModel or ApplicationModel that mediates between the User and the services of the system. This makes it reusable between different screens. It is also easier to JUnit test the ViewModel as a standalone class. Its the Binder technology of ZK which is the key to this succinct OO approach. Calling the approach Model-View-Binder (or more precisely View-Binder-Model) may guide more people into organising their UI logic around business orientated ViewModels. Long live the Binder!
References
- Presentation Patterns In ZK slides presented to the UK ZK Users Group
- Josh Smith's inspirational Microsoft .Net MVVM Article
- Martin Fowler GUI Patterns pages UI Architectures
- Book on how to build a layered domain model with Spring POJOs In Action
- ZK MVC Screen for POJOs In Action book code Test Driving ZK FoodToGo
- Book on designing "domain objects first" for supple code Evans Domain Driven Design
- MVC article Desktop MVC Patterns ZK, Spring & JPA
- Original MVP article SmallTalks 2008 Best MVC Patterns
Opinions expressed by DZone contributors are their own.
Comments