2

MVVM - template inside a template?

asked 2013-03-04 20:35:33 +0800

davout gravatar image davout
1435 3 18

I'm trying to create a bullet proof method for defining grids and listboxes that have a variable number of columns.

Ideally this could be accomplished by allowing a template tag to have another template tag inside its own block, but I can't find a way of making this work.

Here's an example of how I'm using a 'ZK' tag inside a template tag to create the dynamically set number of columns...

            <listbox model="@load(vm.sids)" autopaging="true"
                mold="paging" vflex="true" emptyMessage="No permissions defined"
                checkmark="true" multiple="true"
                selectedItems="@bind(vm.selectedSids)">
                <auxhead>
                    <auxheader>
                        <button label="Delete"
                            onClick="@command('delete')"
                            disabled="@load(empty vm.selectedSids)" />
                        <space />
                        <button label="Add"
                            onClick="@command('addNew')" />
                    </auxheader>
                </auxhead>
                <listhead children="@load(vm.columnsDef)">
                    <template name="children" var="c">
                        <listheader label="Principal" hflex="4" />

                        <zk forEach="${c.variableColumnDefs}">
                            <listheader label="${each.title}"
                                align="center" hflex="1">
                            </listheader>
                        </zk>
                    </template>
                </listhead>
                <template name="model" var="p">
                    <listitem>
                        <listcell >
                           <label value="@load(p.title)"/>
                        </listcell>
                        <zk forEach="${p.permissions}">
                            <listcell>
                                <checkbox checked="{each.state}" />
                            </listcell>
                        </zk>
                    </listitem>
                </template>
            </listbox>

The limitation with the ZUL shown above is that I can't use MVVM @load and @save binding on the components created inside the 'zk forEach' blocks. As a result I have a problem getting data out of those components.

Any suggestions?

delete flag offensive retag edit

Comments

11 Answers

Sort by ยป oldest newest most voted
1

answered 2013-03-07 07:11:38 +0800

davout gravatar image davout
1435 3 18

I have posted an enhancement request, based around the idea of adding MMVM template support to the 'zk' tag, see http://tracker.zkoss.org/browse/ZK-1332

link publish delete flag offensive edit
1

answered 2013-03-08 08:42:47 +0800

vincentjian gravatar image vincentjian
2245 6

Check the zkfiddle sample: http://www.zkfiddle.org/sample/2rjaqos/4-MVVM-with-nested-template.

link publish delete flag offensive edit
1

answered 2013-04-18 17:13:20 +0800

fuwbd182d gravatar image fuwbd182d
10 2

updated 2013-04-18 17:21:28 +0800

Been strugling with exact same problem, and I think I found a solution:

        <listbox model="@load(vm.data)">
            <template name="model" var="line">
                <listitem children="@bind(line)" >
                    <template name="children" var="cell">
                        <listcell label="@load(cell)"/>
                    </template>
                </listitem>
            </template>
        </listbox>
public class DynamicColumnModel {
    private List<list<string>> data = new ArrayList<list<string>>();

    @Init
    public void init() {
        for (int i = 0; i < 20; i++) {
            ArrayList<string> dataLine = new ArrayList<string>();
            for (int j = 0; j < 9; j++) {
                dataLine.add("Data " + i + "/" + j);
            }
            data.add(dataLine);
        }
    }

    public List<list<string>> getData() {
        return data;
    }

    public void setData(List<list<string>> dataList) {
        this.data = dataList;
    }
}

ZK Fiddle demo - zkfiddle.org/sample/1rhr8cd/17-Dynamic-Listbox-Columns (can't post links yet)

link publish delete flag offensive edit
0

answered 2013-03-04 22:40:33 +0800

rickcr gravatar image rickcr
704 7

updated 2013-03-04 22:40:52 +0800

No idea if this kind of thing would work (not sure if ZK can work on collections by index like this?), but maybe something like?

<template name="model" var="p">
    <listitem>
        <listcell >
           <label value="@load(p.title)"/>
        </listcell>
        <zk forEach="${p.permissions}">
            <listcell>
                <checkbox checked="@load(p.permissions[${forEachStatus.index}].state)" />
            </listcell>
        </zk>
    </listitem>
</template>
link publish delete flag offensive edit

Comments

hmm I wonder if that forEachStatus would be the var on the main template "p" collection. I'm curious now about all of this.

rickcr ( 2013-03-04 22:42:00 +0800 )edit

This has me really stumped. I'll definitely run across this so I'd love to know how you bind to nested items? I'm trying different things here http://zkfiddle.org/sample/26h2s9g/11-Test-Nested-List#source-1 without any luck myself. (This is easy with JSTL in JSP stuff so there has to be way.)

rickcr ( 2013-03-04 23:31:14 +0800 )edit

Of course the issue is dynamically creating listitems under a single listbox and having binding work. (I should correct my above in case someone gets here searching since nested listboxes of course works just fine http://zkfiddle.org/sample/26h2s9g/12-Test-Nested-List )

rickcr ( 2013-03-04 23:43:04 +0800 )edit
0

answered 2013-03-05 06:54:45 +0800

davout gravatar image davout
1435 3 18

I tried...

                                <zk forEach="${p.permissions}">
                                    <listcell>
                                        <checkbox
                                            checked="@load(p.permissions[${forEachStatus.index}].state)" /> 
                                    </listcell>
                                </zk>

... and on loading the ZUL I get the error...

05-Mar-2013 06:49:41 org.zkoss.zk.ui.impl.UiEngineImpl handleError:1351 SEVERE: >>org.zkoss.zel.ELException: Error Parsing: ${p.permissions[${forEachStatus.index}].state}

org.zkoss.zel.impl.parser.ParseException: Encountered " <illegal_character> "{ "" at line 1, column 18. Was expecting one of: "." ... "[" ... "]" ... ">" ... "gt" ... "<" ... "lt" ... ">=" ... "ge" ... "<=" ... "le" ... "==" ... "eq" ... "!=" ... "ne" ... "&&" ... "and" ... "||" ... "or" ... "*" ... "+" ... "-" ... "/" ... "div" ... "%" ... "mod" ...

at org.zkoss.zel.impl.parser.ELParser.generateParseException(ELParser.java:2215) at org.zkoss.zel.impl.parser.ELParser.jjconsumetoken(ELParser.java:2097) at org.zkoss.zel.impl.parser.ELParser.BracketSuffix(ELParser.java:1087)

As far as I'm aware the MVVM annotations don't support arrays in view model references. Right?

link publish delete flag offensive edit
0

answered 2013-03-05 07:21:38 +0800

davout gravatar image davout
1435 3 18

Is there are way to bind @load to a vm class method with a paramter passed back to the vm class? Like...

@load(vm.state,param=1)

link publish delete flag offensive edit
0

answered 2013-03-05 07:54:37 +0800

davout gravatar image davout
1435 3 18

Alternatively is there a way to fix up the binding using Javascript AFTER the template has finished its job?

link publish delete flag offensive edit
0

answered 2013-03-05 17:51:36 +0800

rickcr gravatar image rickcr
704 7

What I'd like is maybe just some way to display a nested listbox "inline"? So that it doesn't surround everything with a table and tr tags. Instead it can just use tags. - maybe something like:

<listbox model="@load(vm.sids)" selectedItems="@bind(vm.selectedSids)">
  <template name="model" var="p">
    <listitem>
      <listcell>
        <textbox value="@bind(p.title)"/>
      </listcell>
      <listcell>
        <listbox model="@bind(p.permisssions)" ****** inline="true" *****>
          <template name="model" var="child">
            <listitem>
              <checkbox checked="@bind(child.state)"/>
            </listitem>
          </template>
        </listbox>
      </listcell>
    </listitem>
  </template>
</listbox>

If not using a Listbox, with an 'inline' option, maybe some other type of of binder ? or how would you do all this VM binding with a regular forEach and creating the HTML manually (like I typically have done with JSTL)?

link publish delete flag offensive edit
0

answered 2013-03-06 00:26:40 +0800

davout gravatar image davout
1435 3 18

Back to my original question...

I can't find a way of mixing '${}' EL inside @load and @save annotations, so for the moment I have given up on this.

I have found a way of getting the data out of the checkbox using the 'onCheck' event, see below:

                        <template name="model" var="p">
                            <listitem>
                                <listcell>
                                    <label value="@load(p.title)" />
                                </listcell>
                                <zk forEach="${p.permissions}">
                                    <listcell>
                                        <checkbox 
                                            checked="${each.state}" onCheck="@command('onCheckState',row=pStatus.index,col=self.getParent().getParent().getChildren().indexOf(self.getParent())-1,state=self.isChecked())" /> 
                                    </listcell>
                                </zk>
                            </listitem>
                        </template>

It's a shame that templates can't be put inside templates. Elsewhere I have made a suggestion previously about allowing a '<zk>' tag to be a parent for a <template> tag. That I feel would provide all the flexibility my original question seeks.

link publish delete flag offensive edit

Comments

Do you have a bug/feature ticket in for this? I have an application that will need columns created dynamically (with form content) as well and it's a bit frustrating to have found how difficult this is to accomplish. That work around above is nice.

rickcr ( 2013-03-06 16:20:40 +0800 )edit
0

answered 2013-03-07 04:37:31 +0800

vincentjian gravatar image vincentjian
2245 6

updated 2013-03-07 04:38:19 +0800

Hi all, You can use children binding with multiple template like the answer khcyt provided in this question.

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
2 followers

RSS

Stats

Asked: 2013-03-04 20:35:33 +0800

Seen: 388 times

Last updated: Apr 18 '13

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