Hello ZK MVVM"
Line 127: | Line 127: | ||
''View'': helloMVP2.zul | ''View'': helloMVP2.zul | ||
<source lang="xml"> | <source lang="xml"> | ||
− | <window apply=" | + | <window apply="HelloComposer2"> |
<button id="btn" label="Show"/> | <button id="btn" label="Show"/> | ||
<window id="popwin" title="Hello" width="300px" height="200px" visible="false"> | <window id="popwin" title="Hello" width="300px" height="200px" visible="false"> |
Revision as of 04:18, 21 October 2011
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 Model for View in MVC pattern which is responsible for exposing the data objects from the data 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 states and behaviors. From another angle, you can also say that the View layer is kind like an UI visual 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.
- It will be easier 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 the request 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.
View: helloMVP.zul
<window apply="HelloComposer">
<label id="lbl"/>
<button id="btn" label="Show"/>
</window>
Presenter: HelloComposer.java
public class HelloComposer extends GenericForwardComposer {
private Label lbl;
public void onClick$btn(Event event) {
lbl.setValue("Hello World!");
}
}
The Presenter was injected with the View components Label lbl and the event listener onClick$btn(). As you can see, the characteristic of MVP design pattern is that the Presenter(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.
- Binder then 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 method 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 property to save).
In ZK MVVM, we utilize the ZK Annotation(link) to do these jobs:
View: helloMVVM.zul
<window apply="BindComposer" viewModel="@bind(vm='HelloViewModel')">
<label value="@bind(vm.message)"/>
<button label="Show" onClick="@bind('showHello')"/>
</window>
ViewModel: HelloViewModel.java
public HelloViewModel {
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 that 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 HelloViewModel will be changed if calling this command.
- The binder then finds that the attribute value of component label is associated with the changed message property of the HelloViewModel(as specified in ZK annotation @bind(vm.message)). So it loads data from the property vm.message and updates 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 HelloViewModel is a simple POJO and refers none of the UI components. It only exposes the message contents via getMessage() and provides the necessary action logic showHello(). It does not know 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 just as seen in HelloMVVM.zul.
The example revised -- Pop Up the Message
Customers tend to change their mind when they see the real screen. 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.
Revised MVP Implementation
View: helloMVP2.zul
<window apply="HelloComposer2">
<button id="btn" label="Show"/>
<window id="popwin" title="Hello" width="300px" height="200px" visible="false">
<hbox align="center" pack="center" hflex="true" vflex="true">
<label id="lbl"/>
</hbox>
</window>
</window>
Presenter: HelloComposer2.java
public class HelloComposer2 extends GenericForwardComposer {
private Label popwin$lbl;
private Window popwin;
public void onClick$btn(Event event) {
popwin$lbl.setValue("Hello World!");
popwin.doModal();
}
}
The View zul file has to be revised and the Presenter java file has to be totally rewritten. This time, it injects the pop up window popwin, the label popwin$lbl inside the pop up window and so on because the View has changed.
Revised MVVM Implementation
View: 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 HelloViewModel java file does not have to be changed because what the customer required to change was the way to show the message not the message 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 implemented 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 Save direction only
<textbox value="@bind(save=a.b.c)"/>
- One way binding in Load direction only:
<textbox value="@bind(load=a.b.c)"/>
- Two way binding
<textbox value="@bind(a.b.c)"/>
- Template binding
<listbox model="@bind(vm.persons)" selectedItem="@bind(vm.selected)">
<template name="model" var="p">
<listitem label="@bind(p.firstname)"/>
</template>
</listbox>
- Form binding
<grid self="@form(id='fx', save=vm.currentTask before 'updateTask')">
<row><textbox value="@bind(fx.name)"/></row>
<row><textbox value="@bind(fx.description)"/></row>
<row><datebox value="@bind(fx.date) @converter('formatedDate', format='yyyy/MM/dd')"/></row>
</grid>
- Conditional binding: binding on different commands
<grid self="@form(id='fx', save={vm.currentTask before 'updateTask', vm.newTask before 'addTask'})">
<row><textbox value="@bind(fx.taskName)"/></row>
<row><textbox value="@bind(fx.description)"/></row>
<row><datebox value="@bind(fx.date) @converter('formatedDate', format='yyyy/MM/dd')"/></row>
</grid>
- 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 tracking (in ViewModel)
@NotifyChange
public void setFirstname(String firstname) {
this.firstname = firstname;
}
@NotifyChange
public void setLastname(String lastname) {
this.lastname = lastname;
}
@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. |