Showing posts with label MVC. Show all posts
Showing posts with label MVC. Show all posts

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

Sunday, March 18, 2012

jQuery Selector Inspired Controller in ZK 6's MVC Pattern

The MVC pattern is adopted pervasively among Web frameworks. Various flavours exist for the pattern but the common goal is to achieve separation of concerns.

Under the ZK framework, MVC implementation ultimately requires the Controller to gain reference to, and listen events coming from, the UI components in View. An interesting bit of ZK 6's MVC pattern is the CSS/jQuery Selector inspired mechanism in its Controller that makes this plumbing task simpler and more flexible.

ZK Primer


In simplicity, ZK is a component based and event driven Ajax Java framework. Understanding this basic description alone is enough to take us through its MVC pattern.

Component based

A component either declared in XML or in Java has its state maintained as a POJO in the JVM. A component is then rendered with a set of JavaScript instructions at client side.


Event Driven

Each UI component can listen to event(s). There's a variety of ways to register event listeners to the components.
Just to name a few here,
in XML:
<button onclick="...">
</button>
in Java:
Button btn = new Button();
btn.addEventListener("onClick", new EventListener(){...});       

MVC Nomenclature in ZK

The component declarations make up the View. Although it's possible to construct the UI in Java, akin to GWT or Swing, most would prefer writing mark-up in XML. A ZUL in ZK is an XML compliant page that contains the UI mark-up. One can consider a ZUL page as an Ajax enabled JSP page.

The Controller in ZK is a Java class that implements the Composer interface or extends any one of Composer's implementations. SelectorComposer is the target of our investigation in this post.

Selector Inspired Controller in Action


Consider a simple window that prompts a user to enter her name, email address, and select the journal she'd like to subscribe:

We'll examine how the server-side selector mechanism works in our controller class as we implement the following features:
  1. Displaying a list of the available journals for subscription in a combo box
  2. Clear all fields in this simple form when the "Clear" button is clicked

Let's first see the components in mark-up which our controller will work with:
<grid apply="lab.zkoss.mvc.SubscriptionComposer">
        ...
    <rows>
        <row>
            <label value="User Name"/>
            <textbox mold="rounded"/> 
        </row>
        <row>
            <label value="email"/>
            <textbox mold="rounded"/> 
        </row>
        <row>
            <cell ...>
                <label value="Please subscribe me to "></label>
                <combobox model="${journalListModel}">
                    <template name="model">
                       <comboitem label="${each.title}"/>
                    </template>
                </combobox>
            </cell>
        </row>
        <row>
            <cell ...>
                <button label="Clear" ..."/>
                <button label="Submit" ..."/>
            </cell>
        </row>
        </rows>
</grid>

In our controller class, to implement the said features under the ZK framework, we'd need to gain reference to the UI components so the list of available journals can be rendered in the combo box and the onClick event for the Clear button can be handled.

public class SubscriptionComposer extends SelectorComposer{

 @Wire("combobox")
 Combobox journalbox;

 @Wire("textbox, combobox")
 List<InputElement> inputs;
 
 
 public void doAfterCompose(Component comp) throws Exception{ 
  super.doAfterCompose(comp);
  JournalDAO jdao = new JournalDAO();
  List<Journal> journalList = jdao.findAll();
  ListModelList journalListModel = new ListModelList(journalList);
  journalbox.setModel(journalListModel);
  
 }
 
 @Listen("onClick = button[label='Clear']")
 public void clearAll(){
  for(InputElement i:inputs) i.setText("");
 }
}
Let's elaborate on how selectors are used.

The Controller's Scope

When a controller is "applied" to a component, all of the component's children components also become accessible to the controller. 

In our implementation, the grid component is applied with our controller:
<grid apply="lab.zkoss.mvc.SubscriptionComposer">
...
</grid>
Hence the grid and all of its children components define the scope which our controller SubscriptionComposer can take effect.

Component Wiring

The @Wire annotation on line 3 and 6 take in a CSS selector pattern as its parameter. With the pattern "combobox, the annotation associates the sole combo box in our UI mark-up with the Combobox instance, journalbox declared in the controller class.
One of the many alternatives to achieve the same exact wiring is to give the Combox an ID, for instance:

<combobox id="thisworks2">
...
</combobox>
and the parameter for the annotation would be:
@Wire("#thisworks2")
Combobox journalbox;

Component Initialization

Once we've obtained references to the UI components in View, we could initialize them accordingly.
The doAfterCompose method allows developers to insert instructions to be executed right after the component under effect and its children are created. It's a method invoked by the framework and must be implemented for all classes implementing the Composer interface; such as the SelectorComposer class which we're extending our SubscriptionComposer from.

For our hypothetical feature, we need to initialize our combo box by populating it with a list of journals available for subscription.
@Wire("combobox")
 Combobox journalbox;

 ...
 
 public void doAfterCompose(Component comp) throws Exception{ 
  super.doAfterCompose(comp);
  JournalDAO jdao = new JournalDAO();
  List<Journal> journalList = jdao.findAll();
  ListModelList<Journal> journalListModel = new ListModelList(journalList);
  journalbox.setModel(journalListModel);
  
 }

On line 11, the combo box which we obtained reference to via the selector mechanism, is given the model data we prepared on line 10. ListModelList is a wraper class that enables changes made in its wrapped collection to be updated on its host UI component accordingly.

<combobox model="${journalListModel}">
        <template name="model">
            <comboitem label="${each.title}"/>
        </template>
    </combobox>

Once the combo box is supplied with a list model, the template tag will iteratively create a combo item for each entry in the list model.

Event Listening

The @Listen annotation adds method clearAll, as an event listener for the onClick event, to the button matching the pattern button[label="Clear"].

@Wire("textbox, combobox")
 List<InputElement> inputs;
 
 @Listen("onClick = button[label='Clear']")
 public void clearAll(){
  for(InputElement i:inputs) i.setText("");
 }


As before, there're many alternatives to the selector pattern shown here. One possibility is cell:first-child button, since the "Clear" button is the only component that matches this pattern.

<cell ...>
        <button label="Clear" ..."/>
        <button label="Submit" ..."/>
    </cell>

The brevity of the clearAll method is made possible because a single annotation @Wire("textbox, combobox") in fact wired all fields in the UI to a list of ZK components.

In a Nutshell


In a typical ZK controller class implementation, before we can initialize a UI component, listen to its events, or change its state, we must first obtain a reference to that component.
This CSS/jQuery selector inspired controller gives us great flexibility in referencing the UI components of interest. A reference can be made by matching a component's ID, class name, component attributes, or by traversing through the component tree.
With this flexibility, changes made in the UI cause us minimum grief since the controller code can be updated as easily as coming up with new selector patterns.

References

ZK SmallTalks
ZK Developer's Reference