Inline Macro: pass parameter with ViewModel annotation (@load(x)) [closed]

asked 2015-01-28 14:01:20 +0800

KlausWr gravatar image KlausWr
37 5

updated 2015-01-28 16:26:01 +0800

I try to pass a binding annotation as a parameter to a macro:

<?component name="macro" inline="true" macroURI="macro.zul"?> 

            <window title="Macro Test" 
                   viewModel="@id('vm') @init('de.klauswr.zk.MacroViewModel')">

             <label value="@load(vm.field)" />
             <macro value="@bind(vm.field)" />


where macro.zul:

    <textbox value="${arg.value}" />

But I always get an empty result for the macro, while the label properly renders "Test" as initial value for "field". I fiddled around with thousands of permutations but never got a proper result.

This macro is just a short test for a bit complexer macro i need to use over and over in order to get a unique layout for certain data entry screens so please do not just post an answer for this simple example but help me solve the @()-binding issue.

delete flag offensive retag edit

The question has been closed for the following reason "the question is answered, right answer was accepted" by cor3000
close date 2015-02-02 09:42:36


Your macro, does it extends some component class?

chillworld ( 2015-01-28 15:32:11 +0800 )edit

There was a slight problem in formatting of my post - the component declaration was invisible (now edited). You can see that it is just a text based macro (I think extending HtmlMacroComponent?).

KlausWr ( 2015-01-28 16:26:55 +0800 )edit

@chill: As newbie I neither can comment directly on your answer - nor can I add my own answer. So I choose this way to tell you thanks. Will try your solution. I guess there is no EASY way like I tried before ... means I WILL need a class and I need to know the controls per component, hugh :-(

KlausWr ( 2015-01-28 19:15:58 +0800 )edit

Just upvoted the question, so you have a little more karma. I can help you with creating a simple examle so you could use it. (linkedin is in mine profile)

chillworld ( 2015-01-28 20:25:14 +0800 )edit

3 Answers

Sort by ยป oldest newest most voted

answered 2015-01-30 01:55:59 +0800

cor3000 gravatar image cor3000
4332 1 7
ZK Team

OK hoping I didn't combine/confuse too much of what I read above: here an example giving the same result as a reference - without using @ref.

Since everything in java is a reference you can always add another level of indirection to achieve the same as @ref. Maybe not as convenient but not impossible anyway.

As inline macros don't support bind annotations anyway I broke up the expression into the pojo and field parameter (you could also use "vm" and "field") which are both statically evaluated, and hence available via arg.pojo/arg.field in the macro. However not for long so I store them in custom attributes to be available when the annotation @bind(pojo[field]) is evaluated using runtime evaluation.

I hope the used features are available in ZK CE. Let me know if this fails.

link publish delete flag offensive edit


Brilliant! Works like a charme (in CE) ... while ugly like a frog :D ... Anyway: I will go for it as long as my company won't spend PE/EE fee. Thanks!! (BTW: I learned a lot about references in zk, the convenient and the inconvenient ones)

KlausWr ( 2015-01-30 08:43:24 +0800 )edit

I can only mark ONE answer as correct which is a pity here .-( ... all answers were valid ones depending on the use case!

KlausWr ( 2015-01-30 08:45:53 +0800 )edit

thanks for the feedback, I am glad we could help

cor3000 ( 2015-01-30 09:01:44 +0800 )edit

Sorry for coming back to this issue: I tried to use a form now and used the id of the form as "pojo": <grid form="@id('fx') @bind(vm.pojo)> <rows> <mymacro pojo="${fx}" field="myValue"/> ... but I get "Target Unreachable, identifier 'pojo' resolved to null" Impossible?

KlausWr ( 2015-01-30 09:24:19 +0800 )edit

Maybe it was not clear so far that my problem is caused by clientside constraints. I cannot suppress the save command while there are invalid entries as I cannot set a form to name the "save"-command in the before clause of form @save, nor can I use the @save annotation per input-component..

KlausWr ( 2015-01-30 14:31:19 +0800 )edit

answered 2015-01-28 16:46:10 +0800

chillworld gravatar image chillworld flag of Belgium
5322 4 9

updated 2015-01-28 17:44:02 +0800

You don't have any component behind and that's actually what you are missing.

I have create for myself an component like you want to create :

Declaration is :

<?component name="catalog" macroURI="/WEB-INF/webpages/zk/common/catalog.zul" class="be.chillworld.web.vm.common.BindingCatalogMacroComponent"?>

As you can see that I have now a class behind this component.

This is mine zul :

<?xml version="1.0" encoding="UTF-8"?>
<zk xmlns="http://www.zkoss.org/2005/zul" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.zkoss.org/2005/zul                        http://www.zkoss.org/2005/zul/zul.xsd">
  <hbox align="center" id="${arg.id}">
    <image src="/img/detail.png" id="detail" />
    <textbox cols="9" ctrlKeys="^l" id="code" readonly="${arg.readonly}" sclass="T_TB_code">
      <custom-attributes validation="${arg.constraint}" />
    <separator width="5px" />
    <textbox readonly="true" cols="30" id="description" tabindex="-1" sclass="T_TB_description" />

And as last the a part of the class behind :

public class BindingCatalogMacroComponent extends HtmlMacroComponent {
    protected InputElement code;
    protected Textbox description;
    protected Image detail;

What's really important is that you implement the MineObject getValue() and SetValue(MineObject obj)

The setup is done in the doAfterCompose. I have put the constraint in custom attribute because I have to call the getValue when I open a popup and when constraint fails at that moment I'll have that popup from failing constraint on top of mine popup. (So I actually check the constraint when I need it)

I'll hope if this already can help you.

Edit :

Forget to say, I set the textbox value in the setValue method.
If you need more info, just ask.

greetz chill.

link publish delete flag offensive edit


See my comment on the 2nd solution ... how to get rid of the exception com.prostep.openpdm.admin.component.TextboxRow cannot be cast to org.zkoss.zul.Row?

KlausWr ( 2015-01-29 13:14:52 +0800 )edit

answered 2015-01-29 00:57:56 +0800

cor3000 gravatar image cor3000
4332 1 7
ZK Team

updated 2015-01-29 00:59:00 +0800

The problem with using an "inline" macro is that there is no component for it in the resulting component tree, that's why the @bind() is never actually evaluated. (derived explanation based on http://books.zkoss.org/wiki/ZKDeveloper%27sReference/UIComposing/MacroComponent/InlineMacros#InlineversusRegularMacro)

However with an inline macro you could access the arg.includer and read attributes of it. http://books.zkoss.org/wiki/ZKDeveloper%27sReference/UIComposing/MacroComponent/Inline_Macros#arg.includer

Second problem even if using a "non-inline" macro is that the annotation @bind() will evaluate too late (after the components have been created inside). So the value is not available during component creation inside. And it requires at least a custom component class with MVVM annotations to trigger the @save for a specific event, you need to define as well. (http://books.zkoss.org/wiki/ZKDeveloper%27sReference/MVVM/Advanced/BindingAnnotationforaCustom_Component)

So an easy solution for some cases (maybe yours - wasn't too clear from your example) is to use a @ref(vm.field) to your macro and @load/@save/@bind to that reference inside your macro. The reference will delegate load and save operations to your vm.field.

I created this running example for your you to try. Maybe add what is missing in your macro so I can try to adjust the solution or suggest something different.



link publish delete flag offensive edit


Perfect analysis ... but: I already thought about using references. Unfortunately they need another zk version (EE) which I do not have so I get "ref binding handler is not supported in current runtime". :-(

KlausWr ( 2015-01-29 13:08:27 +0800 )edit

Using the non-inline-macro solution would work, Problem: my real macro should substitute an entire row within a given grid (row, label, textbox, image, /row). It works nice inline, but non-inline I get an exception com.prostep.openpdm.admin.component.TextboxRow cannot be cast to org.zkoss.zul.Row.

KlausWr ( 2015-01-29 13:13:21 +0800 )edit

If you remove the <row> from the zul and put the row tag in the grid it should work.

chillworld ( 2015-01-29 13:18:36 +0800 )edit

Too easy ;-) ... seriously: how would I solve the problem if I need to leave the row tag where it is? Is it possible or not?

KlausWr ( 2015-01-29 13:46:22 +0800 )edit

maybe this works : use="org.zkoss.zul.Row" in the <macro> tag

chillworld ( 2015-01-29 14:06:13 +0800 )edit

Question tools




Asked: 2015-01-28 14:01:20 +0800

Seen: 79 times

Last updated: Jan 30 '15

Support Options
  • Email Support
  • Training
  • Consulting
  • Outsourcing
Learn More