Also note you can nest templates in a grid if that helps you http://forum.zkoss.org/question/84802/problem-with-dyanmic-columns-and-rows-in-a-grid/
rickcr ( 2013-03-09 03:51:56 +0800 )edit-
FEATURED COMPONENTS
First time here? Check out the FAQ!
Hi everybody, the problem is this one (with some simplification).
I've a class: Result
, and two other classes that extend the first one: NumberResult
and TextResult
. NumberResult
has three fields: value
, minValue
and maxValue
; TextResult
has two fields: value
and reference
.
Then there's another class: Exam
, that has a list of Result
.
I need to show the results of an exam in a grid. I can have text and number results mixed together and I can't modify the order of the list. Here is my solution.
<grid vflex="1" model="@load(vm.examResults)">
<columns>
<column hflex="1" label="Value" />
<column hflex="2" label="Reference" />
<column hflex="1" label="Min." />
<column hflex="1" label="Max." />
</columns>
<template name="model">
<row>
<label value="${each.value}" />
<label value="${c:isInstance('myPackage.TextResult', each) ? each.reference : null}" />
<label value="${c:isInstance('myPackage.NumberResult', each) ? each.minValue : null}" />
<label value="${c:isInstance('myPackage.NumberResult', each) ? each.maxValue : null}" />
</row>
</template>
</grid>
It's not a very nice solution and it uses a deprecated tag library (c). Moreover, because the grid has much more fields that those showed in this example, it's also not very efficient.
So I'm trying to find a way to use two templates, one for the NumberResult
and the other for the TextResult
, but I can't find how to do yet.
Any idea will be really appreciated.
Roberto
Maybe not ideal but you could use an Adapter pattern where your Adapter class holds an instance of Result and then you could provide accessor methods. Ideally you'd stuff your Result instances into this Adapter when you getting your collection the first time to avoid an extra iteration.
I put together an example here for you http://zkfiddle.org/sample/11r42l4/10-AdapterExample (Note: not sure why, but Zkfiddle didn't like me using an Interface so that's the only reason you see the classes extends Result, but you get the idea.)
It works because the el on the page won't complain the first time there is null object even if the next property doesn't exist on the object.
Here is a sample of what I did as well (note the static classes just bc I was lazy in my IDE)
<window border="none" apply="org.zkoss.bind.BindComposer" id="mainWindow"
viewModel="@id('vm') @init('net.reumann.zktesting.TestVM')" width="100%" height="100%">
<vlayout>
<grid vflex="1" model="@load(vm.results)">
<columns>
<column hflex="1" label="Value" />
<column hflex="2" label="Reference" />
<column hflex="1" label="Min." />
<column hflex="1" label="Max." />
</columns>
<template name="model">
<row>
<label value="${each.textResult.value}" />
<label value="${each.textResult.reference}" />
<label value="${each.numberResult.minVal}" />
<label value="${each.numberResult.maxVal}" />
</row>
</template>
</grid>
</vlayout>
</window>
public class TestVM {
public List<UiResultAdapter> getResults() {
//call to DB would return these
List<UiResultAdapter> results = new ArrayList<UiResultAdapter>();
Result r1 = new TextResult("t1","ref1");
results.add(new UiResultAdapter(r1));
Result r2 = new NumberResult(1,10);
results.add(new UiResultAdapter(r2));
return results;
}
public static class UiResultAdapter {
private Result result;
public UiResultAdapter(Result result) {
this.result = result;
}
public TextResult getTextResult() {
return result instanceof TextResult ? (TextResult) result :null;
}
public NumberResult getNumberResult() {
return result instanceof NumberResult ? (NumberResult) result :null;
}
}
public static interface Result {
}
public static class TextResult implements Result {
private String value;
private String reference;
public TextResult(String value, String reference) {
this.value = value;
this.reference = reference;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public String getReference() {
return reference;
}
public void setReference(String reference) {
this.reference = reference;
}
}
public static class NumberResult implements Result {
private int minVal;
private int maxVal;
public NumberResult(int minVal, int maxVal) {
this.minVal = minVal;
this.maxVal = maxVal;
}
public int getMinVal() {
return minVal;
}
public void setMinVal(int minVal) {
this.minVal = minVal;
}
public int getMaxVal() {
return maxVal;
}
public void setMaxVal(int maxVal) {
this.maxVal = maxVal;
}
}
}
Also note you can nest templates in a grid if that helps you http://forum.zkoss.org/question/84802/problem-with-dyanmic-columns-and-rows-in-a-grid/
rickcr ( 2013-03-09 03:51:56 +0800 )edituse @teamplate (note:the following code is not verified in runtime)
<grid vflex="1" model="@load(vm.examResults) @template(c:isInstance('myPackage.TextResult', each)?'textTemp':'numberTemp')">
<columns>
<column hflex="1" label="Value" />
<column hflex="2" label="Reference" />
<column hflex="1" label="Min." />
<column hflex="1" label="Max." />
</columns>
<template name="textTemp">
<row>
<label value="${each.value}" />
<label value="${each.reference}" />
<label value="" />
<label value="" />
</row>
</template>
<template name="numberTemp">
<row>
<label value="${each.value}" />
<label value="" />
<label value="${each.minValue}" />
<label value="${each.maxValue}" />
</row>
</template>
</grid>
Asked: 2013-03-04 13:19:24 +0800
Seen: 174 times
Last updated: Mar 11 '13
composite component help [closed]
EL in a forEach @command not working?
Cardlayout animation is broken
Grid RowRender slow using 6.5.1 and sizable=true
setVisible(false), component will load or not
Decimalbox and doublebox value rounded on iPad
history management with page status
Deselect listbox by clicking outside