0

Create component from ViewModel

asked 2022-09-15 19:52:03 +0800

ImanolRP gravatar image ImanolRP
150 4

Hello everyone, ill try to be concise with my problem/doubt.

I have a ViewModel wich with one input param recover info from DB and mount dinamically grids with client info. I need move this VM to a commons .jar for use it on other projects of the same client.

Right now im reusing that VM with a "include" tag and the SRC + input param of vm's zul.

PROBLEM/QUESTION

Its possible declare on lang.xml that VM for use it with custom tag? Its for make it more legible in the future and eaisly difference between other "include" tag.

EXAMPLE

  • NOW

<include src="@load(vm.srcVM_1)" inputParam="@load(vm.inputParam_1)">

<include src="@load(vm.srcVM_2)" inputParam="@load(vm.inputParam_2)">

<include src="@load(vm.srcVM_1)" inputParam="@load(vm.inputParam_1)">

  • EXPECTED

<include src="@load(vm.srcVM_1)" inputParam="@load(vm.inputParam_1)">

<custom-component inputParam="@load(vm.inputParam_2)">

<include src="@load(vm.srcVM_1)" inputParam="@load(vm.inputParam_1)">

EXTRA INFO

I was reading about how create custom components but only find examples for create it extendieng of GenericForwardComposer and SelectorComposer but seems like that is for MVC architecture cant fing anything for MVVM.

delete flag offensive retag edit

4 Answers

Sort by ยป oldest newest most voted
0

answered 2022-09-16 18:56:22 +0800

ImanolRP gravatar image ImanolRP
150 4

updated 2022-09-16 19:01:41 +0800

UPDATE of the investigation (for help to resolve the doubt)

In the last hours i was searching about how create custom components with only an ViewModel without succes. In the only place i have found anything remotely similar to my case its in the oficial wiki of zk. The page has been updated: 2022/08/08 then sould be "reliable".

https://www.zkoss.org/wiki/ZKClient-sideReference/Language_Definition/component

The example im talking about its on the point "9.template-uri > 9.2Define a Custom Component"

That point sais you can define on lang-addon a component like:

<component>
    <component-name>megamenu</component-name>
    <template-uri>/uiComposing/megaMenuParameterized.zul</template-uri>
</component>

And then invoque it from the zul with the custom tag:

<megamenu>

I have copy/pasted that example on my own project creating a simple zul (not provided by the wiki):

megamenu.zul

<zk>
    <label value="megamenu"/>
</zk>

But when i'm deploying fails reading the lang-addon in that component and don't recognize me that tag on .zul files.

Server deploying logs

ERROR [org.zkoss.zk.ui.metainfo.DefinitionLoaders] (ServerService Thread Pool -- 73) Failed to load addon: file:/P:/jboss-eap-7.1.0/standalone/tmp/vfs/temp/temp391cd92af805a4c7/content-d31b2ec3d5f014f7/WEB-INF/lang-addon.xml: java.lang.NullPointerException
        at org.zkoss.zk.ui.metainfo.DefinitionLoaders.parseLang(DefinitionLoaders.java:446)
        at org.zkoss.zk.ui.metainfo.DefinitionLoaders.loadLang(DefinitionLoaders.java:241)

Anyone have tryed this example or others like this with succes?

link publish delete flag offensive edit
0

answered 2022-09-20 00:15:30 +0800

MDuchemin gravatar image MDuchemin
2193 1 5
ZK Team

Hey there,

If you want to do this type of templating in MVVM, I'd suggest extending macrocomponent instead of declaring a custom comp directly.

there is a good sample here: http://books.zkoss.org/zk-mvvm-book/8.0/advanced/bindingannotationforacustom_component.html

The only tricky part is to keep the direction of the data flows you have in mind. The macro component has getters and setters, which can be accessed by your databinding (@bind, @load, @save) and it can send events which can be used to trigger @command on your VM

HOWEVER You need to declare these fields as accessible by the binder. See the "Declare Data Binding in Language Addon XML" in the doc above.

Have a look and let me know if you get stuck

link publish delete flag offensive edit

Comments

that link above talks above the MVVM specific macrocomponent stuff. For the general doc, have a look here instead: https://www.zkoss.org/wiki/ZKDeveloper'sReference/UIComposing/MacroComponent#DefineMacroComponent

MDuchemin ( 2022-09-20 00:17:07 +0800 )edit

The main point is, the macrocomponent acts as an interface between the databinder on your outside page, and the children that you instantiate from the macrocomponent template

MDuchemin ( 2022-09-20 00:18:01 +0800 )edit

it pre-solves a lot of binding questions. You can implement your own component yourself, but you will still need to declare the lang-addon for save / load ACCESS (no need to declare bind, bind is "both" save and load)

MDuchemin ( 2022-09-20 00:18:15 +0800 )edit

First of all, thank you for your answer.

This urls resolve some big doubts but generate other doubts/problems, specifically two.

I'll put both like diferent anwer of the question for facility the answer of both individually in their own comments section.

ImanolRP ( 2022-09-20 20:49:05 +0800 )edit
0

answered 2022-09-20 21:13:22 +0800

ImanolRP gravatar image ImanolRP
150 4

First problem

How acces to ViewModelComponent data and how resolve "UiException: Not unique in the ID space of <Window>."

First of all i have replicated the case of the first example with the point of view of a view model. But that generate me a problem accesing the data of the variables.

The declaration on the lang-addon its the same but the zul and class are a bit different.

test-component.zul

<zk>
    <label value="@load(test.inputParam)"/>
</zk>

TestComponent.java

public class TestComponent extends HtmlMacroComponent {

  private String inputParam;

  public TestComponent() {
    setMacroURI("~./zul/testcomponent/test-component.zul");
    setId("test");
  }

  public void setInputParam(String inputParam) {
    this.inputParam = inputParam;
  }

  public String getInputParam() {
    return inputParam;
  }

}

With that aproach i cant acces to the value of inputParam without adding an ID to the component because we loose the viewModel attribute on the zul declaration. On the example we have "test" like the component ID.

This sounds me like the programatically translation of "@id('vm') @init('org.example.vm.TestVM')", drama becomes when i try to use 2 times the same component in the same .zul and get the error:

UiException: Not unique in the ID space of <Window>

This a normal error of duplicate ID and i understand why occurs but, how can solve it? can i create a dinamic id for use on the zul? have tryed implementing the interface IdSpace without succes...

link publish delete flag offensive edit
0

answered 2022-09-20 21:54:14 +0800

ImanolRP gravatar image ImanolRP
150 4

Second problem

Command/Event binding inside templates.

For this case i need a bit more complex example for illustri the problem, ill explain the use case evolution for make more easy to undertand or for find erros on the thinking evolution.

The problem started when the @Commands usually used for trigger events inside the "VM", are triggered on the parent "VM" and not inside the ViewModelComponent. This can be easily resolved changing @Command for @Listen annotations pointing by id or class deppending the case.

The problem is, that @Listen annotations seems like are builded before the template generation. And if we have the use case:

test-component.zul

<zk>
    <button sclass="btnCommandTest" label="btn.commandTest"/>
</zk>

TestComponent.java

@Listen("onClick = .btnCommandTest")
public void btnCommandTest() {
  // OnClick
}

The event are listen without problems, but if we have this other use case:

test-component.zul

<grid model="@load(test.model)"
      emptyMessage="label.no_results"
      hflex="1">
    <!-- COLUMNS -->
    <columns children="@load(test.columnList)">
        <template name="children" var="column">
            <column label="@load(column.columnLabel)"/>
        </template>
    </columns>
    <!-- AUXHEAD -->
    <auxhead children="@load(test.columnList)">
        <template name="children" var="column">
            <auxheader>
                <hlayout hflex="1" spacing="0">
                    <button iconSclass="z-icon-search-plus"
                            sclass="btnCommandTest"/>
                    <textbox hflex="1"
                             value="@bind(column.filter.value)"/>
                </hlayout>
            </auxheader>
        </template>
    </auxhead>
    <!-- ROWS -->
    <rows>
        <template name="model" var="item">
            <row children="@load(test.columnList)">
                <template name="children" var="column">
                    <textbox hflex="1" readonly="true"
                             value="@load(item.params[column.columnOrder])"
                             tooltiptext="@load(item.params[column.columnOrder])"/>
                </template>
            </row>
        </template>
    </rows>
</grid>

The buttons inside the Grid > AuxHead > Template > AuxHeader never trigger the same component method.

I have tryed with the AfterForward events without succes...

link publish delete flag offensive edit
Your answer
Please start posting your answer anonymously - your answer will be saved within the current session and published after you log in or create a new account. Please try to give a substantial answer, for discussions, please use comments and please do remember to vote (after you log in)!

[hide preview]

Question tools

Follow
1 follower

RSS

Stats

Asked: 2022-09-15 19:52:03 +0800

Seen: 11 times

Last updated: Sep 20

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