Communication between ViewModel and Composer"

From Documentation
Line 4: Line 4:
  
  
Communication between a composer and a ViewModel is done by '''Global Command'''.
+
In order to understand the following paragraphs, you had better understand [[ZK Developer's Reference/MVVM/ViewModel/Commands#Global_Command | concept of global command]] and [[ZK Developer's Reference/MVVM/Data Binding/Global Command Binding| how to bind an event to it]].
 +
 
 +
The [[ZK Developer's Reference/MVVM/Data Binding/Global Command Binding#Usage | 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 =
 
=Posting a Command from a Composer to a ViewModel =
  
Composer doesn't have a Binder to send a global command for it,
+
We have already known that global command is triggered by [[ZK Developer's Reference/MVVM/Data Binding/Binder| binder sending events into event queue]]. Hence ViewModels can communicate each other by their own binders. But a composer doesn't have a binder to send a global command for it. Therefore, we provide a utility class, '''<javadoc> org.zkoss.bind.BindUtils </javadoc>''', that can do this job. You can use it in a composer.
To offer communication there needs to be a way for the MVC pattern bound section of the application to pass a command to the binder which will in turn talk to all the view models and tell them to run a particular command. This is achieved by posting a global command and works in a much similar way to the normal command system.
 
  
The example below shows a function which was taken from our SelectorComposer (MVC pattern) and shows the issuing of a global command. In the product view upon clicking of the add button will result in the execution of said function.
+
For example, after adding a product, you want to tell <tt> ShoppingCartViewModel </tt> to refresh shopping cart's items.
  
<source lang="java" high="17">
+
''' Send a global command in a composer (Sender)'''
@Listen("onAddProductOrder=#PrdoDiv #prodGrid row productOrder")
 
public void addProduct(Event fe) {
 
  
if (!(fe.getTarget() instanceof ProductOrder)) {
+
<source lang="java" high="8">
return;
+
 
}
+
public class MyComposer extends SelectorComposer{
 +
 
 +
@Listen("onAddProductOrder=#PrdoDiv #prodGrid row productOrder")
 +
public void addProduct(Event fe) {
  
ProductOrder po = (ProductOrder) fe.getTarget();
+
//business logic of adding a product
  
try {
+
BindUtils.postGlobalCommand(null, null, "updateShoppingCart", null);
UserUtils.getShoppingCart()
 
.add(po.getProduct(), po.getQuantity());
 
} catch (OverQuantityException e) {
 
po.setError(e.getMessage());
 
 
}
 
}
 
BindUtils.postGlobalCommand(null, null, "updateShoppingCart", null);
 
 
}
 
}
 
</source>
 
</source>
  
Line 17 shows the function "BindUtils" and its function "postGlobalCommand" is used to post a command to the binder. In this case the first two strings take the name of the binder and the scope of said binder, in this case it is set to null to use the default. In most cases one would want to set this to null. Then the string name for the command is given along with a map of arguments to pass, in this case null as there are no arguments.
+
* we use <tt> BindUtils.postGlobalCommand(String queueName, String queueScope, String cmdName, Map<java.lang.String,java.lang.Object> args) </tt> 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. (line 19)
  
This globalCommand is then executed by the binder on any view model that has registered for it. In the case of this application the ShoppingCartViewModel needs to refresh the cart items when a product is added to a cart. Therefore a function is created in the ShoppingCartViewModel and registered as a global command, this function has the ability to do some processing and then notify the binder that the cartItems in that view have changed. The snippet below shows this in action.
+
* The specified global command is then executed by all ViewModel's binders that have subscribed to the event queue in the same (desktop) scope.  
  
<source lang="java">
+
 
 +
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)'''
 +
 
 +
<source lang="java" high="5,7">
 
public class ShoppingCartViewModel {
 
public class ShoppingCartViewModel {
 
 
Line 46: Line 47:
 
@NotifyChange("cartItems")
 
@NotifyChange("cartItems")
 
public void updateShoppingCart() {
 
public void updateShoppingCart() {
//no post processing to be done
+
//update shopping cart
 
}
 
}
 
}
 
}
 
</source>
 
</source>
  
This takes care of passing commmands from the MVC composer to MVVM view model, the next section discusses message passing between MVVM view models.
+
 
  
  

Revision as of 07:51, 17 May 2012


DocumentationZK Developer's ReferenceMVVMAdvancedCommunication between ViewModel and Composer
Communication between ViewModel and Composer


WarningTriangle-32x32.png This page is under construction, so we cannot guarantee the accuracy of the content!


In order to understand the following paragraphs, you had better understand concept of global command and how to bind an event to it.

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 can communicate each other by their own binders. 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.

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. (line 19)
  • 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
	}
}



Posting a Command from a ViewModel to a Composer

Version History

Last Update : 2012/05/17


Version Date Content
6.0.0 May 2012 Supplement to advanced topic.




Last Update : 2012/05/17

Copyright © Potix Corporation. This article is licensed under GNU Free Documentation License.