0

Databinding timing question

asked 2010-02-25 08:12:59 +0800

TOtte gravatar image TOtte
93 2

Hi,
I got a strange problem right now with the databinding of comboboxes. I am using ZK 5 with spring and hibernate.

In my zul i have (only snippets because it is quite long):

<listbox id="zu_psListbox" multiple="true" model="@{controller.getAlleZu_ps, load-after='btnCancel.onClick, btnNew.onClick'}"
 							selectedItem="@{controller.currentZu_ps}" rows="10" mold="paging" pageSize="10">

<listitem id="zu_psListitem" self="@{each='zu_ps'}" value="@{zu_ps}">

<label value="Personalart Bereich:"></label>
<combobox id="personalartBereichCombobox" readonly="true" model="@{controller.getAllePersonalartBereiche}" value="@{controller.currentZu_ps.vorlage_ps.bereich, save-after='none'}">
	<comboitem self="@{each=bereich}" label="@{bereich}" value="@{bereich}"></comboitem>
</combobox>
<label value="Personalart Gruppe:"></label>
<combobox id="personalartGruppeCombobox" readonly="true" model="@{controller.getAllePersonalartGruppen, load-after='personalartBereichCombobox.onChange'}" value="@{controller.currentZu_ps.vorlage_ps.gruppe, save-after='none'}">
       <comboitem self="@{each=vorlage_ps}" label="@{vorlage_ps.gruppe}" value="@{vorlage_ps}"></comboitem>
</combobox>

The items of the second combobox are dependend on the selection of the first combobox.

My Problem starts when I reload the page. The Object is loaded from the database, but the selectedItems of the Comboboxes are not set. If the User then just changes some other values and tries to update without touching the comboboxes the selectedItems are null.
I need the selected Items for the update, so I have to set them after loading the page.
I am doing this by catching the onClick$zu_psListitem event and then looking for the right object in the comboboxes.
My method to do this:

	public void onClick$zu_psListitem() {
		for (Object object : personalartBereichCombobox.getItems()) {
			Comboitem comboitem = (Comboitem) object;
			if (currentZu_ps.getVorlage_ps().getBereich().equals(comboitem.getValue())) {
				personalartBereichCombobox.setSelectedItem(comboitem);
				binder.loadComponent(personalartGruppeCombobox);
			}
		}
		System.out.println(personalartGruppeCombobox.getItemCount());
		for (Object object : personalartGruppeCombobox.getItems()) {
			Comboitem comboitem = (Comboitem) object;
			if (currentZu_ps.getVorlage_ps().equals(comboitem.getValue())) {
				personalartGruppeCombobox.setSelectedItem(comboitem);
			}
		}
       }

So I am setting the right selectedItem in the first combobox and then I am loading the data for the second Combobox (It is only loaded if selectedItem of the first combobox is != null).
But unfortunately I am getting 0 for getItemCount() at that point, so the for loop ends immediately. I checked it in the debugger and I am getting a result from the database. Also if I look into the combobox after the execution of this method, the comboitems are there.

Now the part that really puzzles me: If I click on the Listitem again, without doing anything else inbetween it works fine. I get the result from the database, the itemcount is > 0 and the selectedItem is set.

So is there anything about the databinding that I can't access the items before the execution of the onClick method is finished?
If there is a better approach to fill those selected Items I would also be glad to use that instead.

I really need help with this. Thank you!

delete flag offensive retag edit

7 Replies

Sort by » oldest newest

answered 2010-04-14 06:04:19 +0800

cr4k gravatar image cr4k
12

Thankyou klotzw!

link publish delete flag offensive edit

answered 2010-03-04 01:04:21 +0800

jimmyshiau gravatar image jimmyshiau
4921 5
http://www.zkoss.org/ ZK Team

updated 2010-03-04 01:04:51 +0800

I write a sample
is it you need ?

<?init class="org.zkoss.zkplus.databind.AnnotateDataBinderInit"?>

<zk>
	<zscript><![CDATA[
	                  
		class Product{
			private String name;
			private List typeList;
			private int typeIndex = 0;
			
			public Product(String name, List typeList){
				this.name = name;
				this.typeList = typeList;
			}			
			public String getName(){
				return this.name;
			}
			public List getTypeList(){
				return this.typeList;
			}
			public int getTypeIndex(){
				return this.typeIndex;
			}
			public void setTypeIndex(int typeIndex){
				this.typeIndex = typeIndex;
			}
		}
		
		class Type{
			private String name;
			private List colorList;
			private int colorIndex = 0;
			
			public Type(String name, List colorList){
				this.name = name;
				this.colorList = colorList;
			}			
			public String getName(){
				return this.name;
			}
			public List getColorList(){
				return this.colorList;
			}
			public int getColorIndex(){
				return this.colorIndex;
			}
			public void setColorIndex(int colorIndex){
				this.colorIndex = colorIndex;
			}
		}
		
		public List createColor(String c1, String c2){
			List color = new ArrayList();
			color.add(c1);
			color.add(c2);
			return color;
		}
		
		List carType = new ArrayList();		
		carType.add(new Type("Mini car", createColor("red", "blue")));		
		carType.add(new Type("Sports car", createColor("green", "yellow")));		
		Product car = new Product("Car", carType);	
		
		
		List aircraftType = new ArrayList();
		aircraftType.add(new Type("Jet aircraft", createColor("white", "Light Blue")));		
		aircraftType.add(new Type("Helicopters", createColor("black", "gray")));		
		Product aircraft = new Product("Aircraft", aircraftType);
		
		List products = new ArrayList();
		products.add(car);
		products.add(aircraft);		
		
		
		Product listSelected = (Product)products.get(0);
		Type comboSelected = (Type)listSelected.getTypeList().get(0);
		String colorSelected = (String)comboSelected.getColorList().get(0);
		
	]]></zscript>
	


	<listbox id="lb" model="@{products}" selectedItem="@{listSelected}" width="200px">
		<listitem self="@{each='product'}">
			<listcell label="@{product.name}"/>
		</listitem>
	</listbox>
	<combobox id="cb1" model="@{listSelected.typeList}" selectedItem="@{comboSelected}">
		<comboitem self="@{each='type'}" label="@{type.name}"/>		
	</combobox>
	<combobox id="cb2" model="@{comboSelected.colorList}" selectedItem="@{colorSelected}">
		<comboitem self="@{each='color'}" label="@{color}"/>	
	</combobox>



	<zscript><![CDATA[
		lb.addEventListener("onSelect", new EventListener() {					
			public void onEvent(Event event) throws Exception {
				comboSelected = (Type)listSelected.typeList.get(listSelected.typeIndex);
			}
		});
		
		cb1.addEventListener("onInitRender", new EventListener() {			
			public void onEvent(Event event) throws Exception {
				cb2.setModel(new BindingListModelList(comboSelected.colorList,true));
				colorSelected = (String)comboSelected.colorList.get(comboSelected.colorIndex);
			}
		});
		
		cb1.addEventListener("onSelect", new EventListener() {			
			public void onEvent(Event event) throws Exception {
				colorSelected = (String)comboSelected.colorList.get(comboSelected.colorIndex);
				listSelected.typeIndex = cb1.selectedIndex;
			}
		});
		
		cb2.addEventListener("onSelect", new EventListener() {			
			public void onEvent(Event event) throws Exception {
				comboSelected.colorIndex = cb2.selectedIndex;
			}
		});

	]]></zscript>
</zk>

link publish delete flag offensive edit

answered 2010-03-03 03:26:52 +0800

TOtte gravatar image TOtte
93 2

Thank you a lot for your answer William. Calling onInitRender after the databinding also works for me. This is really helpfull because I just ran into the problem again and didn't want to use my other workaround.
But it still seems like something that shouldn't happen. This time I had the problem with only one combobox, so actually a very simple example:

	public List<Kostenstelle> getPid1List() {
		//Das momentane Objekt wird übergeben, damit es nicht selbst mit zurückgegeben wird
		if (getKostenstelleObjekt() != null) {
			List<Kostenstelle> list = getKostenstelleService().getPid1List(getKostenstelleObjekt());
			System.out.println(list.size());
			return list;
		}
		else
			return null;
	}


                binder.loadcomponent(pid1Combobox);
		if(kostenstelle.getPid1Parent() != null) {
			System.out.print("combobox size: ");
			System.out.print(pid1Combobox.getItemCount());
			for(Object object : pid1Combobox.getItems()) {
				Comboitem item = (Comboitem) object;
				if (kostenstelle.getPid1Parent().equals(item.getValue())) {
					pid1Combobox.setSelectedItem(item);
				}
			}
		}

The first method returns the expected size, lets say 10. But in the second code snipped (the databinding is usually done earlier, but for test cases i loaded the component again at that point) I will get 0 as Itemcount.
Now with Williams solution i also get 10 in the second snipped, but this seems like a bug to me.
Any suggestions from the ZK guys to why this happens or if it is a bug?

Thank you

link publish delete flag offensive edit

answered 2010-02-27 09:58:23 +0800

klotzw gravatar image klotzw
33

Hi TOtte,

In my application I had problems with using comboboxes when the data behind the combobox changed or was added after the initial creation of the combobox.

The application has two comboboxes one for called VehicleMakeComboBox the other VehicleModelComboBox.
When the user selects a vehicle make I query the database for associated models and update the VehicleModelComboBox. My problem was after the data was updated in the VehicleModelCombox I could GetItemsCount() on that box would return 0 and I could not set the initial selected item so I would have a default.

I solved this by calling onInitRender of the VehicleModelComboBox after I loaded the data into it.
VehicleModelComboBox.onInitRender(new Event("onInitialize", VehicleModelComboBox));

This was the only way I could find the reliably get the combobox to work when having to change the data model associated the combobox after creation was complete.

William

link publish delete flag offensive edit

answered 2010-02-26 06:48:25 +0800

TOtte gravatar image TOtte
93 2

Got it sovled now by creating a new comboitem for the second combobox and setting the value and label, then appending it to the combobox.
This works, but i am still curious why my other approach worked from the second click on while the first produced problems.

link publish delete flag offensive edit

answered 2010-02-26 02:09:05 +0800

TOtte gravatar image TOtte
93 2

Hi thank you for your reply as1225.
Dependend on the selected Item in the first combobox a data base query is executed to fill the second combobox. So the selectedIndex of combobox one is nt equal to the selectedIndex of combobox2.
onCreate happens before I know which item the user selected, so I can't use that.
I tried to call a method from the onChange event where I did the same as I did in the onClick method postet above. Unfortunately this didn't help either, it seems that the databinding filling the comboobx is not triggering onChange.

But the databinding of combobox2 is called when I use my onClick method, so that is not the issue. Its just that the items don't seem to be available before the onClick method ends and I have no clue why.
So the part that bothers me:

From the onClick method

		for (Object object : personalartBereichCombobox.getItems()) {
			Comboitem comboitem = (Comboitem) object;
			if (currentZu_ps.getVorlage_ps().getBereich().equals(comboitem.getValue())) {
				personalartBereichCombobox.setSelectedItem(comboitem);
				System.out.println(personalartBereichCombobox.getSelectedItem().getValue());
				binder.loadComponent(personalartGruppeCombobox);
				System.out.println(personalartGruppeCombobox.getItemCount());
			}
		}

Method to fill the second combobox

	public List<Vorlage_ps> getAllePersonalartGruppen() {
		if(personalartBereichCombobox.getSelectedItem() != null)
			return getVorlage_psService().getAlleVorlage_psGruppenByBereichOrganisation((String) personalartBereichCombobox.getSelectedItem().getValue(), organisation);
		else
			return null;
	}

So what happens when I click on the Listitem is:
1. The selected Item of the first combobox gets set and the System.out return the right value for it.
2. The database query is executed and returns a list with valid results, it does not return an empty list
3. The System.out returns 0 as ItemCount for the second combobox

In step 3 the itemcount should be above 0 and if I click on the Listitem again it will be above 0, but not the first time.
If I click on some other Listitem with my second click it also works.
So it is just the very first selection that produces this problem.

link publish delete flag offensive edit

answered 2010-02-25 20:02:22 +0800

jimmyshiau gravatar image jimmyshiau
4921 5
http://www.zkoss.org/ ZK Team

Hi, TOtte
You can try this to set select item

<combobox onCreate="self.selectedIndex= 0;" onChange="cb2.selectedIndex = self.selectedIndex;">
	<comboitem label="Simple and Rich" />
	<comboitem label="Cool!" />
	<comboitem label="Thumbs Up!" />
</combobox>
<combobox  id="cb2" onCreate="self.selectedIndex= 0">
	<comboitem label="Simple and Rich" />
	<comboitem label="Cool!" />
	<comboitem label="Thumbs Up!" />
</combobox>

link publish delete flag offensive edit
Your reply
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

RSS

Stats

Asked: 2010-02-25 08:12:59 +0800

Seen: 772 times

Last updated: Apr 14 '10

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