# foreach

ftmichael
129 1

hi there,
i'm in trouble. i've just read documentations and forum-posts, but i've not found any solution for my problem.

i have a composer: MyComposer.java
public void doAfterCompose(Component comp) throws Exception {
super.doAfterCompose(comp);
//new UserDB();
UserDB.createPOIs();
//wire variables
Components.wireVariables(comp, this);
//register onXxx event listeners
//auto forward
comp.setAttribute("test", this, false);
}
public List<String> getList(){
return list;
}
and a zul page: index.zul where i apply my MyComposer.java
in this zul file i want to loop throught the returned list:
<zk forEach="${test.testList}" > <textbox value="${each}" />
</zk>

the problem is, that this won't work. i found out that in "foreach" there is only EL allowed.
i have to access the variable defined in MyComposer.

I hope someone can help me.
Best Regards

delete retag edit

## 18 Replies

ftmichael
129 1

ok i've got it working by using session.setAttribute and bind the component.
my next question is, when i edit the textbox and want to override the current value i have to do that with the onChange event manually or will the "set" methode be called?
the problem is: <textbox id="txt" value="${each}" /> in java i can do the following: public void onChange$txt{} but if more than two textboxes are generated by foreach there is a conflict because all textboxes have the same id. how can i solve this?

<textbox value="Eins"/>
<textbox value="Zwei"/>

if the first textbox changed his value to "One" this new value should also replace "Eins" in the java-List "list" correctly.

caclark
1753 2 5
http://clarktrips.intltwi...

First, use the code tags available in this forum editor. Look at the line immediate above the text editor when you're creating a new thread or right above the Post Reply button when replying.

Secondly, the answer to your original post is that forEach is evaluated, using only EL, in the component creation phase of the page's lifecycle. The doAfterCompose() is called later in the rendering phase. So, when your ZUL was evaluated, "testList" had no value.

There's a (apparently) little known interface that GFC implements named ComposeExt that has a doBeforeCompose() method. This is called BEFORE the page is rendered, so it's appropriate to initialize variables there that EL expressions need. Just be aware that when using forEAch, you'll not be able to change the list of components that are generated. EL and forEach are 1 time deals because of them being done during the component creation phase (aka the composer's Compose time in the doBefore/AfterCompose()) unlike those created by databinding.

Third, you're doing things in your doAfterCompose() method that are already done for you. The Components::wireVariables and Components::addForwards are done for you by GFC and its ancestors. Your code should be:

    public void doAfterCompose(Component comp) throws Exception
{
super.doAfterCompose(comp);  // stuff done for you here...
//new UserDB();
UserDB.createPOIs();
}

public void doBeforeCompose(Component comp) throws Exception
{
super.doBeforeCompose(comp);
comp.setAttribute("test", this, false);
}


ftmichael
129 1

i'm knowing the issue with EL.
i'm searching for a solution where i can create textboxes at runtime, where databinding can deal with onChange-Events.
the current solution is i'm creating a listbox with a model="@{win$composer.getList}" then i'm looping the list and create textboxes in listcell. that's working fine, but i don't want to use a listbox or gridbox. i just want the number of textboxes with databinding. i hope you understand my problem. answered 2011-06-02 08:01:36 +0800 caclark 1753 2 5 http://clarktrips.intltwi... Not following you so much... answered 2011-06-02 08:16:12 +0800 ftmichael 129 1 ok from beginning (i don't know the correct syntax): <?init class="org.zkoss.zkplus.databind.AnnotateDataBinderInit" root="win" ?> <window id="win" apply="myComposer"> <listbox id="box" model="@{win$composer.getAll}">
<listheader label="a lot of text" sort="auto" />
<listitem self="each..." value="...">
<listcell ><textbox value="@{list.text}" /></listcell
</listitem>
</listbox>
</window>


this snippet works fine, if i'm changing the textbox the databinder binds the new value. he calls list.setText().
the problem is, that i won't use listbox. i want to do it like for-each, but it only works with EL, so when i'm changing the text, the methode list.setText() is not called because of EL.
the result should look like this:

<vlayout>
<zk foreach...>
<vbox><textbox value="@{list.text}" /></vbox>
</zk>
</vlayout>

this example won't work because of EL.

caclark
1753 2 5
http://clarktrips.intltwi...

Hook the onChange or onChanging event, as appropriate, and forward it to your controller. Also, look into adding a custom attribute to the textbox and assigning it the value of "each" from your foreach iteration. This will let you retrieve the domain model when the onChange/onChanging event is fired and update the correct value.

Remind me why you don't want to use databinding?

ftmichael
129 1

i want to use databinding! but it doesn't work with foreach because of EL... databinding is for me, that zk determines if it have to call setText() and getText(). an this is not possible with foreach and EL

caclark
1753 2 5
http://clarktrips.intltwi...

You're only going to be able to use databinding with components that support the model attribute.

...but i don't want to use a listbox or gridbox...


Why not?

ftmichael
129 1

because its a table look&feel and in the next step i want to replace textbox with ckeditor and they can't be placed in listbox.

9393 3 7 16
http://www.oxitec.de/

ftmichael, automatically databinding is not the solution for all things !!!

Try to use an Itemrenderer. In it you can do what you want with your textboxes. And like Cary said, use than the forwarding of the textbox Events.

not tested

public class MyRenderer implements ListitemRenderer {

@Override
public void render(Listitem item, Object data) throws Exception {

final Customer customer = (Customer) data;

Listcell lc = new Listcell(customer.getKunNr());
lc.setParent(item);

Listcell lc = new Listcell();
Textbox txtbox = new Textbox();
txtbox.setParent(item);
ComponentsCtrl.applyForward(txtbox, "onChanging=onChangingMethodInTheController");

item.Value( data) ;

}


best
Stephan

[hide preview]