Showing posts with label Binder. Show all posts
Showing posts with label Binder. Show all posts

Monday, June 11, 2012

ZK in Action [2] : MVVM - Update View Programmatically

In the previous 2 posts we've used ZK's MVVM functionalities to:

We've seen when a method is decorated with the annotation @NotifyChange(), upon its execution completes, the Binder would be informed of the VM property's changes so that Binder can update the corresponding UI accordingly. 

In this post, whilst we implement the functionality of item deletion in our inventory, we'll see how we can update UI components programmatically at runtime.

Objective

Build a delete function to our simple inventory CRUD feature.

Select Item in Table, Click "Delete", Confirm Deletion


ZK Feature in Action


  • MVVM : BindUtils

Implement Deletion with MVVM BindUtils

We will:
  • Add markup for the delete button and assign it an onClick event handler
  • Implement command method "deleteItem()" in VM

The Markup
<window apply="org.zkoss.bind.BindComposer" 
 viewModel="@id('vm') @init('...InventoryVM')">
 <toolbar  width="100%">
  <toolbarbutton label="Add" onClick="@command('createNewItem')" />
  <toolbarbutton label="Delete" onClick="@command('deleteItem')" disabled="@load(empty vm.selected)"/>
 </toolbar>

  • line 5, assign a command method "deleteItem" to the delete button's onClick handler
  • line 5, "disabled="@(empty vm.selected)"" ensures that the delete button is functional only if an entry in the table has been selected



The ViewModel Class

public class InventoryVM {

    private Item selected;
    private List<Item> items;
    ...

    @Command
    public void deleteItem() throws Exception{
        if (selected != null){
            String str = "The item with name \""
                         +selected.getName()
                         +"\" and model \""
                         +selected.getModel()
                         +"\" will be deleted.";

        Messagebox.show(str,"Confirm Deletion", Messagebox.OK|Messagebox.CANCEL, Messagebox.QUESTION, 
            new EventListener<event>(){
                @Override
                public void onEvent(Event event) throws Exception {
                    if (event.getName().equals("onOK")){
                        DataService.getInstance().deleteItem(selected);
                        items = getItems();
                        BindUtils.postNotifyChange(null, null, InventoryVM.this, "items");
                    }); 
                } ...
    }
    ...
}

  • line 7, we decorate our deleteItem method with @Command so it can be wired as the onClick event handler in our added markup:
    <toolbarbutton label="Delete" onClick="@command('deleteItem')" />;
  • line 9, we go ahead with the deletion process only if an item is selected.
  • line 16, we show a Messagebox which prompts the user to confirm the deletion of the selected item.
  • line 20, if user clicks "OK", our program proceeds to delete the selected item.
  • line 23, we call BindUtils.postNotifyChange(String queueName, String queueScope, Object bean, String property) to update our inventory table. By giving the parameter queueScope a null value, the default desktop queue scope is used. The third and forth argument are given as such since we want to notify the Binder that property "items" in our InventoryVM instance has changed. The Binder would then update the UI (remove the item entry in the inventory table).

Wrap Up

The @NotifyChange annotation lets us update the UI through ZK MVVM's Binder to reflect changes made to the ViewModel properties. The notification is fired when the annotated method finishes executing. In our implementation, we attached an anonymous event listener class to a Messagebox. In this case, after deleteItem is executed, the annotation @NotifyChange("items") would falsely alert the Binder before the event handling is completed. A programmatic way to reflect state changes in ViewModel to the UI resolves this particular problem conveniently.

Next up, editing the entries with MVVM.

Reference

ZK Deverloper Reference

Thursday, May 31, 2012

ZK in Action [1] : MVVM - Form Binding

This is the second episode in our efforts to build a ZK application from the ground up. The previous post dealt with loading and rendering of data into a table using MVVM. In this post, we'll be introduced to ZK MVVM's form binding.

Objective

We'll build an "Add" function that would enable us to save new entries to the inventory.

A Form Appears When "Add" is Clicked


New Entry is Added When "Save" is Clicked


ZK Features in Action

  • MVVM : Save, Form Binding, Conditional Binding

Add New Entries with MVVM Form Binding

we'll need to implement these parts:
  • Enhance our ViewModel POJO
  • Add UI markup to present a form and decorate the markup with the appropriate annotations
The ViewModel Class
public class InventoryVM {

    private List<item> items;
    private Item newItem;
 
    @NotifyChange("newItem")
    @Command
    public void createNewItem(){
        newItem = new Item("", "",0, 0,new Date());
    }
 
    @NotifyChange({"newItem","items"})
    @Command
    public void saveItem() throws Exception{
        DataService.getInstance().saveItem(newItem);
        newItem = null;
        items = getItems();
    }
  
    @NotifyChange("newItem")
    @Command
    public void cancelSave() throws Exception{
        newItem = null;
    }
 
    public List<item> getItems() throws Exception{
        items = DataService.getInstance().getAllItems();
        return items;
        }
    }

  • Line 4, we declare an Item object named newItem which will reference the Item instance to be saved to the database.
  • Line 6, @NotifyChange informs the binder to update the UI on the state of the associated ViewModel's property.
    In our UI markup shown below, at line 8, we have a Groupbox annotated with visible="@load(not empty vm.newItem), hence the Groupbox will become visible once createNewItem assigns an instance of Item to newItem.
    Simply put, @NotifyChange refreshes the UI with respect to the updates on ViewModel's properties.
  • Line 7, we annotate the createNewItem method with @Command and in our UI markup shown below, at line 4, we have a Toolbarbutton with onClick="@commnad(createNewItem)". So when the Toolbarbutton is clicked, the createNewItem method will be invoked.
  • Similarly, from line 12 to 18, we have a saveItem method which is called when its corresponding onClick event is triggered. Once the new Item object is saved to the database cache, we reset the newItem to null and retrieve the new list of items. The changes made to the ViewModel properties newItem (now null again) and items (now with an extra entry) are reflected to the UI using @NotifyChange as before.


The Markup
<window apply="org.zkoss.bind.BindComposer" 
 viewModel="@id('vm') @init('lab.sphota.zk.ctrl.InventoryVM')">
<toolbar>
 <toolbarbutton label="Add" onClick="@command('createNewItem')" />
</toolbar>
<groupbox form="@id('itm') @load(vm.newItem) 
        @save(vm.newItem, before='saveItem')"
 visible="@load(not empty vm.newItem)">
 <caption label="New Item"></caption>
 <grid width="50%">
  <rows>
   <row>
    <label value="Item Name" width="100px"></label>
    <textbox id="name" value="@bind(itm.name)" />
   </row>
   <row>
    <label value="Model" width="100px"></label>
    <textbox value="@bind(itm.model)" />
   </row>
   <row>
    <label value="Unit Price" width="100px"></label>
    <decimalbox value="@bind(itm.price)" format="#,###.00"
     constraint="no empty, no negative" />
   </row>
   <row>
    <label value="Quantity" width="100px"></label>
    <spinner value="@bind(itm.qty)"
     constraint="no empty,min 0 max 999: 
    Quantity Must be Greater Than Zero" />
   </row>
   <row>
    <cell colspan="2" align="center">
     <button width="80px" label="Save"
      onClick="@command('saveItem')" mold="trendy" />
     <button width="80px" label="Cancel"
      onClick="@command('cancelSave')" mold="trendy" />
    </cell>
   </row>
  </rows>
 </grid>
</groupbox>
<listbox>
...
</listbox>
</window>
  • Line 1, we apply ZK's default implementation of its BindComposer. It is responsible for instantiating our ViewModel and Binder instances.
  • Line 2, we supply the full class name of the ViewModel we wish to instantiate and give it an ID for future reference
  • Line 4, we assign our ViewModel's "command method" createNewItem as the onClick event handler for the toolbar button.
  • Line 6, the property newItem in ViewModel is made referenceable throughout the Groupbox using the ID "itm".
  • Line 6,7, by using form binding, to avoid invalid or incomplete data saved to the ViewModel property, entries in the form are saved to a temporary object until the command method saveItem is called.
  • Line 8, we show the Groupbox to enter a new Item entry only user has clicked the "Add" button; which in turn invokes createNewItem method and assigns the VM property newItem an instance of Item with default value(empty strings and 0s).
  • Line 14, 18, 22, 27, we bind the Item properties with the input elements. @bind is effectively equivalent to @load plus @save.

In a Nuteshell

To sum up in point form:

  • Using form binding avoids directly modifying data in ViewModel properties by saving form entries to a temporary object. Data is written to the ViewModel properties only if the condition specified is satisfied; in our example, only if the saveItem method is invoked. 
  •  @Command annotation allows the binder to map UI event handlers to ViewModel command methods.
  • @NotifyChange informs the binder which ViewModel properties had been modified after the command method is executed so changes in data can then be reflected on the UI.
  • We can assign values to any of UI components' attributes at run-time via MVVM binding to manipulate parameters such as visibility, style, disable/enable, etc.
In this post, we've not seen how data entries are validated. Before that, we'll implement the delete and edit functionalities in the next post.

Reference

ZK Developer Reference

Wednesday, May 30, 2012

ZK in Action [0] : MVVM - Load and Render Data

A previous post had briefly introduced the RIA framework ZK and how its CSS Selector inspired controller mechanism alleviates some of the burdens that comes with UI changes by making the task of referencing UI components in the controller class a relatively flexible affair.

We then explored how the MVVM patterns in ZK allows a single ViewModel to serve different views in the last post.

This post marks the beginning of a series of posts that will go through steps in building a simple application from the ground up using ZK.

Objective

For now, we'll build a simple inventory management feature which is limited only to the loading and rendering of a data collection from a database into a table.

ZK Features in Action

  • MVVM : Load
  • Template Tag

Load and Render Data into a Table with MVVM

Assume there's a collection of objects named "Item" and there's a DataService class which takes care of caching and communication with the database (MongoDB and Morphia).
@Entity("items")
public class Item {
 @Id
 private ObjectId id;
 
 private String name;
 private String model;
 private int qty;
 private float price;
 private Date datemod;
 
        // getters & setters

To render data into a table as shown below in ZK, we'll need to implement these parts:
  • A POJO that will serve as our ViewModel
  • A ZK markup file as our presentation

The ViewModel Class
public class InventoryVM {

    private List<item> items;
 
    public List<item> getItems() throws Exception{
        items = DataService.getInstance().getAllItems();
        return items;
        }
    }

  • Line 3,  the list of items needs to be declared as a property of the VM class
  • Line 5, we need to provide a getter method so the Binder can retrieve the list of items. To recap, the Binder holds reference to the UI components and the ViewModel so it can keep data on both sides in sync as well as call command methods in ViewModel as events are triggered in View.

The Markup
<window apply="org.zkoss.bind.BindComposer" 
 viewModel="@id('vm') @init('lab.sphota.zk.ctrl.InventoryVM')">
 <listbox model="@load(vm.items) ">
  <listhead>
   <listheader label="Name" />
   <listheader label="Model" />
   <listheader label="Quantity" />
   <listheader label="Unit Price"/>
   <listheader label="Last Modified" />
  </listhead>
  <template name="model" var="item" >
   <listitem>
    <listcell>
     <textbox value="@load(item.name)" inplace="true" />
    </listcell>
    <listcell>
     <textbox value="@load(item.model)" inplace="true" />
    </listcell>
    <listcell>
     <spinner value="@load(item.qty)"  inplace="true" />
    </listcell>
    <listcell>
     <decimalbox value="@load(item.price)" inplace="true" 
     format="#,###.00"/>
    </listcell>
    <listcell label="@load(item.datemod)" />
   </listitem>
  </template>
 </listbox>
</window>

  • Line 1, we apply ZK's default implementation of its BindComposer. It is responsible for instantiating our VM instance as well as the Binder instance.
  • Line 2, we supply the full class name of the ViewModel we wish to instantiate and give it an ID (in this case, 'vm') for future reference
  • Line 3, we assign a data model, which we made as a property of our ViewModel instance, to the Listbox.
  • Line 11, we instruct the Template component to iterate through the given collection. We also declare a variable called "item" which will iteratively take on each Item object inside our collection. Alternatively, we can omit the variable declaration and use the keyword "each" to reference the data object (Item).
  • Line 14, 17, 20, 23, 26, we retrieve the Item properties which we'd like to be displayed in the Listbox.
  • Here we use input elements (Textbox, Spinner, Decimalbox) inside the Listcells in anticipation of our future implementation of an editable table. The attribute "inplace=true" will render these input elements as regular labels while they're not selected.

Wrap Up

ZK Binder is central to the workings of ZK MVVM. It holds references to both the UI components and the ViewModel. The ViewModel class is just a POJO where we declare and assign our data models. It exposes getter methods so Binder can retrieve and bind data to their respective annotated UI components. The template tag then allows us to iteratively render UI components with respect to the data model. In our case, a row of 5 Listcells with each cell holding a bean property is rendered iteratively through the bean collection using the template tag.

In the next post, we'll implement an "Add" feature so we can save new entries to our existing inventory using MVVM's form binding.

Reference

ZK Developer Reference

Monday, April 30, 2012

A First Look at MVVM in ZK 6

MVVM vs. MVC

In a previous post we've seen how the Ajax framework ZK adopts a CSS selector inspired Controller for wiring UI components in View and listening to their events. Under this ZK MVC pattern, the UI components in View need not to be bound to any Controller methods or data objects. The flexibility of using selector patterns as a mean to map View states and events to the Controller makes code more adaptive to change.

MVVM approaches separation of concern in a reverse direction. Under this pattern, a View-Model and a binder mechanism take place of the Controller. The binder maps requests from View to action logic in View-Model and updates any value (data) on both sides, allowing the View-Model to be independent of any particular View.

Anatomy of MVVM in ZK 6

The below is a schematic diagram of ZK 6's MVVM pattern:
Here are some additional points that's not conveyed in the diagram:
BindComposer:
  • implements ZK's standard controller interfaces (Composer & ComposerExt)
  • the default implementation is sufficient, no modifications necessary
View:
  • informs binder which method to call and what properties to update on the View-Model
View-Model:
  • just a POJO
  • communication with the binder is carried out via Java Annotation

MVVM in Action

Consider the task of displaying a simplified inventory without knowledge of the exact UI markup. An inventory is a collection of items, so we have the object representation of such:

public class Item {
 private String ID;
 private String name;
 private int quantity;
 private BigDecimal unitPrice;

        //getters & setters
}

It also makes sense to expect that an item on the list can be selected and operated on. Thus based on our knowledge and assumptions so far, we can go ahead and implement the View-Model.

public class InventoryVM {
 
    ListModelList<Item> inventory;
    Item selectedItem;
  
    public ListModelList<Item> getInventory(){
        inventory = new ListModelList<Item>(InventoryDAO.getInventory());
        return inventory;
    }

    public Item getSelectedItem() {
        return selectedItem;
    }
 
    public void setSelectedItem(Item selectedItem) {
        this.selectedItem = selectedItem;
    }

}   

Here we have a typical POJO for the View-Model implementation, data with their getters and setter.

View Implementation, "Take One"

Now suppose we later learned the requirements for the View is just a simple tabular display:

A possible mark-up to achieve the UI as indicated above is:
<window title="Inventory" border="normal" apply="org.zkoss.bind.BindComposer" 
 viewModel="@id('vm') @init('lab.zkoss.mvvm.ctrl.InventoryVM')" >
 <listbox model="@load(vm.inventory)" width="600px" >
  <auxhead><auxheader label="Inventory Summary" colspan="5" align="center"/> </auxhead>
  <listhead>
   <listheader width="15%" label="Item ID" sort="auto(ID)"/>
   <listheader width="20%" label="Name" sort="auto(name)"/>
   <listheader width="20%" label="Quantity" sort="auto(quantity)"/>
   <listheader width="20%" label="Unit Price" sort="auto(unitPrice)"/>
   <listheader width="25%" label="Net Value"/>
  </listhead>
  <template name="model" var="item">
   <listitem>
    <listcell><label value="@load(item.ID)"/></listcell>
    <listcell><label value="@load(item.name)"/></listcell>
    <listcell><label value="@load(item.quantity)"/></listcell>
    <listcell><label value="@load(item.unitPrice)"/></listcell>
    <listcell><label value="@load(item.unitPrice * item.quantity)"/></listcell>
   </listitem> 
  </template>
 </listbox>
</window>

Let's elaborate a bit on the mark-up here.

  • At line 1, we apply the default BindComposer to the Window component which makes all children components of the Window subject to the BindComposer's effect.
  • On the following line, we instruct the BindComposer which View-Model class to instantiate and we give the View-Model instance an ID so we could make reference to it.
  • Since we're loading a collection of data onto the Listbox, at line 3 we assign the property "inventory" of our View-Model instance, which is a collection of the Item objects, to Listbox's attribute "model". 
  • At line 12, we then make use of the model on our Template component. Template iterates its enclosed components according to the model it receives. In this case, we have 5 list items which makes up a row in the Listbox. 
  • In each Listcell, we load the properties of each object and display them in Labels.
Via ZK's binding system, we were able to access data in our View-Model instance and load them in View using annotations.

View Implementation, "Take Two"

Suppose later in development, it's agreed that the current tabular display takes too much space in our presentation and we're now asked to show the details of an item only when the item is selected in a Combobox, as shown below:


Though both the presentation and behaviour(detail is shown only upon user's selection) differ from our previous implementation, the View-Model class needs not be heavily modified. Since an item's detail will be rendered only when it is selected in the Combobox, it's obvious that we'd need to handle the "onSelect" event, let's add a new method doSelect:
public class InventoryVM {
 
    ListModelList<Item> inventory;
    Item selectedItem;

    @NotifyChange("selectedItem")
    @Command
    public void doSelect(){ }
    
    //getters & setters

}

A method annotated with @Command makes it eligible to be called from our mark-up by its name, in our case:

<combobox onSelect="@command('doSelect')" >

The annotation @NotifyChange("selectedItem") allows the property selectedItem to be updated automatically whenever user selects a new Item from the Combobox. For our purposes, no addition implementation is needed for the method doSelect. With this bit of change done, we can now see how this slightly-modified View-Model would work with our new mark-up:

<window title="Inventory" border="normal" apply="org.zkoss.bind.BindComposer" 
 viewModel="@id('vm') @init('lab.zkoss.mvvm.ctrl.InventoryVM')" width="600px">
 ...
  <combobox model="@load(vm.inventory)" 
     selectedItem="@bind(vm.selectedItem)" 
      onSelect="@command('doSelect')" >
   <template name="model" var="item">
    <comboitem label="@load(item.ID)"/>
   </template>
   <comboitem label="Test"/>
  </combobox>
  <listbox  visible="@load(not empty vm.selectedItem)" width="240px">
   <listhead>
    <listheader ></listheader>
    <listheader ></listheader>
   </listhead>
   <listitem>
    <listcell>
     <label value="Item Name: " />
    </listcell>
    <listcell>
     <label value="@load(vm.selectedItem.name)" />
    </listcell>
   </listitem>
   <listitem>
    <listcell>
     <label value="Unit Price: " />
    </listcell>
    <listcell>
     <label value="@load(vm.selectedItem.unitPrice)" />
    </listcell>
   </listitem>
   <listitem>
    <listcell>
     <label value="Units in Stock: " />
    </listcell>
    <listcell>
     <label value="@load(vm.selectedItem.quantity)" />
    </listcell>
   </listitem>
   <listitem>
    <listcell>
     <label value="Net Value: " />
    </listcell>
    <listcell>
     <label value="@load(vm.selectedItem.unitPrice * vm.selectedItem.quantity)" />
    </listcell>
   </listitem>
  </listbox>
 ...
</window>


  • At line 4, we load the data collection inventory to the Combobox's model attribute so it can iteratively display the ID for each Item object in the data model using the Template component declared on line 7. 
  • At line 5, the selectedItem attribute points to the most recently selected Item on that list of Item objects
  • At line 6, we've mapped the onSelect event to the View-Model's doSelect method
  • At line 12,  we make the Listbox containing an Item's detail visible only if the selectedItem property in View-Model is not empty (selectedItem will remain empty until an item is selected in the Combobox).
  • The selectedItem's properties are then loaded to fill out the Listbox.

Recap

Under the MVVM pattern, our View-Model class exposes its data and methods to the binder; there's no reference made to any particular View component. The View implementations access data or invoke event handlers via the binder.

In this post, we're only exposed to the fundamental workings of ZK's MVVM mechanisms. The binder is obviously not restricted to just loading data from the View-Model. In addition to saving data from View to ViewModel, we can also inject data converters and validators in the mix of View to View-Model communications. The MVVM pattern may also work in conjunction with the MVC model. That is, we can also wire components and listen to fired-events via the MVC Selector mechanism if we wish to do so.

We'll dig into some of these topics at a later time.

Reference

ZK Developer's Reference