Introduction
Some times we want to change a component while some event of another component is triggered, we can achieve this by posting an event with some data to the component we want to change instead of modify it directly in the event listener of another component.
This seems a little bit weird and useless but this would be helpful in some situation such like implementing inplace editing of grid with renderer under MVVM (will be described in another article later)
Pre-request
(must)
Basic MVC with SelectorComposer
http://ben-bai.blogspot.tw/2012/10/zk-basic-mvc-pattern-with_31.html
The Composer
PasseventTestComposer.java
Simply post an event to label while the value of textbox is changed, update label's value in the event listener itself.
package test.event.passeventtest;
import java.util.HashMap;
import java.util.Map;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zk.ui.event.InputEvent;
import org.zkoss.zk.ui.select.SelectorComposer;
import org.zkoss.zk.ui.select.annotation.Listen;
import org.zkoss.zk.ui.select.annotation.Wire;
import org.zkoss.zul.Label;
/**
* Tested with ZK 6.0.2
*
* Test passing event with data from one component to another
*
* This seems a little bit weird and useless here
* but this would be helpful in some situation
* such like implement inplace editing of grid with renderer
* under MVVM
* (will be described in another article later)
*
* @author benbai
*
*/
public class PasseventTestComposer extends SelectorComposer {
@Wire
Label lb;
/**
* Post an event with the new value to label
* while the value of textbox is changed
* instead of modify the value of label directly
* @param event
*/
@Listen("onChange=#tbx")
public void onChange$tbx (InputEvent event) {
Map data = new HashMap();
data.put("value", event.getValue());
Events.postEvent("onValueChange", lb, data);
}
/**
* Really modify the value of label here
* @param event
*/
@Listen("onValueChange=#lb")
public void onValueChange$lb (Event event) {
Map data = (Map)event.getData();
String value = (String)data.get("value");
lb.setValue(value);
}
}
The ZUL Page
pass_event_to_other_component.zul
<zk>
<!-- Tested with ZK 6.0.2 -->
<window apply="test.event.passeventtest.PasseventTestComposer">
<label id="lb" value="label" />
<textbox id="tbx" />
</window>
</zk>
The Result
View demo on line
http://screencast.com/t/9wYBLE3lubaF
Reference
http://books.zkoss.org/wiki/ZK_Developer's_Reference/Event_Handling/Event_Firing
Download
Files at github
pass_event_to_other_component.zul
https://github.com/benbai123/ZK_Practice/blob/master/Components/projects/Components_Practice/WebContent/pass_event_to_other_component.zul
PasseventTestComposer.java
https://github.com/benbai123/ZK_Practice/blob/master/Components/projects/Components_Practice/src/test/event/passeventtest/PasseventTestComposer.java
pass_event_to_other_component.swf
https://github.com/benbai123/ZK_Practice/blob/master/Components/demos/pass_event_to_other_component.swf
How to pass KeyStroke event in Child Pages I have hierarchy MainParent->MainParentChild->MainParentChildsChild now i will want to pass the KeyStroke Event in the MainParentChildsChild page like If User Press Ctrl+q or Ctril+S or Ctrl+A i have pass these keys in the Child pages.
ReplyDeleteHow do you include child page? Using ?
DeleteThis comment has been removed by the author.
ReplyDeleteThe pages are included like this..
ReplyDelete<tabpanels>
<tabpanel style="color:#333399;">
<include src="dashboard.zul" />
</tabpanel>
What i will want here to send Keypress event code in Child page ViewModel. As i added
ctrlKeys="^a^s^d#f8" onCtrlKey="@command('ctrlKeyClick',code=event.getKeyCode())"
In My parent ZUL and now i will want KeyCode in my Children viewmodel How can i do this?
Child page can access parent vm directly, please refer to the sample at zkfiddle http://zkfiddle.org/sample/2cptkn6/6-MVVM-Inner-Page-Ctrlkeys
DeleteI think you miss understood my problem in my case i have send data to Child viewmodel from parent viewmodel.In you example you are passing Ctrl event from child to parent but i need opposite..I have asked a question here..http://forum.zkoss.org/question/84920/how-to-call-child-viewmodel-method-from-parent-window/
DeleteMaybe you can try Global Command Binding: http://books.zkoss.org/wiki/ZK%20Developer's%20Reference/MVVM/Data%20Binding/Global%20Command%20Binding
DeleteThanks i have done this with GlobalCommand can you please tell me is any drawback to use GlobalCommand ?
DeleteOne more thing i have to fire Ctrl key event on active tab as my parent window can open lots of tab and if i will use Global command how i will figure out which tab is active so that i can fire the command only on that tab.
DeleteIf the page is cached and then refreshed, it may bind command multiple times.
DeleteYou can try pass the information of selected tab (e.g., index, label, etc) and use it as a condition in command fumction.
DeleteHere in my case tab contain a wholee page different tab means a different page also tab are created dynamically from java code and when tab or page is selected and user doing something then if user use ctrl key then I have to fire save, refresh, delete etc.
DeleteAre the tabs under parent VM or child VM?
DeleteI have home.zul which contain menu with item and when you will click on any menu item it will open a tab for each menu item a new tab will open now each tab contain a zul page where user can do certain operation and by Ctrl keys like Ctrl+s for Saving, Ctrl+r for Refresh, Ctrl+q for query etc will perform. If I will use global command I have to write that global command in each tab view model or we can say child of home. Now suppose I open a tab then ctrl key will fire now I open another tab now 2 times ctrl key will fire , while I will want only active tab view model will fire a event on ctrl key
DeleteMaybe you can try the form binding (http://books.zkoss.org/wiki/ZK%20Developer's%20Reference/MVVM/Data%20Binding/Form%20Binding), if this still not work in your case, you can try customize the tabbox as needed, e.g., like this sample at zkfiddle (http://zkfiddle.org/sample/vmmp6p/1-MVVM-Test)
DeleteThanks Let me try your example
DeleteHere you added ctrl key event in tab while in my case i added ctrl key event in windows compoentn so it will available for each tab because my all tab is added from java code and its too complex to add ctrl key in tab component
DeleteI've tested it and the onCtrlKey event fired for each tab without any problem, basically the parent component (tabbox) will receive the events of its children (all tabs)
DeleteBy the way, the sample above firing event to selected tab child from tabbox instead of using global command
Deletecan it possible we can change this line
DeleteEvents.postEvent("onActionRequest", tp.getFirstChild().getFellow("div"), data);
As you are doing id binding i will want to give command name or other thing because i have plenty with different component if i will add id static id in each pages i have to change plenty of places .Can we have any other solution here?
You can also use tp.getFirstChild().getFirstChild() if the first element of each inner page is the element that apply child vm.
DeleteIn my case its very hard to do that Can we do something like postcommand where we can give command name and the command will fire child viewmodel ?
ReplyDeleteMaybe you can try global command in this way:
Delete1. Store the selected tab in parent vm, and pass it to each child vm with global command
2. Store any component (maybe the first one under child vm) in the child zul within child vm, and continuously get parent component until find a tab then check whether it is the selected tab when global command triggered.
Ok but If we are adding a calling a GlobalComamnd from Parent View Model and creating a global command in each of the Child viewmodel then it is going to each viewmodel global command because name is same in each child viewmodel
DeleteThat's right, then you can find the parent tab (from child vm) and detect whether it is the selected tab (in the global event from parent vm).
DeleteCan it possible to run bind.postCommand("methodName", map); here ?
DeleteAccording to the javadoc (http://www.zkoss.org/javadoc/6.5.1/zk/org/zkoss/bind/impl/BinderImpl.html#postCommand(java.lang.String, java.util.Map)), postCommand will post a command to current binder, it can not post command from parent vm to child vm. You can try use EventQueue directly as needed.
DeleteThere's an idea coming in to my mind, since requests are thread safe, we can assume the create event of tab and the init of child vm are occur at the same time, in other words, if we maintain two list say tabList and vmList, we can assume the order of tab in tabList will match the order of child vm in vmList, i.e., we can do something as below:
Delete1. find the order of selected tab in parent vm
2. get the corresponding child vm based on the order found before in vmList
3. call binder.postCommand of child vm
just a rough concept, not tested
Thanks Again Ben ...i got another idea and look like it is working fine with me What i did? I made a Singleton Class and added a variable of Component class with get/set method. Now in each of my view Model afterCompose() i am calling setter method of Component variable from singleton class, and passing current viewModel Component object to it and in my HomeViewModel CTRL key event method i adding this code so it calling method from Selected tab .
DeleteComponent ctrlkeyComp = idBinder.getCompObject();
if(ctrlkeyComp != null){
Binder bind = (Binder) ctrlkeyComp.getAttribute("binder");
if (bind == null)
return;
bind.postCommand("doActionInChildVM", map);
}
Yeah this seems a good way to go.
DeleteThese is one issue with this approach here in using Singleton Class .Let us suppose i have open A<B,C,D tab and i am in D tab so Singleton class have COmponent class of D now if i will click on tab A then methods of TabD will be call Which is a issue.
DeleteIs there a sample that can reproduce this issue?
DeleteI have asked one question here http://stackoverflow.com/questions/15001670/how-to-get-viewmodel-from-selectedtab-in-zk
DeleteBen do you have any idea about this http://stackoverflow.com/questions/14879269/zk-listbox-onselect-issue
ReplyDeleteSeems the spec of modal window, replied
DeleteThanks Ben for your help
Delete