Communication between ViewModel and Composer
In order to understand the following paragraphs, you had better understand concept of global command and global command binding first.
The global command binding usage section demonstrates how to communicate between multiple ViewModels. We can also use the same mechanism to perform communication between a composer and a ViewModel, but usage is a little different.
Posting a Command from a Composer to a ViewModel
We have already known that global command is triggered by binder sending events into event queue. Hence ViewModels with attached binders can communicate each other by global command. But a composer doesn't have a binder to send a global command for it. Therefore, we provide a utility class, BindUtils, that can do this job. You can use it in a composer.
For example, after adding a product, you want to tell ShoppingCartViewModel to refresh shopping cart's items. Assume that we don't change default setting that ShoppingCartViewModel's binder (receiver) subscribes to default event queue.
Send a global command in a composer (Sender)
public class MyComposer extends SelectorComposer{
@Listen("onAddProductOrder=#PrdoDiv #prodGrid row productOrder")
public void addProduct(Event fe) {
//business logic of adding a product
BindUtils.postGlobalCommand(null, null, "updateShoppingCart", null);
}
}
- we use BindUtils.postGlobalCommand(String queueName, String queueScope, String cmdName, Map<java.lang.String,java.lang.Object> args) to post a command. We leave first two arguments as "null" to use default queue name and default scope (desktop). The third arguments is global command's name. You can send extra data with a Map by the fourth argument.
- The specified global command is then executed by all ViewModel's binders that have subscribed to the event queue in the same (desktop) scope.
In the ShoppingCartViewModel, we should declare a global command method named "updateShoppingCart" to receive this command request and refresh cart items. The code snippet below shows this.
Global command in a ViewModel (Receiver)
public class ShoppingCartViewModel {
...
@GlobalCommand
@NotifyChange("cartItems")
public void updateShoppingCart() {
//update shopping cart
}
}
- As a binder subscribes to desktop scope event queue by default, we only need to declare a global command.
Posting a Command from a ViewModel to a Composer
Because a ViewModel has a binder attached to it, triggering a global command doesn't need BindUtils. We just can use global command binding.
Assume that we want to inform a composer to update shopping cart's items.
Bind global command in a ZUL (Sender)
<window apply="org.zkoss.bind.BindComposer" binder="@init(queueName='myqueue')"
viewModel="@id('vm') @init('example.MyViewModel')" >
<button id="addProduct" label="Add" onClick="@global-command('updateShoppingCart')"/>
</window>
- We set the queue name as 'myqueue' that the binder publishes to.
As we mentioned before, global command is sent by event queue, the composer (receiver) should subscribe to the same scope event queue to receive this global command.
Subscribe to the event queue for the global command (Receiver)
public class MyComposesr extends SelectorComposer<Component>{
@Subscribe("myqueue")
public void updateShoppingCart(Event evt){
if(evt instanceof GlobalCommandEvent){
if("updateShoppingCart".equals(((GlobalCommandEvent)evt).getCommand())){
//update shopping cart's items
}
}
}
}
- Subscribe to a queue named 'myqueue' because previous binder publish to this queue.
- For @Subscribe , please refer to ZK Developer's Reference/MVC/Controller/Subscribe to EventQueues.
- To subscribe a event queue by method call, please refer to ZK Developer's Reference/Event Handling/Event Queues#Subscribe_to_an_Event_Queue
Version History
Version | Date | Content |
---|---|---|
6.0.0 | May 2012 | Supplement to advanced topic. |