ZK - Open Source Ajax Java FrameworkZK - Open Source Ajax Java Framework

ZK 6 Composite component getter not working in view model

jaan
14 Jan 2012 13:42:54 GMT
14 Jan 2012 13:42:54 GMT

Hi,

I'm a very newbie in ZK and Java. But I do love the technology by now.
After a lot of trial (and more error) I bumped into the following problem.
I've created a composite component following this smalltalk: Define Composite Component using Java Annotation in ZK6


@Composite(name="testcomposite")
public class TestComposite extends Textbox implements IdSpace {
	private String someProp;
	
	public TestComposite() {
		
	}

	public String getSomeProp() {
		return this.getValue(someProp);
	}
	public void setSomeProp(String someProp) {
		this.setValue(someProp)
	}
}

Now if I bind some data from a viewModel to this someProp-property it is set (setSomeProp is called).
So when I try :
<testcomposite someProp="@bind(vm.selected.website)" />

the textbox is filled with the website data.
But when I try to save the data nothing is changed in vm.selected. It never updates the website value.

I'm doing stupid things? Am I forgetting something?

jaan

dennis
6 Feb 2012 04:49:10 GMT
6 Feb 2012 04:49:10 GMT

hi,
you need addition information(annotation) to support save-binding in composite or other custom component.
please follow this feature request. http://tracker.zkoss.org/browse/ZK-833

pmq
16 Mar 2012 10:15:29 GMT
16 Mar 2012 10:15:29 GMT

Hi Dennis,

I have the same troubles with composite component.

I did getter and setter for Date value (in my case).

I send event onChange, when internal component is updated.


Events.postEvent(Events.ON_CHANGE,this,null);


Different is only in my annotations:
<testcomposite someProp="@{vm.selected.website,save-when='self.onChange'}" self="@action(recalculate,when='onChange')"/>

Action "recalculate" works fine, but data binding works only for setter.

When can I expect solution for this issue?

pmq

dennis
19 Mar 2012 09:30:19 GMT
19 Mar 2012 09:30:19 GMT

@jaan
this feature was resolved by http://tracker.zkoss.org/browse/ZK-883 already,
following is the example to enable binding for imagelabel in the smalltalk http://books.zkoss.org/wiki/Small_Talks/2011/December/Define_Composite_Component_using_Java_Annotation_in_ZK6.

@ComponentAnnotation({"description:@ZKBIND(ACCESS=both,SAVE_EVENT=onAfterEdit)","title:@ZKBIND(ACCESS=both,SAVE_EVENT=onAfterEdit)"})
public class ImageLabel extends Div implements IdSpace {..}

dennis
19 Mar 2012 09:32:36 GMT
19 Mar 2012 09:32:36 GMT

@pmq
form the syntax, you are trying zkbind1
did you try zkbind2 ? it is more powerful and easier than zkbind1
you can read document here. http://books.zkoss.org/wiki/ZK%20Developer's%20Reference/MVVM

pmq
19 Mar 2012 13:49:58 GMT
19 Mar 2012 13:49:58 GMT

Hi Dennis,
Where can I find package for Componentannotation?
I cannot find library with org.zkoss.zk.ui.annotation.ComponentAnnotation

pmq

dennis
20 Mar 2012 00:50:11 GMT
20 Mar 2012 00:50:11 GMT

it is after zk 6.0.1, it is freshly now. try here, http://www.zkoss.org/download/freshly/

shumy
20 Mar 2012 12:07:24 GMT
20 Mar 2012 12:07:24 GMT

Adding to this. Is there any support for child components? Like the one I describe in ZK 6 Composite Feature

ws13
8 Apr 2012 20:24:58 GMT
8 Apr 2012 20:24:58 GMT

Hi,

I follow the small talk to composite a component and and it making an error to deploy:

Caused by: java.lang.IncompatibleClassChangeError: Found class org.objectweb.asm.AnnotationVisitor, but interface was expected

It seems that the 3 jars added + zk 6.0.1 make this error. (in the original version 6.0 also).

thanks in advance

ws13
8 Apr 2012 22:59:14 GMT
8 Apr 2012 22:59:14 GMT

Hi,

I have been trying to deploy your example and it was impossible. I have been learning how to make the composite components with the example that is found in the demo components: ListBox:DualListBox. It was impossible that this component updated the status populating the input listbox in MVVM, bumping into the same problem

<emailDualListbox id="dualLBox" candidateModel="@init(initEmailDualBox)"/>

thank in advance

dennis
9 Apr 2012 07:04:06 GMT
9 Apr 2012 07:04:06 GMT

I think you have multiple asm jars in the project and they conflict.

ws13
9 Apr 2012 23:30:55 GMT
9 Apr 2012 23:30:55 GMT

Hi,

Thanks for your help.... I built the component step by step and is working (is updated form VMMV to Component but not from component to VMMV).... The only problem that onAfterEvent is not fire... I dont know why, any idea!!

<div id="EmailDiv">	
		<emailDualListbox id="dualLBox" candidateList="@bind(vm.candidateEmailDualBox)" chosenList="@bind(vm.chosenEmailDualBox)" >
			<attribute name="onAfterEdit"><![CDATA[
				alert("new title is: "+event.candidateList);
				alert("new title is: "+event.chosenList);
			]]></attribute>
		</emailDualListbox>
</div>

	public static final String ON_AFTER_EDIT = "onAfterEdit";

	public class AfterEditEvent extends Event{

		private static final long serialVersionUID = 7283694297879164498L;

		public AfterEditEvent() {
			super(ON_AFTER_EDIT, EmailDualListbox.this);
		}
		
		public List<CodeExtraInfoVo> getCandidateList(){
			return new ArrayList<CodeExtraInfoVo>(candidateModel);
		}

		public List<CodeExtraInfoVo> getChosenList() {
			System.out.println("dddddddd");
			return new ArrayList<CodeExtraInfoVo>(chosenModel);
		}


Do you know if i have to do something special to updated the information from the component to VMMV?

Thanks in advance...

dennis
12 Apr 2012 08:52:01 GMT
12 Apr 2012 08:52:01 GMT

if you are talking about dual listbox selection, I just wrote a simple example for you.


MoveSelectionVM.java
package j1p545q6$v2;


import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.zkoss.bind.annotation.Command;
import org.zkoss.bind.annotation.NotifyChange;

public class MoveSelectionVM {

Set<String> selection1;
List<String> list1;
Set<String> selection2;
List<String> list2;

public MoveSelectionVM(){
list1 = new ArrayList<String>();
list2 = new ArrayList<String>();
selection1 = new HashSet<String>();
selection2 = new HashSet<String>();
for (int i=0;i<10;i++){
list1.add("Item "+i);
}
}

public Set<String> getSelection1() {
return selection1;
}

public void setSelection1(Set<String> selection1) {
this.selection1 = selection1;
}

public List<String> getList1() {
return list1;
}

public Set<String> getSelection2() {
return selection2;
}

public void setSelection2(Set<String> selection2) {
this.selection2 = selection2;
}

public List<String> getList2() {
return list2;
}

@Command
@NotifyChange({"list1","list2","selection1","selection2"})
public void moveToList1(){
if(selection2!=null && selection2.size()>0){
list1.addAll(selection2);
list2.removeAll(selection2);
selection1.addAll(selection2);
selection2.clear();
}
}

@Command
@NotifyChange({"list1","list2","selection1","selection2"})
public void moveToList2(){
if(selection1!=null && selection1.size()>0){
list2.addAll(selection1);
list1.removeAll(selection1);
selection2.addAll(selection1);
selection1.clear();
}
}


}


index.zul
<window apply="org.zkoss.bind.BindComposer" viewModel="@id('vm') @init('j1p545q6$v2.MoveSelectionVM')">

<hlayout>
<vlayout>
List1
<listbox model="@bind(vm.list1)" selectedItems="@bind(vm.selection1)" multiple="true" width="300px" height="300px"/>
</vlayout>
<vbox vflex="1" pack="middle">
<button label=">" onClick="@command('moveToList2')"/>
<button label="<" onClick="@command('moveToList1')"/>
</vbox>
<vlayout>
List2
<listbox model="@bind(vm.list2)" selectedItems="@bind(vm.selection2)" multiple="true" width="300px" height="300px"/>
</vlayout>
</hlayout>
</window>

please try it on fiddle and switch the zk version to 6.0.0

ws13
12 Apr 2012 11:38:46 GMT
12 Apr 2012 11:38:46 GMT

Hi Dennis,

i am not explain myself very well, apologizes about that. I will try again:

1.- i make it the dualboxlist like you do in your last post

2.- I get this and make it a composite component with that, following yours recomendation. Right i can instance this component populating from VMMV a list and initializating the component in correct way. When i pass a elemnt i can get the event and the element updated.

3.- I create a zul page with the composite and a button to store in DB the chosen elements:

<emailDualListbox id="dualLBox" candidateList="@bind(vm.candidateEmailDualBox)" chosenList="@bind(vm.chosenEmailDualBox)" >
<button label="Store" onClick="@command('StoreDB')"/>

4.- The problem is the folowing:

The dualBoxList has to list:
-> One the initially the candidatesList form VMMV is OK: the candistes is render n the component correctly.
-> When pass elements from the candidates to the chosen it is fire an event and it is working fine also . I can get it the element also, no problem...

but when press StoreDB button to get chosenElements in the MVVM function is fired and i get the chosenElement list empty (or with the same elements when it was initially ). that it menas that from the composite components has to inform the VMMV about this chosenlist is change and this is not happens. I know that i can use directly the event form the component to updated the chosenList for each buttton, buit to avoid to do that for every element that the user select and avoid more ajax call innecesaries i would like to get the whole list form the component.

This means that i can send and update informaton from MVVM => Component but in reverse way from the COmponent to MVVM is not happens and maybe the only solution for that is to updated in each event increasing the ajax call to the server....

Regards

dennis
13 Apr 2012 09:48:11 GMT
13 Apr 2012 09:48:11 GMT

Could you provide your implementation(and the test-case) to me, hard to know what you have done (and what is wrong or missing in your composite implementation).
Can you share the code in gist http://gist.github.com?

ws13
15 Apr 2012 10:11:09 GMT
15 Apr 2012 10:11:09 GMT

Here you have the link with the code:

git@gist.github.com:741eba05139d98065066.git

regards

ws13
15 Apr 2012 10:33:32 GMT
15 Apr 2012 10:33:32 GMT

https://gist.github.com/741eba05139d98065066

ws13
15 Apr 2012 17:28:10 GMT
15 Apr 2012 17:28:10 GMT

Create.Zul


<?taglib uri="http://www.zkoss.org/dsp/web/core" prefix="c"?>

<zk>

<window border="none" width="100%" height="100%" xmlns:w="client" >
	<include id="includeStyle" src="/style/default.zul" ></include>
	<borderlayout width="100%" height="100%" vflex="true">




		<center border="normal" flex="true"  class="center" style="overflow:auto; background: white" autoscroll="true"
		apply="org.zkoss.bind.BindComposer" viewModel="@id('vm') @init('es.migou.myamp.fe.myamp.CreateAmpVm')" 
		form="@id('fx') @save(vm.codeVo , before='save' )">

			<vlayout spacing="2%" style="overflow:auto; background: white">

				<div id="msgAreaRememberWindow" visible="@load(vm.isVisibleMessageArea)" >
					<label value="@load(vm.messageArea)" style="color : #FF0000; font-style:italic;font-size:15px;"></label>
				</div>

				<div align="left">
					<label value="${labels.newAmp.main.infoTxt}" style="font-size: 15px;"></label>				
				</div>




				<groupbox id="EmailGroup" mold="3d" closable="true" width="50%" open="false"> 
					<caption image="/images/icon_email.png" label="Email" ></caption>
						<div id="EmailDiv">	
							<emailDualListbox id="dualLBox" candidateList="@bind(vm.candidateEmailDualBox)" chosenList="@bind(vm.chosenEmailDualBox)" >
								<attribute name="onChoose"><![CDATA[
										alert("new title is: "+event.candidateList);
										alert("new title is: "+event.chosenList);
									]]></attribute>
							</emailDualListbox>
						</div>
				</groupbox>





				<vlayout>
					<button label="Guardar" onClick="@command('save')"></button>
					<button label="Atrás" onClick="@command('goToWelcome')" ></button>				
				</vlayout>

			</vlayout>



		</center>

		<east width="5%" border="normal" flex="true" vflex="min" >


		</east>

		<south border="normal" class="footer" size="45px">
			<include src="/footer/footer.zul"></include>
		</south>

	</borderlayout>


</window>


</zk>

CreateAmpVm.java


package es.migou.myamp.fe.myamp;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import org.apache.log4j.Logger;
import org.zkoss.bind.annotation.Command;
import org.zkoss.bind.annotation.Init;
import org.zkoss.bind.annotation.NotifyChange;
import org.zkoss.util.resource.Labels;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zk.ui.util.Clients;

import es.migou.myamp.be.myamp.MyAmpLocator;
import es.migou.myamp.be.myamp.service.code.CodeServiceRemote;
import es.migou.myamp.be.myamp.vo.code.CodeExtraInfoVo;
import es.migou.myamp.be.myamp.vo.code.CodeVo;
import es.migou.myamp.be.myamp.vo.enumerates.CodeTypeEnum;
import es.migou.myamp.fe.vo.ComboVo;


public class CreateAmpVm
{
	private static final Logger log = Logger.getLogger(CreateAmpVm.class);
	private MyAmpLocator locator;
	
	
	private CodeVo codeVo;
	private String messageArea;
	private Boolean isVisibleMessageArea;
	
	private List<ComboVo> codeTypeList;
	private ComboVo selectedCodeType;

	
	private List<CodeExtraInfoVo> candidateEmailDualBox;
	private List<CodeExtraInfoVo> chosenEmailDualBox;
	
	
	 @Init(superclass=true)
	 public void init()
	 {
		locator=MyAmpLocator.getInstance();
		codeVo=new CodeVo();
		messageArea="";
		isVisibleMessageArea=false;
		this.loadCodeTypeList();
		selectedCodeType=new ComboVo();
		this.loadEmailDualList();
		
	 }
	
	@Command("goToHome")
    public void goToWelcome(){
		log.debug("[CreateAmpVm - goToHome] - redirect:/welcome.zul");
		Executions.sendRedirect("/welcome.zul");
        
    }
	
	@NotifyChange({"selectedCodeType"})
	@Command("onSelectCodeType")
    public void onSelectCodeType()
	{
		log.debug("[CreateAmpVm - onSelectCodeType] - init");
		log.debug("[CreateAmpVm - onSelectCodeType] - selectedCodeType:"+selectedCodeType.getCode());
		
		if (CodeTypeEnum.ADDRESS_BOOK.toString().equals(selectedCodeType.getCode())){
			Clients.evalJavaScript("jq('$personalInfoDiv').hide().slideDown(1000);");
			Clients.evalJavaScript("jq('$professionalInfoDiv').show().slideUp(1000);");
			this.loadCodeTypeList();
				
		}else if(CodeTypeEnum.VCARD_COMPANY.toString().equals(selectedCodeType.getCode())){
			Clients.evalJavaScript("jq('$personalInfoDiv').show().slideUp(1000);");
			Clients.evalJavaScript("jq('$professionalInfoDiv').hide().slideDown(1000);");
		
		}else if(CodeTypeEnum.VCARD_PROFESIONAL.toString().equals(selectedCodeType.getCode())){
			Clients.evalJavaScript("jq('$personalInfoDiv').hide().slideDown(1000);");
			Clients.evalJavaScript("jq('$professionalInfoDiv').hide().slideDown(1000);");
		}
		
        
    }
	
	
	
 
	@NotifyChange({"isVisibleMessageArea", "messageArea"})
	@Command("save")
    public void save()
	{
		long T1=System.currentTimeMillis();
		log.debug("[CreateAmpVm - save] -INIT ");
		isVisibleMessageArea=true;
		
		try{
			log.debug("[CreateAmpVm - save] - codeVo: "+codeVo);
			log.debug("[CreateAmpVm - save] - Creating codeVo...");
			
			log.debug("[CreateAmpVm - save] - candidateEmailDualBox:"+candidateEmailDualBox);
			log.debug("[CreateAmpVm - save] - chosenEmailDualBox:"+chosenEmailDualBox);
			
//			CodeServiceRemote codeService = locator.getCodeService();
//			codeService.createCode(codeVo);
			messageArea=Labels.getLabel("newAccount.suscess.000");
			
		}catch (Exception ex){
			log.error("[CreateAmpVm - save] - Error:",ex);
			messageArea=Labels.getLabel("general.error.001");
	
		}finally{
			log.debug("[CreateAmpVm - save] - isVisibleMessageArea:"+isVisibleMessageArea);
			log.debug("[CreateAmpVm - save] - messageArea:"+messageArea);
			log.debug("[CreateAmpVm - save] - Finish Timing:"+(System.currentTimeMillis()-T1));	
		}
    }

	
	
	public CodeVo getCodeVo() {
		return codeVo;
	}

	public void setCodeVo(CodeVo codeVo) {
		this.codeVo = codeVo;
	}

	public String getMessageArea() {
		return messageArea;
	}

	public void setMessageArea(String messageArea) {
		this.messageArea = messageArea;
	}

	public Boolean getIsVisibleMessageArea() {
		return isVisibleMessageArea;
	}

	public void setIsVisibleMessageArea(Boolean isVisibleMessageArea) {
		this.isVisibleMessageArea = isVisibleMessageArea;
	}

	
	public void loadEmailDualList()
	{
		candidateEmailDualBox=new ArrayList<CodeExtraInfoVo>();
		chosenEmailDualBox=new ArrayList<CodeExtraInfoVo>();
		
		long uuid=0;
		CodeExtraInfoVo codeExtraInfoVo = null;

		codeExtraInfoVo = new CodeExtraInfoVo();
		codeExtraInfoVo.setIdCode(uuid++);
		codeExtraInfoVo.setSubcategory("Email");
		codeExtraInfoVo.setValue(uuid+"ss@hotmail.com");
		candidateEmailDualBox.add(codeExtraInfoVo);

		codeExtraInfoVo = new CodeExtraInfoVo();
		codeExtraInfoVo.setIdCode(uuid++);
		codeExtraInfoVo.setSubcategory("Email");
		codeExtraInfoVo.setValue(uuid+"sxxxxxxxdsds@hotmail.com");
		candidateEmailDualBox.add(codeExtraInfoVo);
		System.out.println("loadEmailDualList - FINISH");
	}
	
	
	
	public void loadCodeTypeList()
	{
		System.out.println("loadCodeTypeList");
		List<ComboVo> codeTypeListAux=new ArrayList<ComboVo>();
		Collection<String> codeTypeEnumList=CodeTypeEnum.literals();
		Iterator<String> ite=codeTypeEnumList.iterator();
		while(ite.hasNext())
		{
			String code=ite.next();
			ComboVo comboVo=new ComboVo(code , Labels.getLabel("CodeTypeEnum."+code));
			codeTypeListAux.add(comboVo);
		}
		this.codeTypeList =codeTypeListAux;
		
	}


	
	public List<ComboVo> getCodeTypeList() {
		return codeTypeList;
	}

	public void setCodeTypeList(List<ComboVo> codeTypeList) {
		this.codeTypeList = codeTypeList;
	}

	public ComboVo getSelectedCodeType() {
		return selectedCodeType;
	}

	public void setSelectedCodeType(ComboVo selectedCodeType) {
		this.selectedCodeType = selectedCodeType;
	}

	public List<CodeExtraInfoVo> getCandidateEmailDualBox() {
		return candidateEmailDualBox;
	}

	public void setCandidateEmailDualBox(List<CodeExtraInfoVo> candidateEmailDualBox) {
		this.candidateEmailDualBox = candidateEmailDualBox;
	}

	public List<CodeExtraInfoVo> getChosenEmailDualBox() {
		return chosenEmailDualBox;
	}

	public void setChosenEmailDualBox(List<CodeExtraInfoVo> chosenEmailDualBox) {
		this.chosenEmailDualBox = chosenEmailDualBox;
	}


	
	 
	
}



emailDualListbox.zul

<!-- View of customized component DualListbox -->

<vlayout vflex="true" hflex="true">
	<zscript><![CDATA[
		String imgPath = "/images/composite/emailDualList";
	]]></zscript>
	
	<space spacing="2%"></space>
	<hlayout>
		<vlayout hflex="1"></vlayout>
	
		<label  value="Email"></label>
		<textbox hflex="1" id="codeInpt" value="" ></textbox>
		<textbox hflex="1" id="cods" value="" ></textbox>
		<button id="add" label="Add" image="${imgPath}/icon_add_email.png"
        	hoverImage="${imgPath}/icon_add_email_hover.png" style="cursor:pointer" ></button>
        <vlayout hflex="1"></vlayout>
	</hlayout>


	<hlayout vflex="true" hflex="true"  spacing="2%">
		<listbox id="candidateLb" vflex="true" hflex="true" multiple="true" emptyMessage="No items match your search">
			<listhead>
				<listheader hflex="min"></listheader>
				<listheader hflex="min" label="Tipo"></listheader>
				<listheader hflex="min" label="Email"></listheader>
			</listhead>
			<template name="model">
				<listitem>
					<listcell image="${imgPath}/icon_email.png"></listcell>
					<listcell label="${each.subcategory}"></listcell>
					<listcell label="${each.value }"></listcell>
				</listitem>
			</template>
		</listbox>
		<vbox  vflex="true" spacing="10px" align="center" pack="center">
			<image style="cursor:pointer" id="chooseAllBtn" src="${imgPath}/rightrightarrow_g.png" ></image>
			<image style="cursor:pointer" id="chooseBtn" src="${imgPath}/rightarrow_g.png" ></image>
			<image style="cursor:pointer" id="removeBtn" src="${imgPath}/leftarrow_g.png" ></image>
			<image style="cursor:pointer" id="removeAllBtn" src="${imgPath}/leftleftarrow_g.png" ></image>
		</vbox>
		<listbox id="chosenLb" vflex="true" hflex="true" width="380px" multiple="true" emptyMessage="Dont select Any items">
			<listhead>
				<listheader hflex="1"></listheader>
				<listheader hflex="1" label="Tipo"></listheader>
				<listheader hflex="3" label="Email"></listheader>
			</listhead>
			<template name="model">
				<listitem>
					<listcell image="${imgPath}/icon_email.png"></listcell>
					<listcell label="${each.subcategory}"></listcell>
					<listcell label="${each.value }"></listcell>
				</listitem>
			</template>
		</listbox>
	
		<vbox spacing="10px">
			<image style="cursor:pointer" id="topBtn" src="${imgPath}/upuparrow_g.png" ></image>
			<image style="cursor:pointer" id="upBtn" src="${imgPath}/uparrow_g.png" ></image>
			<image style="cursor:pointer" id="downBtn" src="${imgPath}/downarrow_g.png" ></image>
			<image style="cursor:pointer" id="bottomBtn" src="${imgPath}/downdownarrow_g.png" ></image>
		</vbox>
	</hlayout>

</vlayout>


EmailDualListbox.java

package es.migou.myamp.fe.composite;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

import org.zkoss.composite.Composite;
import org.zkoss.composite.Composites;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.IdSpace;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zk.ui.select.annotation.Listen;
import org.zkoss.zk.ui.select.annotation.Wire;
import org.zkoss.zul.Div;
import org.zkoss.zul.ListModelList;
import org.zkoss.zul.Listbox;

import es.migou.myamp.be.myamp.vo.code.CodeExtraInfoVo;



@Composite(name="emailDualListbox")
public class EmailDualListbox extends Div implements IdSpace {
	/**
	 * 
	 */
	private static final long serialVersionUID = 5183321186606483396L;
	
	@Wire
	private Listbox candidateLb;
	@Wire
	private Listbox chosenLb;

	private ListModelList<CodeExtraInfoVo> candidateModel;
	private ListModelList<CodeExtraInfoVo> chosenModel;
	
	public EmailDualListbox() {
		
		Composites.doCompose(this, null);
	}
	
	
	@Listen("onClick = #chooseBtn")
	public void chooseItem() {
		Events.postEvent(new ChooseEvent(this, chooseOne()));
	}

	@Listen("onClick = #removeBtn")
	public void unchooseItem() {
		Events.postEvent(new ChooseEvent(this, unchooseOne()));
	}

	@Listen("onClick = #chooseAllBtn")
	public void chooseAllItem() {
		for (int i = 0, j = candidateModel.getSize(); i < j; i++) {
			chosenModel.add(candidateModel.getElementAt(i));
		}
		candidateModel.clear();
	}

	@Listen("onClick = #removeAllBtn")
	public void unchooseAll() {
		for (int i = 0, j = chosenModel.getSize(); i < j; i++) {
			candidateModel.add(chosenModel.getElementAt(i));
		}
		chosenModel.clear();
	}

	@Listen("onClick = #topBtn")
	public void top() {
		int i = 0;
		Iterator<CodeExtraInfoVo> iterator = new LinkedHashSet<CodeExtraInfoVo>(chosenModel.getSelection()).iterator();
		while (iterator.hasNext()) {
			CodeExtraInfoVo selectedItem = iterator.next();
			chosenModel.remove(selectedItem);
			chosenModel.add(i++, selectedItem);
			chosenModel.addToSelection(selectedItem);
		}
	}

	@Listen("onClick = #upBtn")
	public void up() {
		Set<CodeExtraInfoVo> selected = chosenModel.getSelection();
		if (selected.isEmpty())
			return;
		int index = chosenModel.indexOf(selected.iterator().next());
		if (index == 0 || index < 0)
			return;
		CodeExtraInfoVo selectedItem = chosenModel.get(index);
		chosenModel.remove(selectedItem);
		chosenModel.add(--index, selectedItem);
		chosenModel.addToSelection(selectedItem);

	}

	@Listen("onClick = #downBtn")
	public void down() {
		Set<CodeExtraInfoVo> selected = chosenModel.getSelection();
		if (selected.isEmpty())
			return;
		int index = chosenModel.indexOf(selected.iterator().next());
		if (index == chosenModel.size() - 1 || index < 0)
			return;
		CodeExtraInfoVo selectedItem = chosenModel.get(index);
		chosenModel.remove(selectedItem);
		chosenModel.add(++index, selectedItem);
		chosenModel.addToSelection(selectedItem);
	}

	@Listen("onClick = #bottomBtn")
	public void bottom() {
		Iterator<CodeExtraInfoVo> iterator = new LinkedHashSet<CodeExtraInfoVo>(chosenModel.getSelection()).iterator();
		while (iterator.hasNext()) {
			CodeExtraInfoVo selectedItem = iterator.next();
			chosenModel.remove(selectedItem);
			chosenModel.add(selectedItem);
			chosenModel.addToSelection(selectedItem);
		}
	}

	/**
	 * Set new candidate ListModelList.
	 * 
	 * @param candidate is the  of candidate list model
	 */
	public void setCandidateList(List<CodeExtraInfoVo> candidate) {
		System.out.println("setCandidateList candidate:"+candidate);
		candidateLb.setModel(this.candidateModel = new ListModelList<CodeExtraInfoVo>(candidate));
		chosenLb.setModel(chosenModel = new ListModelList<CodeExtraInfoVo>());
	}
	
	public List<CodeExtraInfoVo> getCandidateList() 
	{
		System.out.println("getCandidateList");
		return new ArrayList<CodeExtraInfoVo>(candidateModel);
	}
	

	/**
	 * @return current chosen  list
	 */
	public List<CodeExtraInfoVo> getChosenList() {
		System.out.println("getChosenList");
		return new ArrayList<CodeExtraInfoVo>(chosenModel);
	}

	public void setChosenList(List<CodeExtraInfoVo> chosen) {
		chosenLb.setModel(this.chosenModel = new ListModelList<CodeExtraInfoVo>(chosen));
		
	}
	
	private Set<CodeExtraInfoVo> chooseOne() {
		Set<CodeExtraInfoVo> set = candidateModel.getSelection();
		for (CodeExtraInfoVo selectedItem : set) {
			chosenModel.add(selectedItem);
			candidateModel.remove(selectedItem);
		}
		return set;
	}

	private Set<CodeExtraInfoVo> unchooseOne() {
		Set<CodeExtraInfoVo> set = chosenModel.getSelection();
		for (CodeExtraInfoVo selectedItem : set) {
			candidateModel.add(selectedItem);
			chosenModel.remove(selectedItem);
		}
		return set;
	}

	



	// Customized Event
	public class ChooseEvent extends Event {

		private static final long serialVersionUID = -7334906383953342976L;

		public ChooseEvent(Component target, Set<CodeExtraInfoVo> data) {
			super("onChoose", target, data);
		}
		
		public List<CodeExtraInfoVo> getCandidateList(){
			System.out.println("ChooseEvent - getCandidateList");
			return new ArrayList<CodeExtraInfoVo>(candidateModel);
		}

		public List<CodeExtraInfoVo> getChosenList() {
			System.out.println("ChooseEvent - getChosenList");
			return new ArrayList<CodeExtraInfoVo>(chosenModel);
		}
	}
	
	
	
}

dennis
18 Apr 2012 10:41:58 GMT
18 Apr 2012 10:41:58 GMT

OK, you have to let binder know when to save the value of component back to bean when the component change (with the onChoose event fired) by adding zkbind annotation of your composite componet.
here, try to add this in EmailDualListbox

@Composite(name="emailDualListbox")
@ComponentAnnotation({"candidateList:@ZKBIND(ACCESS=both,SAVE_EVENT=onChoose)","chosenList:@ZKBIND(ACCESS=both,SAVE_EVENT=onChoose)"})
public class EmailDualListbox extends Div implements IdSpace {
..
}

ws13
22 Apr 2012 17:19:50 GMT
22 Apr 2012 17:19:50 GMT

Thanks you very much for oyur help. It has been very worthy..