# How to pass parameters from ViewModel to ViewModel via <include>?

cypha
27 1

Hello everyone,

i hope someone can help me with the following problem:

I have an overview ZUL dialog with a ViewModel. Inside the ZUL, i want to include another ZUL dialog with its own ViewModel.
Now i want to pass some parameters from the first VIewModel to the second. I'm trying to achieve this via dynamic properties, i.e.

<include src="someFile.zul"  folders="@load(overviewVM.folders)" />

But i cannot read the "folders"-param in the second ViewModel. I tried all the Param Annotations but they are all null. Using include in defer mode or using reference binding didn't help too. I assume this is a lifecycle problem, but how do i solve this?

Maybe a small diagram just to make things clear:

ViewModel1                                                         ViewModel2
|                                                                |
|                                                                |
Overview.zul   ------> <include src="someFile.zul"/>  --------> someFile.zul


delete retag edit

## 6 Replies

rdgrimes
735 7

It occurs to me that maybe you aren't aware that someFile.zul doesn't need it's own viewModel. As an included zul, it automatically has access to Overview.zul's viewmodel. So, in someFile.zul, you can just use overviewVM.folders in a component. You should look at any included zul as though it is in the same document as parent zul. No difference.

But, as a general principle of communicating between viewmodels, there are a few options. Personally, I would use one of these two techniques:

1) Push the folders object from viewmodel1 to viewmodel2 via an event queue. See here.

2) Make the folders object accessible via a session level attribute.

ViewModel1

Sessions.getCurrent().setAttribute("folders", folders);


Then, in ViewModel2, you can retrieve it via:

List<Folder> folders = Sessions.getCurrent().getAttribute("folders");


I don't know what type of object your folders is, so I just used List<Folder> for an example.

Ron

cypha
27 1

Hi Ron,

thanks for your help, however it seems i forgot to explain something. I want someFile.zul to be a single, universally usable Dialog which does not depend on others. So it has to have its own viewmodel. I want to call it directly, include it and create it via Executions.createComponents. Is this possible?

rdgrimes
735 7

I think then, that this might help: http://books.zkoss.org/wiki/ZK%20Developer's%20Reference/MVVM/Advance/Access%20Arguments

That would address the include technique. For the .createComponents, you should be able to pass a Map as the third parameter. That Map contains the parameters you want the created component to have access to: http://books.zkoss.org/wiki/ZK_Developer's_Reference/UI_Composing/ZUML/Load_ZUML_in_Java

cypha
27 1

Unfortunately it did not solve the problem.
Maybe we should go for some example code:

InnerVM.java
package j17kiil$v2;import org.zkoss.bind.annotation.ExecutionArgParam;import org.zkoss.bind.annotation.Init;public class InnerVM { private String passedText; private String textFromZul; @Init public void init(@ExecutionArgParam("passedText") String passedText, @ExecutionArgParam("textFromZul") String textFromZul) { this.passedText = passedText; this.setTextFromZul(textFromZul); } public String getPassedText() { return passedText; } public void setPassedText(String passedText) { this.passedText = passedText; } public String getTextFromZul() { return textFromZul; } public void setTextFromZul(String textFromZul) { this.textFromZul = textFromZul; }} inner.zul <zk> <window border="none" apply="org.zkoss.bind.BindComposer" viewModel="@id('innerVM') @init('j17kiil$v2.InnerVM')">      <label value="@bind(innerVM.passedText)" />      <label value="@bind(innerVM.textFromZul)" />	</window></zk>

OuterVM.java
package j17kiil$v2;public class OuterVM { // could be loaded from database or whatever private String textToPass = "textFromOuterViewModel"; public String getTextToPass() { return textToPass; } public void setTextToPass(String textToPass) { this.textToPass = textToPass; }} index.zul <zk> <window border="none" id="outer" apply="org.zkoss.bind.BindComposer" viewModel="@id('outerVM') @init('j17kiil$v2.OuterVM')">       <include src="inner.zul" passedText="@ref(outerVM.textToPass)" textFromZul="textDirectlyFromZUL" /> 	</window></zk>

If i specify the parameter directly in the zul code, i can access it in the inner view model. But if the parameter should be loaded from the outer view model, i have no chance to access it.

dennis
3669 1 6
http://www.javaworld.com....

the lifecycle is not matched if you use include.src directly and want to access some args from execution (it is too late because the binder is working after creation, in afterCompose)

to achieve, there are some steps you have to follow.
1. change the src to binding too.

<include src="@init('inner.zul')" ..></include>

use @init because it only loads once and never changes. (use @load is ok but more cost )
2. set the binding args in inner viewModel @init to the value of @ref
viewModel="@id('innerVM') @init('j17kiil\$v2.InnerVM', theArg=passedText)"


3.change @ExecutionArgParam("passedText") to @BindingParam("theArg")

I know it is not so straightforward.

cypha
27 1

Thank you very much, dennis! That is exactly what i was looking for. :)

[hide preview]