MVVM in ZK 6 - Design your first MVVM page
Dennis Chen, Senior Engineer, Potix Corporation
November 9, 2011
ZK 6
ZK 6 & MVVM
In ZK 6, we introduce a whole new data binding system called ZK Bind which is easy to use, flexible and supports MVVM development model. MVVM is an UI design pattern, similar to MVC, it represents Mode, View and ViewModel. The main concept of MVVM design pattern is to separate the data and logic from the presentation.
You can read ZK Bind's | introduction here. For a short to MVVM in ZK 6, please refer to | this article
In this article, I will use a real case to show how you can write your first MVVM page with some basic ZK Bind syntax.
Case scenario
I will use a search example to show how you can archive MVVM design pattern in ZK 6 by using ZK Bind. Please imagine yourself creating a search page in which the searching of an item is done by a filter string; the search result of items is displayed in a list and when selecting on an item, it will also show the details of the selected item.
Design the View Model
Follow the design concept of MVVM, we should design the view model first, we should not consider the visual effect. A view model should not depend on a View, but consider the data and actions as it contract for interacting with the View. In this scenario, we need a String as a filter and a ListModelList<Item> for the search result and a doSearch() method to perform the search command. Further, we also need a selected file to keep the item which is currently selected.
As you can see, I am defending a View Model and it is isolated from the View, which means that it is possible to be reused by another View and even tested by pure Java code. Following is the code of the View Model.
ViewModel : SearchVM.java
SearchVM is definitely a POJO, and because it is, we need to notify ZK Bind that the properties of this POJO were changed. In ZK Bind, it has the binder to help the binding between View and View Model. By adding @NotifyChange on a setter method of a property, after binder set the property, it is noticed to reload components that bind to this property. Add @NotifyChange on a command method, after Binder executes the method, it is noticed to reload components that bind to these properties.
For example, I add @NotifyChange on setFilter, when binder sets the value by setFilter(), it is noticed to reload any binding that is related to filter property of the view model. I also added @NotifyChange({“items”,”selected”}) on doSearch(), that is because when doing the search, I will search by the filter and has a new item list and also reset selected to null, so I need to notify Binder this 2 properties was changed.
With @NotifyChange, it let binder knows when to reload the view automatically.
Design a View with ZK Bind
After the View Mode is ready, we are now able to bind View to View Model, not only the data, but also the action, and reloading the changed data automatically (thanks the @NotifyChange in SearchVM).
Here is the designed View that will be use in this article to bind with View Model:
Apply the BindComposer
Now, we have to create a ‘search.zul’ and bind it to the View Model. To do this, set the ‘apply’ attribute to ‘org.zkoss.bind.BindComposer’ as the composer, and bind the ‘viewModel’ to ‘SearchVM’ that was just created. BindComposer will read all the ZK Bind syntax and create a binder to bind View and View model.
View : search.zul
The @bind(name=expression) here, is the syntax to assign a View Model to the binder, ‘name’ is the name of the View Model which will be referenced in nested binding. ‘expression’ is an EL 2.2 expression and there are some rules about this expression; if the evaluated result is a ‘String’, it uses ‘String’ as a class name to create the view model whereas if the result is a ‘Class’, it creates the View Model by ‘Class.newInstance()’. Moreover, if the result is a non-primitive Object then it will use it directly, other-wise, it complains an exception.
Binding the textbox with filter data
We need a textbox to represent the filter data, when user types in the textbox, the data will automatically update to ‘vm.filter’, and we also want the search button disabled if the value of ‘vm.filter’ is empty.
View : search.zul
The @bind(expression) here, is the two-way binding syntax to bind component’s attribute and the VM’s property together, it constructs a prompt binding, which means that the change of a component’s attribute caused by a user’s action will also be saved to the VM’s property. And any changed notification of the property will cause a reload of the component.
In the above example, I have binded the ‘vm.filter’ to the ‘value’ attribute of the textbox, and the ‘disabled’ attribute of the button. When editing the textbox, ‘vm.filter’ will be changed and the button will immediately be enabled or disabled depending on the value of ‘vm.filter’.
Binding the listbox with search result
In ZK 6, we introduce a new feature called ‘template’, it is a perfect matching when binding a collection. We will have a listbox and a template to show the search result.
View : search.zul
The @bind(expression) can also apply to ‘model’ attribute of a component. When binding to a model, we have to provide a template, which name is ‘model’, to render each item in the model. In the template, we have to set the name of ‘var’, so we could use it as an item in the template. We also introduce the @converter syntax, so you can write a ‘Converter’ to convert data to attribute when loading to component, and convert back when saving to bean.
In the above example, the ‘model’ of listbox binds to ‘vm.items’, and the ‘selectedItem’ binds to ‘vm.selected’ with a template that has responsibility to render each item of the ‘vm.items’. Of course, we could also use @bind in the template, even bind to a ‘sclass’ attribute of a listcell with a flexible expression ‘item.quantity lt 3?’red’:’’’. Look into ‘item.price’, it is a double, I want it to be shown with an expected format, therefore a built-in converter ‘formatedNumber’ and a format argument ‘###,##0.00’ are used.
Binding the selected item
When binding the listbox, we also bind the ‘selectedItem’ of listbox to ‘selected’ property of View Model. You do not need to worry about selectedItem(in which its value type is a Listitem) of listbox being the incorrect data type of the model because binder will convert it to item automatically. By the binding of ‘selectedItem’, when selecting an item in the listbox, the ‘selected’ property will be updated to the selected item and displayed in detail.
View : search.zul
In the example above, we bind ‘visible’ attribute of groupbox with the expression ‘not empty vm.selected’, so that the groupbox will only appear visible when user selects an item. Oppositely, if no item is selected, this groupbox will not show up. The @converter is used again here but with some differences. The converter now comes from the View Model . Of course, a ‘getTotalPriceConverter’ method needs to be prepared in View Model and return a Converter.
ViewModel : SearchVM.java
Binding the button action to a command
Now, we have to perform a command of the View Model when clicking on the search button. To do so, add a @bind in the onClick event of the button.
The @bind(expression) syntax in the event of a component represents the binding of an event to a command of the View Model. It has some rules.
- The evaluation result of the expression result has to be a ‘String’,
- The string must also be the name of the command
- View model must have an executable method that has the name of the command.
In the case above, onClick is binded with a ‘doSearch’ command. When clicking on the button, binder will go through the command lifecycle (we will talk about this in another smalltalk ,[link when ready]) and execute the doSearch method of view model.
Show case
[A flash viedo]
Various View
One of the advantages of MVVM is that the View Model is a contact class. It holds data, action and logic. This means, users are allowed to use various Views as long as the View can be applied to the View Model. Here is an example with various views, we can bind combox with ‘filter’, so users not only can type the text but also select by a pre-defended filter. Even on the action, it is also possible to redefine it to be performed when the filter is selected or changed.
ViewModel : SearchVM.java
Various View
One of the advantages of MVVM is that the View Model is a contact class. It holds data, action and logic. This means, users are allowed to use various Views as long as the View can be applied to the View Model. Here is an example with various views, we can bind combox with ‘filter’, so users not only can type the text but also select by a pre-defended filter. Even on the action, it is also possible to redefine it to be performed when the filter is selected or changed.
ViewModel : SearchVM.java
Test a view model
Since the View Model is definitely a POJO, it is also possible to do unit test on the View Model. Here is a very straight forward test case to test SearchVM.
TestCase : SearchVMTestCase.java
Of course, there will be problems in preparing the testing environment, for example, how to get the ‘SearchService’ that we are using in the example? However, this really depends on what container framework you use (for example, Spring, Seam or CDI) but this is not the topic of this article.
Syntax review
ZUL annotation syntax
Syntax | Explanation |
---|---|
viewModel=”@bind(name=expression)” | Sets the View Model
|
comp-attribute=”@bind(expression)” | Two-way binding between component’s attribute and the property of an expression.
|
@converter(expression, arg = arg-expression) | Provide a converter for a binding
|
comp-attribute=”@bind(expression)” | row 2, cell 2 |
comp-attribute=”@bind(expression)” | row 2, cell 2 |
comp-attribute=”@bind(expression)” | row 2, cell 2 |
Java syntax
Summary
In this article, the concept of designing a MVVM page was demonstrated, it is a good design pattern since users are allowed to design a View Model that is isolated from a View, and you only concert the data and the behavior making it possible to reuse this View Model with another view and can even perform a unit test of this View Model.
I also showed how ZK Bind helps you to accomplish MVVM with ZUL. With the power of ZK Bind you can easily bind ZUL to a View Model with well-defined annotation. There will be more upcoming articles discussing more about how MVVM works in ZK 6, before then, any feedback is always welcomed.
Downloads
Comments
Copyright © Potix Corporation. This article is licensed under GNU Free Documentation License. |