ZK Model-View-ViewModel (MVVM)

ZK supports the Model-View-ViewModel (MVVM) design pattern which automates the data-binding tasks that developers would have to otherwise implement in a traditional controller. This pattern divides an application into three parts.

.The Model consists of application data and business rules.
.The View means user interface. The zul page which contains ZK components represents this part. An user's interaction with components triggers events to be sent to controllers.
.The ViewModel is type of View abstraction which contains a View's state and behavior. It is responsible for exposing data from the Model to the View and providing required action requested from the View
.There is a binder in ZK which synchronizes data between ViewModel and View and handle events automatically according to your data binding expressions. You don't need to control components by yourself.


1.A user clicks "Search" button and a corresponding event is sent.
2.ZK's binder invokes the corresponding command method in the ViewModel.
3.The method accesses data from Model and updates some ViewModel's properties.
4.ZK's binder reloads changed properties from the ViewModel to update component's states.


Write a ViewModel:
ViewModel is an abstraction of View. Therefore when we design a ViewModel, we should analyse UI's functions for what states it contains and what behaviours it has. In the ViewModel of this demo, which contains the state : keyword, car list, selected car and behavior search

public class SearchViewModel{
     
    private String keyword;
    private List<Car> carList;
    private Car selectedCar;
 
    public void search(){
        ...
    }
    //getter & setter ...
}
Annotate the command method :
Any behaviour which can be requested by a View is a command in a ViewModel, you should apply an annotation @Command on the behaviour method (also called command method). After the execution of the command method, a ViewModel annotated with @NotifyChange would reflect the state changes made in View.
public class SearchViewModel{
    ... 
    @Command
    @NotifyChange("carList")
    public void search(){
        carList = carService.search(keyword);
    }
}
Bind View to ViewModel :
To bind View to a ViewModel, you should apply a composer called org.zkoss.bind.BindComposer, and use @id('VMID') @init('FULL.QUALIFIED.CLASSNAME') syntax in viewModel attribute. @id() is used to set ViewModel's id to an arbitrary variable name of your choice. You will use this id to reference ViewModel's properties. @init() is used to initialize the ViewModel object.
<window apply="org.zkoss.bind.BindComposer"
    viewModel="@id('vm') @init('demo.getting_started.mvvm.SearchViewModel')">
    ...
</window>
Bind attribute with property :
To bind a component attribute to a property of ViewModel, you use @bind(VMID.PROPERTY_NAME) on the attribute of component.
<textbox value="@bind(vm.keyword)" />
Bind event with command :
To bind a component event to a command of ViewModel, you use @command('COMMAND_NAME') on the event of component.
<button label="Search" onClick="@command('search')" />


View
<window title="Search" width="600px" border="normal" apply="org.zkoss.bind.BindComposer"
    viewModel="@id('vm') @init('demo.getting_started.mvvm.SearchViewModel')">
    <hbox align="center">
        Keyword:
        <textbox value="@bind(vm.keyword)" />
        <button label="Search" image="/widgets/getting_started/img/search.png" onClick="@command('search')" />
    </hbox>
    <listbox height="160px" model="@bind(vm.carList)" emptyMessage="No car found in the result"
    selectedItem="@bind(vm.selectedCar)" style="margin-top:10px">
        <listhead>
            <listheader label="Model" />
            <listheader label="Make" />
            <listheader label="Price" width="20%"/>
        </listhead>
        <template name="model">
            <listitem>
                <listcell label="@bind(each.model)"></listcell>
                <listcell label="@bind(each.make)"></listcell>
                <listcell>$<label value="@bind(each.price)" /></listcell>
            </listitem>
        </template>
    </listbox>
    <hbox style="margin-top:20px" visible="@bind(not empty vm.selectedCar)">
        <image src="@bind(vm.selectedCar.preview)" style="padding:10px" />
        <vbox>
            <hlayout>
                Model : <label value="@bind(vm.selectedCar.model)" style="font-weight:bold"/>
            </hlayout>
            <hlayout>
                Make : <label value="@bind(vm.selectedCar.make)" style="font-weight:bold"/>
            </hlayout>
            <hlayout>
                Price : 
                <span>$<label value="@bind(vm.selectedCar.price)" style="font-weight:bold"/></span>
            </hlayout>
            <label value="@bind(vm.selectedCar.description)" />
        </vbox>
    </hbox>
</window>
ViewModel
package demo.getting_started.mvvm;
 
import java.util.List;
 
import org.zkoss.bind.annotation.Command;
import org.zkoss.bind.annotation.NotifyChange;
 
import demo.getting_started.tutorial.Car;
import demo.getting_started.tutorial.CarService;
import demo.getting_started.tutorial.CarServiceImpl;
 
public class SearchViewModel {
     
    private String keyword;
    private List<Car> carList;
    private Car selectedCar;
     
    private CarService carService = new CarServiceImpl();
     
    public void setKeyword(String keyword) {
        this.keyword = keyword;
    }
    public String getKeyword() {
        return keyword;
    }
 
    public List<Car> getCarList(){
        return carList;
    }
     
         
    public void setSelectedCar(Car selectedCar) {
        this.selectedCar = selectedCar;
    }
    public Car getSelectedCar() {
        return selectedCar;
    }
 
     
    @Command
    @NotifyChange("carList")
    public void search(){
        carList = carService.search(keyword);
    }
}
Model

package demo.getting_started.tutorial;
 
public class Car {
 
    private Integer id;
    private String model;
    private String make;
    private String preview;
    private String description;
    private Integer price;
 
    public Car() {
    }
 
    public Car(Integer id, String model, String make, String description, String preview, Integer price) {
        this.id = id;
        this.model = model;
        this.make = make;
        this.preview = preview;
        this.description = description;
        this.price = price;
    }
 
    public Integer getId() {
        return id;
    }
 
    public void setId(Integer id) {
        this.id = id;
    }
 
    public String getMake() {
        return make;
    }
 
    public void setMake(String make) {
        this.make = make;
    }
 
    public String getPreview() {
        return preview;
    }
 
    public void setPreview(String preview) {
        this.preview = preview;
    }
 
    public String getDescription() {
        return description;
    }
 
    public void setDescription(String description) {
        this.description = description;
    }
 
    public Integer getPrice() {
        return price;
    }
 
    public void setPrice(Integer price) {
        this.price = price;
    }
 
    public String getModel() {
        return model;
    }
 
    public void setModel(String model) {
        this.model = model;
    }
}
package demo.getting_started.tutorial;
 
import java.util.List;
 
public interface CarService {
 
    /**
     * Retrieve all cars in the catalog.
     * @return all cars
     */
    public List<Car> findAll();
     
    /**
     * search cars according to keyword in name and company.
     * @param keyword for search
     * @return list of car that match the keyword
     */
    public List<Car> search(String keyword);
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值