Communication between ViewModel and Composer"

From Documentation
m ((via JWB))
 
(21 intermediate revisions by 4 users not shown)
Line 1: Line 1:
 
{{ZKDevelopersReferencePageHeader}}
 
{{ZKDevelopersReferencePageHeader}}
 +
{{Deprecated | url=[http://books.zkoss.org/zk-mvvm-book/8.0/advanced/communication_between_viewmodel_and_composer.html zk-mvvm-book/8.0/data_binding/advanced/communication_between_viewmodel_and_composer]|}}
  
{{Template:UnderConstruction}}
 
  
  
Communication between a composer and a ViewModel is done by '''Global Command'''.
+
To get an in-depth understanding of the following paragraphs, it is recommended that you have read and understood the [[ZK Developer's Reference/MVVM/ViewModel/Commands#Global_Command | concept of global command]] and [[ZK Developer's Reference/MVVM/Data Binding/Global Command Binding| global command binding]] prior reading this article.
 +
 
 +
The [[ZK Developer's Reference/MVVM/Data Binding/Global Command Binding#Usage | global command binding usage section]] demonstrates how you can communicate between multiple ViewModels. We can also use the same mechanism to perform communication between a composer and a ViewModel, but of course, 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 know that global command is triggered by [[ZK Developer's Reference/MVVM/Data Binding/Binder| binder sending events into event queue]], hence, ViewModels attached with binders are able to communicate with each other by global command. However, a composer doesn't have a binder to send a global command, 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.
+
 
 +
For example, after adding a product, you want to tell <code>ShoppingCartViewModel</code> to refresh shopping cart's items. Assuming that we do not change the default setting such that ShoppingCartViewModel's binder (receiver) subscribes to the default event queue.
 +
 
 +
''' Send a global command in a composer (Sender)'''
  
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.
+
<source lang="java" highlight="8">
  
<source lang="java" high="17">
+
public class MyComposer extends SelectorComposer{
@Listen("onAddProductOrder=#PrdoDiv #prodGrid row productOrder")
 
public void addProduct(Event fe) {
 
  
if (!(fe.getTarget() instanceof ProductOrder)) {
+
@Listen("onAddProductOrder=#PrdoDiv #prodGrid row productOrder")
return;
+
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 <code>BindUtils.postGlobalCommand(String queueName, String queueScope, String cmdName, Map<java.lang.String,java.lang.Object> args)</code> 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 parameters with a Map by the fourth argument.  
  
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 <b>ShoppingCartViewModel</b>, 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" highlight="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.
+
* As [[ZK Developer's Reference/MVVM/Data Binding/Binder|a binder subscribes to desktop scope event queue by default]], we only need to declare a global command.
  
 +
* To receive parameters with global command, please refer to [[ZK Developer's Reference/MVVM/Advance/Parameters#A_Global_Command_Example]].
  
 
=Posting a Command from a ViewModel to a Composer =
 
=Posting a Command from a ViewModel to a Composer =
  
 +
As a ViewModel has a binder attached to it, triggering a global command doesn't need <javadoc> org.zkoss.bind.BindUtils </javadoc>, we can simply use global command binding.
 +
 +
<!-- default name of event queue subscribed by the binder is DEFAULT_QUEUE_NAME = "$ZKBIND_DEFQUE$" which is too wired
 +
We specified another queue name.
 +
-->
 +
 +
Assuming that we want to inform a composer to update shopping cart's items.
 +
 +
'''Bind global command in a ZUL (Sender) '''
 +
 +
<source lang="xml" hign="4">
 +
 +
<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>
 +
 +
</source>
 +
* We set the queue name as 'myqueue' in which the binder publishes to.
 +
 +
As mentioned earlier, global command is sent by event queue, the composer (receiver) should subscribe to the same scope event queue to receive this global command.
  
 +
'''To subscribe global command (Receiver) to the event queue'''
 +
 +
<source lang="java" highlight="3">
 +
 +
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
 +
}
 +
}
 +
}
 +
}
 +
 +
</source>
 +
 +
* Subscribe to a queue named 'myqueue' because previous binder publishes to this queue.
 +
* For <code>@Subscribe</code>, please refer to [[ZK Developer's Reference/MVC/Controller/Subscribe to EventQueues]].
 +
* To subscribe an event queue by method call, please refer to [[ZK Developer's Reference/Event Handling/Event Queues#Subscribe_to_an_Event_Queue]]
  
 
=Version History=
 
=Version History=
{{LastUpdated}}
+
 
{| border='1px' | width="100%"
+
{| class='wikitable' | width="100%"
 
! Version !! Date !! Content
 
! Version !! Date !! Content
 
|-
 
|-

Latest revision as of 07:35, 8 July 2022


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


Stop.png This article is out of date, please refer to zk-mvvm-book/8.0/data_binding/advanced/communication_between_viewmodel_and_composer for more up to date information.


To get an in-depth understanding of the following paragraphs, it is recommended that you have read and understood the concept of global command and global command binding prior reading this article.

The global command binding usage section demonstrates how you can communicate between multiple ViewModels. We can also use the same mechanism to perform communication between a composer and a ViewModel, but of course, usage is a little different.

Posting a Command from a Composer to a ViewModel

We know that global command is triggered by binder sending events into event queue, hence, ViewModels attached with binders are able to communicate with each other by global command. However, a composer doesn't have a binder to send a global command, 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. Assuming that we do not change the default setting such that ShoppingCartViewModel's binder (receiver) subscribes to the 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 parameters 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
	}
}

Posting a Command from a ViewModel to a Composer

As a ViewModel has a binder attached to it, triggering a global command doesn't need BindUtils, we can simply use global command binding.


Assuming 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' in which the binder publishes to.

As mentioned earlier, global command is sent by event queue, the composer (receiver) should subscribe to the same scope event queue to receive this global command.

To subscribe global command (Receiver) to the event queue

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
			}				
		}
	}
}

Version History

Version Date Content
6.0.0 May 2012 Supplement to advanced topic.




Last Update : 2022/07/08

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