0

Executions.createComponents and databinding

asked 2010-04-14 06:42:17 +0800

dickdastardly gravatar image dickdastardly
168 1 5

If you use

Executions.createComponents("subPage.zul", parentComponent, null)
to add the subPage.zul into your parent component
within a composer...

How do you get the input fields that are mapped to a data model with@{} inside the subPAge.zul to be bound to the backing data beans?

what am i missing ?

DD

delete flag offensive retag edit

10 Replies

Sort by ยป oldest newest

answered 2010-04-14 08:07:55 +0800

dickdastardly gravatar image dickdastardly
168 1 5

cant anyone help me with this?

I am getting all "Desperate Dan"!

:-(

link publish delete flag offensive edit

answered 2010-04-14 10:20:13 +0800

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

Do you have an AnnotateDataBinderInit in subPage.zul?

link publish delete flag offensive edit

answered 2010-04-14 10:59:52 +0800

dickdastardly gravatar image dickdastardly
168 1 5

Cary

Thanks for looking at this

no, if you look at my other post entitled "dynamic Tabbox"

you'll see the composer and zul

Why do i need an AnnotateDataBinderInit in the Executions.createComponents("subPage.zul", parentComponent, null)?

doesnt the one in the parent page look after all the data models?

I am thinking of giving up the quest for dynamic tabboxes!

They look too hard and i still cannot work out ho wto set the index of the backing ListArray with the tabindex! :-(

Is it becuase I havent studied zk enough?

Or cant it be done?

whats odd is the exception i am getting! Or more i dont understand the exception i am getting

Cannot find associated CollectionItem=<Comboitem z_h4_15>, binding=[binder:org.zkoss.zkplus.databind.AnnotateDataBinder@1189cbb, comp:<Comboitem z_h4_15>, attr:label, expr:childLanguage.description, load-when:null, save-when:null, load-after:null, save-after:null, load:true, save:false, converter:null], collectionComp=<Comboitem @z_h4_t3_0>

this from one of the many drop downs on the included page within one of the tabs.

All i want to do is

1). Create a new Tab panel with an associated tab in a tabbox each time the user clickson the "Add child" button
2). For the new tab to be bound to a backing arraylist of children instances with the correct arraylist index set matching the tabindex.
3). for zk databinding to work so that i can collect the childs details enterd by the user.

doesnt seem a complicated task !

have i missed a smalltalk or something that explains all this?

I've spent the last week googling and reading up on zk


Cheers

DD

link publish delete flag offensive edit

answered 2010-04-14 13:22:42 +0800

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

updated 2010-04-14 13:23:21 +0800

Sorry, I'm at a client site and haven't the time to lookup the other thread.

Are the children UI components that you're referring to in 3) above created programmatically or via Executions.createComponents("subPage.zul", parentComponent, null)? If the former, you'll have to bind them to bean yourself. If the latter, you'll need an AnnotateDataBinderInit in the subPage.zul or create and bind the beans yourself. "doesnt the one in the parent page look after all the data models?" How could it? The child page containing the UI components did not exist when it was created so it could not do the automatic binding for you.

link publish delete flag offensive edit

answered 2010-04-14 13:54:38 +0800

dickdastardly gravatar image dickdastardly
168 1 5

Thanks for bothering

my composer is

package com.pre.school.zk.composer;

import java.util.List;

import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Components;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zk.ui.event.ForwardEvent;
import org.zkoss.zk.ui.util.GenericForwardComposer;
import org.zkoss.zkplus.databind.AnnotateDataBinder;
import org.zkoss.zul.Button;
import org.zkoss.zul.Datebox;
import org.zkoss.zul.Tab;
import org.zkoss.zul.Tabbox;
import org.zkoss.zul.Tabpanel;
import org.zkoss.zul.Tabpanels;
import org.zkoss.zul.Tabs;
import org.zkoss.zul.Textbox;
import org.zkoss.zul.impl.InputElement;

public class ValidationComposer extends GenericForwardComposer {

	private static final long serialVersionUID = -1870580858482873118L;

	private AnnotateDataBinder binder;
	private Component childComponent;
	public boolean allFieldsValid = true;
	private Button nextButton;
	private Tabbox childrenTabbox;

	@Override
	public void doAfterCompose(Component comp) throws Exception {
		super.doAfterCompose(comp);
		addChildrenTab();
		addChildrenTab();

	}

	public void onCreate$win(ForwardEvent event) {
		binder = (AnnotateDataBinder) event.getTarget().getAttributeOrFellow("binder", true);
		nextButton.setDisabled(true);

	}

	@SuppressWarnings("unchecked")
	public void onOK$win(ForwardEvent event) {
		List childComponents;

		childComponents = event.getTarget().getChildren();

		childComponent = (Component) childComponents.get(0);

		if (getChildren(childComponent)) {
			nextButton.setDisabled(false);
		} else {
			nextButton.setDisabled(true);
		}

		binder.saveAll();
		addChildrenTab();

	}

	private void addChildrenTab() {
		Tabpanel tabpanel = new Tabpanel();
		Executions.createComponents("childTAB.zul", tabpanel, null);
		Tab tab = new Tab("Another Child");
		
		if (childrenTabbox.getTabs() == null){
			childrenTabbox.appendChild(new Tabs());			
			childrenTabbox.appendChild(new Tabpanels());			
		}
			
		childrenTabbox.getTabs().appendChild(tab);
		childrenTabbox.getTabpanels().appendChild(tabpanel);

	}

	@SuppressWarnings("unchecked")
	private boolean getChildren(Component theseChildren) {

		List<Component> componentList;

		if (theseChildren == null) {
			return false;
		}

		componentList = (List<Component>) theseChildren.getChildren();

		if ((componentList == null) || (componentList.size() == 0)) {
			return allFieldsValid;
		}

		for (Component myComponent : componentList) {

			if (myComponent instanceof Textbox) {
				((Textbox) myComponent).getValue();
			} else if (myComponent instanceof Datebox) {
				((Datebox) myComponent).getValue();
			}

			if (myComponent instanceof InputElement) {
				if (allFieldsValid) {
					allFieldsValid = ((InputElement) myComponent).isValid();
				}
			}

			getChildren(myComponent);

		}

		return allFieldsValid;

	}

}

my childTAB.zul

<grid fixedLayout="false">
	<columns>
		<column label="" width="15%" />
		<column label="" width="30%" />
	</columns>
	<rows>
		<row>
			<label value="Gender" />
			<combobox model="@{preSchoolReferenceData.genders}"
				selectedItem="@{family.child.gender}" readonly="true"
				mold="rounded">
				<comboitem self="@{each='childGender'}"
					label="@{childGender.description}">
				</comboitem>
			</combobox>
		</row>
		<row>
			<label value="First Name" width="100px" />
			<textbox constraint="no empty"
				value="@{family.child.firstName, save-when='self.onBlur'}"
				width="190px" />
		</row>
		<row>
			<label value="Middle Name" width="100px" />
			<textbox
				value="@{family.child.middleName, save-when='self.onBlur'}"
				width="190px" />
		</row>
		<row>
			<label value="Surname" width="100px" />
			<textbox constraint="no empty"
				value="@{family.child.surname, save-when='self.onBlur'}"
				width="190px" />
		</row>
		<row>
			Date Of Birth:
			<hbox>
				<datebox onSelection="self.close()"
					readonly="false" mold="rounded"
					constraint="no empty, no future: Please enter a valid Date Of Birth"
					format="dd/MM/yyyy"
					value="@{family.child.dateOfBirth, save-when='self.onChange'}" />
			</hbox>
		</row>
		<row>
			<label value="Language" />
			<combobox model="@{preSchoolReferenceData.languages}"
				selectedItem="@{family.child.language}" readonly="true"
				mold="rounded">
				<comboitem self="@{each='childLanguage'}"
					label="@{childLanguage.description}">
				</comboitem>
			</combobox>
		</row>
		<row>
			<label value="Ethnic Group" />
			<combobox model="@{preSchoolReferenceData.ethnicGroups}"
				selectedItem="@{family.child.ethnicGroup}" readonly="true"
				mold="rounded">
				<comboitem self="@{each='childEthnicGroup'}"
					label="@{childEthnicGroup.description}">
				</comboitem>
			</combobox>
		</row>
		<row>
			<label value="Religion" />
			<combobox model="@{preSchoolReferenceData.religions}"
				selectedItem="@{family.child.religion}" readonly="true"
				mold="rounded">
				<comboitem self="@{each='childReligion'}"
					label="@{childReligion.description}">
				</comboitem>
			</combobox>
		</row>
	</rows>
</grid>


My first test was successful and added my initial single tab to the tabbox and all data binding works fine
the only thing i dont have working at this single tab stage is the selectedindex from the Tab driving the arraylist of children.

My second test failed. What i tried was to call

addChildrenTab();

in

public void onOK$win(ForwardEvent event) {}


the second tab was displayed however none of the databinding had happend so my drop downs didnt have any data in them and any text
i entered in the input fields was ignored. I think this is i have added a new tab and not run "doaftercompose()" although i am not sure i am allowed to do that!

My third test...

just as a quick and dirty test I added two childrens tabs in doaftercompose method

The good news is the comboboxes have been bound to the backing data sources and have drop down content
the bad news is i get this exception

Cannot find associated CollectionItem=<Comboitem z_h4_15>, binding=[binder:org.zkoss.zkplus.databind.AnnotateDataBinder@1189cbb, comp:<Comboitem z_h4_15>, attr:label, expr:childLanguage.description, load-when:null, save-when:null, load-after:null, save-after:null, load:true, save:false, converter:null], collectionComp=<Comboitem @z_h4_t3_0>

any ideas how i get passed this?

is what i am trying an acceptable approach?

I just tried an annotated databinder init in the childTAB.zul page and the whole page doesnt display, all i get is an exception saying i already have a databinder covering the page

14-Apr-2010 19:52:30 org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet zkpreschool threw exception
org.zkoss.zk.ui.UiException: Page is already covered by another Data Binder. Cannot be covered by this Data Binder again. Page:z_t4_0
	at org.zkoss.zkplus.databind.AnnotateDataBinderInit.doAfterCompose(AnnotateDataBinderInit.java:146)
	at org.zkoss.zk.ui.impl.RealInits.doAfterCompose(Initiators.java:82)
	at org.zkoss.zk.ui.impl.UiEngineImpl.createComponents(UiEngineImpl.java:844)
	at org.zkoss.zk.ui.impl.AbstractExecution.createComponents(AbstractExecution.java:236)
	at org.zkoss.zk.ui.Executions.createComponents(Executions.java:176)
	at com.pre.school.zk.composer.ValidationComposer.addChildrenTab(ValidationComposer.java:82)
	at com.pre.school.zk.composer.ValidationComposer.doAfterCompose(ValidationComposer.java:37)
	at org.zkoss.zk.ui.impl.UiEngineImpl.execCreateChild0(UiEngineImpl.java:663)
	at org.zkoss.zk.ui.impl.UiEngineImpl.execCreateChild(UiEngineImpl.java:610)
	at org.zkoss.zk.ui.impl.UiEngineImpl.execCreate0(UiEngineImpl.java:554)
	at org.zkoss.zk.ui.impl.UiEngineImpl.execCreateChild(UiEngineImpl.java:586)
	at org.zkoss.zk.ui.impl.UiEngineImpl.execCreate0(UiEngineImpl.java:554)
	at org.zkoss.zk.ui.impl.UiEngineImpl.execCreate(UiEngineImpl.java:521)
	at org.zkoss.zk.ui.impl.UiEngineImpl.execNewPage0(UiEngineImpl.java:365)
	at o

having change childTAB.zul

<?init class="org.zkoss.zkplus.databind.AnnotateDataBinderInit" ?>
<zk>
	<grid fixedLayout="false">
		<columns>
			<column label="" width="15%" />
			<column label="" width="30%" />
		</columns>
		<rows>
			<row>
				<label value="Gender" />
				<combobox model="@{preSchoolReferenceData.genders}"
					selectedItem="@{family.child.gender}" readonly="true"
					mold="rounded">
					<comboitem self="@{each='childGender'}"
						label="@{childGender.description}">
					</comboitem>
				</combobox>
			</row>
			<row>
				<label value="First Name ${arg.tabularIndex}"
					width="100px" />
				<textbox constraint="no empty"
					value="@{family.child.firstName, save-when='self.onBlur'}"
					width="190px" />
			</row>
			<row>
				<label value="Middle Name" width="100px" />
				<textbox
					value="@{family.child.middleName, save-when='self.onBlur'}"
					width="190px" />
			</row>
			<row>
				<label value="Surname" width="100px" />
				<textbox constraint="no empty"
					value="@{family.child.surname, save-when='self.onBlur'}"
					width="190px" />
			</row>
			<row>
				Date Of Birth:
				<hbox>
					<datebox onSelection="self.close()" readonly="false"
						mold="rounded"
						constraint="no empty, no future: Please enter a valid Date Of Birth"
						format="dd/MM/yyyy"
						value="@{family.child.dateOfBirth, save-when='self.onChange'}" />
				</hbox>
			</row>
			<row>
				<label value="Language" />
				<combobox model="@{preSchoolReferenceData.languages}"
					selectedItem="@{family.child.language}" readonly="true"
					mold="rounded">
					<comboitem self="@{each='childLanguage'}"
						label="@{childLanguage.description}">
					</comboitem>
				</combobox>
			</row>
			<row>
				<label value="Ethnic Group" />
				<combobox model="@{preSchoolReferenceData.ethnicGroups}"
					selectedItem="@{family.child.ethnicGroup}" readonly="true"
					mold="rounded">
					<comboitem self="@{each='childEthnicGroup'}"
						label="@{childEthnicGroup.description}">
					</comboitem>
				</combobox>
			</row>
			<row>
				<label value="Religion" />
				<combobox model="@{preSchoolReferenceData.religions}"
					selectedItem="@{family.child.religion}" readonly="true"
					mold="rounded">
					<comboitem self="@{each='childReligion'}"
						label="@{childReligion.description}">
					</comboitem>
				</combobox>
			</row>
		</rows>
	</grid>
</zk>

Cary thanks again for taking th etime, especially if you ar eon site!

Cheers

DD

link publish delete flag offensive edit

answered 2010-04-15 05:55:23 +0800

dickdastardly gravatar image dickdastardly
168 1 5

i've managed to get my included sub page to display with its own databinder

as shown below

however the backing beans are still not binding!

what else do i have to do?

What am i missing?

Someone please help!

Potix Jimmy ... Where are you?

I just want to "drive it like i stole it" !!!

<?init class="org.zkoss.zkplus.databind.AnnotateDataBinderInit" arg0="./children${arg.tabularIndex}"?>
<window id="children${arg.tabularIndex}">
	<grid fixedLayout="false">
		<columns>
			<column label="" width="15%" />
			<column label="" width="30%" />
		</columns>
		<rows>
			<row>
				<label value="Gender" />
				<combobox model="@{preSchoolReferenceData.genders}"
					selectedItem="@{family.child.gender}" readonly="true"
					mold="rounded">
					<comboitem self="@{each='childGender'}"
						label="@{childGender.description}">
					</comboitem>
				</combobox>
			</row>
			<row>
				<label value="First Name ${arg.tabularIndex}"
					width="100px" />
				<textbox constraint="no empty"
					value="@{family.child.firstName, save-when='self.onBlur'}"
					width="190px" />
			</row>
			<row>
				<label value="Middle Name" width="100px" />
				<textbox
					value="@{family.child.middleName, save-when='self.onBlur'}"
					width="190px" />
			</row>
			<row>
				<label value="Surname" width="100px" />
				<textbox constraint="no empty"
					value="@{family.child.surname, save-when='self.onBlur'}"
					width="190px" />
			</row>
			<row>
				Date Of Birth:
				<hbox>
					<datebox onSelection="self.close()" readonly="false"
						mold="rounded"
						constraint="no empty, no future: Please enter a valid Date Of Birth"
						format="dd/MM/yyyy"
						value="@{family.child.dateOfBirth, save-when='self.onChange'}" />
				</hbox>
			</row>
			<row>
				<label value="Language" />
				<combobox model="@{preSchoolReferenceData.languages}"
					selectedItem="@{family.child.language}" readonly="true"
					mold="rounded">
					<comboitem self="@{each='childLanguage'}"
						label="@{childLanguage.description}">
					</comboitem>
				</combobox>
			</row>
			<row>
				<label value="Ethnic Group" />
				<combobox model="@{preSchoolReferenceData.ethnicGroups}"
					selectedItem="@{family.child.ethnicGroup}" readonly="true"
					mold="rounded">
					<comboitem self="@{each='childEthnicGroup'}"
						label="@{childEthnicGroup.description}">
					</comboitem>
				</combobox>
			</row>
			<row>
				<label value="Religion" />
				<combobox model="@{preSchoolReferenceData.religions}"
					selectedItem="@{family.child.religion}" readonly="true"
					mold="rounded">
					<comboitem self="@{each='childReligion'}"
						label="@{childReligion.description}">
					</comboitem>
				</combobox>
			</row>
		</rows>
	</grid>
</window>

link publish delete flag offensive edit

answered 2010-04-17 11:57:30 +0800

dickdastardly gravatar image dickdastardly
168 1 5

I am feeling unloved and ignored by the zk forum!

is there no one that can put me out of my misery?

Muttley, Do Something!!!!!!!!!!!!! :-)

link publish delete flag offensive edit

answered 2010-04-18 02:03:44 +0800

henrichen gravatar image henrichen
3869 2
ZK Team

@dickdastardly,

Theoretically, what you done is correct. However, can you provide a simpler and complete test case? It will ease the effort for the community to help you.

link publish delete flag offensive edit

answered 2010-04-18 07:59:29 +0800

dickdastardly gravatar image dickdastardly
168 1 5

henrichen

thanks for responding ...

However i've given up!

I may give up on zk (which is very disappointing) as i really like the ease of use and look and feel of it.

I just cannot afford to spend so much time getting round the points where zk falls short

such as tabbox not supporting a data model

the only outstanding problem i am left with is setting the arraylist index from the tabindex value...

I just cannot see a "clean" way of doing this

Thanks again

DD

link publish delete flag offensive edit

answered 2010-04-18 17:56:50 +0800

robertpic71 gravatar image robertpic71
1275 1

Hi,

About your orgin problem: create omponents and databinder

Databinding does not support dynamic (new components after the init) binding, however it's no problem to use more than one binder-instance.

1. With <?init...
Make sure, that you use different store positions for databinder. Check this Api for the correct parameters. However, if you use always use the default (page), you will get an error.#

2. Without <?init Databinder - create your instance inside the composer
I prefer to create my own DataBinder-instance inside the composer.

Create just like this:

public class Main extends GenericForwardComposer {

	private AnnotateDataBinder binder;
	...
	/*
	 * Model und Servicedata
	 */
	
	MainModel model;
	
	@Override
	public void doAfterCompose(Component _win) throws Exception {
		super.doAfterCompose(_win);
		win.setVariable("model", model, false);  // make models visible for the databinder [1]
		binder = new AnnotateDataBinder(_win);
		...
	}


And: Register your model/data to the databinder (not only the composer or UI-Component)
In this case: register the modelclass MainModel as resourcename model (@{model.bean.value}).

In your case: If you want to use different tabs(?) with the same model, create different composers and databinders, but register the same model.
You can store paramters i.e. inside the (user) attributes form the new tab and retrieve them inside the composer to get the correct array. (i hope i unsertand your request - my time is limited)

[1] Use win.setAttribute for ZK > 5.0

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-04-14 06:42:17 +0800

Seen: 2,059 times

Last updated: Apr 18 '10

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