Hello ZK MVVM
Henri Chen, Principal Engineer, Potix Corporation
October 17, 2011
ZK 6
This is the first article in a series about ZK and MVVM design pattern. I will explain how to use ZK and ZK Bind, our new generation of data binding system, with simple examples. From beginner level to advance level, each article will cover a major feature of the ZK Bind or discuss the best practice of using the ZK Bind with MVVM design pattern in some commonly seen use cases in real world applications. All example source codes are downloadable.
Introduction
Here is some background information if you are not familiar with the term of MVVM. For those who are already familiar with what MVVM is, you can skip this section.
What is MVVM?
MVVM represents Model, View, and ViewModel which is identical to Presentation Model introduced by Martin Fowler, a special variance of the famous MVC pattern.
The ViewModel in MVVM design pattern acts like a special Controller in MVC pattern which is responsible for exposing the data objects from the Model to the View and providing required action logic for user requests from the View. The ViewModel is kind like an abstraction of a View, which contains a View's state and behavior. From another angle, you can also say that the View layer is kind like an UI projection of the ViewModel.
Until now, you might start puzzling: "Isn't that just what Controller is in MVC? Are you just inventing a new term?". Of course not. One more important feature about ViewModel in MVVM pattern is that a ViewModel shall knows nothing about View's visual elements at all. This is the key that makes MVVM design pattern different from other MVC variances.
Why MVVM?
Separation of data and logic from presentation
The key feature that the ViewModel knows nothing about View's visual elements guarantees the one way dependency from View to the ViewModel and avoid mutual programming ripple effects between UI and the ViewModel. Consequently, it brings the following advantages:
- As long as the contract is set(what data to show and what actions to proceed), the UI design and coding of ViewModel can be implemented parellelly. Either side will not block the other's way.
- You can easily change your UI design from time to time without changing the ViewModel as long as the contract does not change.
- You are more likly to design different views for different devices with a common ViewModel. For a desktop browser with bigger screen, you can show more information in one page; while for a smart phone with limited display space, you might design a wizard-based step-by-step operation UI without the need to change (much of) the ViewModel.
- Since ViewModel does not "see" presentation layer, you can unit-test the ViewModel functions easily without UI elements.
What does this has to do with data binding?
Implementation-wise, no matter how, "someone" in the system has to help synchronizing data between View and ViewModel layers. Also this "someone" has to accept the user request from the View layer and bridge to the action logic provided by the ViewModel layer. This "someone", the kernel part in the MVVM design pattern, is typically a data binding system; either written by the application developers themselves or provided by a framework.
It would be easier to explains the concept with examples with two different implementations. One in Model-View-Presenter(MVP)[1] design pattern and another in Model-View-ViewModel(MVVM).
- ↑ Model-View-Presenter(MVP) is another variance of MVC design pattern. If you are not aware of what that is, don't worry, just watch the example codes.
The example -- On Demand Hello World!
The use case: Press a button on the screen and show on the screen a message provided by the Model, say, "Hello World!".
MVP Implementation
- An user push a button(an action) on the screen. A corresponding event is fired.
- An event listener on the back-end handles this event.
- Access data and so on.
- Then UI elements was changed accordingly to provide visual feed backs to the user.
helloMVP.zul
<window apply="test.hello.HelloComposer">
<label id="lbl"/>
<button id="btn" label="Show"/>
</window>
HelloComposer.java
public class HelloComposer extends GenericForwardComposer {
private Label lbl;
public void onClick$btn(Event event) {
lbl.setValue("Hello World!");
}
}
The "Presentor" was injected with the View components Label lbl, Button btn, and the event listener onClick$btn(). As you can see, the characteritic of MVP design pattern is that the Presentor(the Controller) would need to hold references to the View layer UI components so it can update the states of the View and generates visual feed backs. As in this example, the value of the Label component lbl is updated with the "Hello World" and provide visual feed backs to the user.
MVVM Implementation
As you can see on the above graph, data binder plays the role of syncing data between UI and ViewModel.
- An user presses a button on the screen, a corresponding event is fired to the binder.
- The binder finds the corresponding action logic in the ViewModel and call it.
- The action logic access data and so on.
- View-Model notify the binder that some properties have been changed.
- Per what properties have been changed, the binder load data from the ViewModel and updates the corresponding UI controls to provide visual feed backs to the user.
Apparently, UI designer has to tell binder at least following things:
- Which UI event is used to proceed which action logic (so binder knows what to call).
- Which UI attribute is used to show which data (so binder knows what to load and what to update).
- Which UI attribute is used to input into which data (so binder knows what to save).
In ZK MVVM, we utilize the ZK Annotation(link) to do these jobs:
helloMVVM.zul
<window apply="test.hello.HelloViewModel">
<custom-attributes composerName="vm"/>
<label value="@bind(vm.message)"/>
<button label="Show" onClick="@bind('showHello')"/>
</window>
HelloViewModel.java
public HelloViewModel extends GenericBindComposer {
private String message;
public String getMessage() {
return message;
}
@NotifyChange("message")
public void showHello() {
message = "Hello World!";
}
}
Per this example, let's run through the program flow:
- When end user press the "Show" button, the onClick event is fired to binder.
- The binder finds the command name in the ViewModel is "showHello" as specified in the ZK annotation @bind('showHello').
- The binder calls the showHello() method in the HelloViewModel and change the message property. Note the @NotifyChange("message") Java method annotation on showHello() method in HelloViewModel. It tells the binder that the property message in the ViewModel will be changed if calling this command.
- The binder then find that the attribute value of component label is associated with the changed vm.message property, so it loads data from the property vm.message and update the label's value attribute. The new message "Hello World!" is then shown on the screen and provide the visual feed back to the end user.
In this MVVM implementation with data binding system, the ViewModel refers none of the UI elements. It only exposes the message contents and provides the necessary action logic required. The ViewModel knows nothing about how these information or action logic will be used. It is the UI designer's job to decide which UI components to use in which layout.
The example revised
Say, after you demonstrated the program to the customer and he/she said, "Well, I thought the Hello World! message shall be in a pop up window...".
No problem, let's prepare a modal window and puts the message in the modal window. Easy. Here is the revised MVP implementation.
helloMVP2.zul
<window apply="test.hello.HelloComposer2">
<button id="btn" label="Show"/>
<window id="win" title="Hello" width="300px" height="200px" visible="false">
<hbox align="center" pack="center" hflex="true" vflex="true">
<label id="lbl"/>
</hbox>
</window>
</window>
HelloComposer2.java
public class HelloComposer2 extends GenericForwardComposer {
private Label win$lbl;
private Button btn;
private Window win;
public void onClick$btn(Event event) {
win$lbl.setValue("Hello World!");
win.doModal();
}
}
Both the View zul file and the Controller has to be revised. This time, it injects the pop up window win and so on because the View has changed.
Then how about the revised MVVM implementation? helloMVVM2.zul
<window apply="test.hello.HelloViewModel">
<custom-attributes composerName="vm"/>
<button label="Show" onClick="@bind('showHello')"/>
<window title="Hello" width="300px" height="200px" mode="modal"
visible="@bind(not empty vm.message)">
<hbox align="center" pack="center" hflex="true" vflex="true">
<label value="@bind(vm.message)"/>
</hbox>
</window>
</window>
The advantages of using MVVM design pattern shows up when customers change their requirements on the View. UI Designer can proceed the change independently and the ViewModel does not have to be changed because what the customer required to change was the way to show an information not the information itself. Notice that here we control the show/hide of the modal window per the "message" is empty or not.
ZK Bind Features
To make ZK Bind as easy to use as possible, we have implement many features. We will cover such features one by one in the coming articles with proper examples commonly seen in real world applications. Here is a brief feature list:
- One way binding in either way
- Save only:
<textbox value=“@bind(save=a.b.c)”/>
- Load only:
<textbox value=“@bind(load=a.b.c)”/>
- Save only:
- Two way binding
<textbox value=“@bind(a.b.c)”/>
- Template binding
<template name=“model” var=“p”>
� <listitem label=“@bind(p.firstname)”/>
�</template>
- Form binding
<grid self=“@form(id=‘fx’, save=vm.currentTask before ‘updateTask’)”/>
Conditional binding: binding on different commands
<grid self=“@form(id=‘fx’, save={vm.currentTask before ‘updateTask’, vm.newTask before ‘addTask’})”/>
- EL 2.2 powered
<image src=“@bind(person.boy ? ‘boy.png’ : ‘girl.png’)/>
<button onClick=“@bind(vm.add ? ‘add’ : ‘update’)” />
<button disabled=“@bind(empty vm.symbol)”/>
- Java annotated property dependency (in View-Model)
@NotifyChange
public void setFirstname(String firstname) {
this.firstname = firstname;
}
@DependsOn({"firstname", "lastname"})
public String getFullname() {
return firstname + " " + lastname;
}
Summary
In this article, I have mentioned the design pattern MVVM and its advantages. I also scratch the basic operations of our new generation of data binding system for ZK, the ZK Bind. The On Demand Hello World example somehow presents the basic idea of MVVM and how ZK Bind works but might be too simiple to be a good one in real world. I will address more functions of the ZK Bind with more examples in following series of articles including the concepts of conditional binding, form binding, template binding, and separation of loading and saving, etc.. Stay tuned.
Download
Comments
Copyright © Potix Corporation. This article is licensed under GNU Free Documentation License. |