0

Putting a button per row in a grid with model and data binding

asked 2010-04-30 04:08:10 +0800

mirjalali gravatar image mirjalali
27 1

Hi all,
I am creating a grid given a list as its model.
I want to put a button in each row of the grid while using data-binding and save-when, ... features.
The important thing is that the actions of the button should affect only the components on its own row, not the other rows.
For example, consider the following zul file:

<?init class="org.zkoss.zkplus.databind.AnnotateDataBinderInit" ?>
<?page title="Books"?>
<zk xmlns="http://www.zkoss.org/2005/zul" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.zkoss.org/2005/zul http://www.zkoss.org/2005/zul/zul.xsd " >
	<include src="/commons/header.zul"/>
		<zscript><![CDATA[
		    class Book {
		    	private int id;
		    	private String title;
		    	public int getId() {
		    		return id;
		    	}
		    	public void setId(int i) {
		    		id = i;
		    	}
		    	public String getTitle() {
		    		return title;
		    	}
		    	public void setTitle(String t) {
		    		title = t;
		    	}
		    }

		    Book b1 = new Book();
		    b1.setId(1);
		    b1.setTitle("b1");
		    
		    Book b2 = new Book();
		    b2.setId(2);
		    b2.setTitle("b2");
		    
		    List bookList = new ArrayList();
		    bookList.add(b1);
		    bookList.add(b2);
		    
		]]></zscript>
<window  width="100%" height="100%" >
	<grid model="@{bookList}"  >
		<columns>
			<column label="id" />
			<column label="TitleEdit" />
			<column label="Titleview" />
			<column  />
		</columns>
		<rows >
			<row self="@{each=book}" >
				<label value="@{book.id}" />
				<textbox value="@{book.title, save-when='btnSave.onClick', load-after='btnSave.onClick' }" />
				<label value="@{book.title, load-after='btnSave.onClick'}"/>
				<button id="btnSave" label="Save changes" />
			</row>
		</rows>
	</grid>
</window>
</zk>

Consider the following scenario:
1- Edit the textbox in the first row.
2- Edit the textbox in the second row.
3- Click the button in the second row.

What I want is that the new value of ONLY the "textbox" in row#2, be saved in "b2.title" and be loaded to the "label" in row#2.
But, by following the above scenario, you will see that the value of the textbox in row#1 is also saved in the "b1.title", and is seen in the label in row#1.
It seams that the buttons created in the 4th column are not distinct buttons, and they are considered as a single button.
I think the problem is that the "id" of the buttons is the same in multiple rows and we cannot define different values for the "save-when" attributes of the textboxes.
Is there a simple way to solve this problem without doing a big surgery to the code?

delete flag offensive retag edit

9 Replies

Sort by » oldest newest

answered 2010-05-02 20:04:34 +0800

samchuang gravatar image samchuang
4084 4

Hi

you mean you don't want to write java code, need a simple way to achieve it, right, I have to think how

link publish delete flag offensive edit

answered 2010-05-03 14:28:08 +0800

mirjalali gravatar image mirjalali
27 1

Well, I have no idea how data-binding can be done through java codes.
Could you please provide an equivalent java code which works correctly?
Though, naturally, I would be much more happy if no java code was needed for that.

Thanks a lot.

link publish delete flag offensive edit

answered 2010-05-03 20:23:35 +0800

samchuang gravatar image samchuang
4084 4

Hi

<?init class="org.zkoss.zkplus.databind.AnnotateDataBinderInit" ?>
<?page title="Books"?>
<zk xmlns="http://www.zkoss.org/2005/zul" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.zkoss.org/2005/zul http://www.zkoss.org/2005/zul/zul.xsd " >
<window  width="100%" height="100%" >
	<grid id="grid"  >
		<columns>
			<column label="id" />
			<column label="TitleEdit" />
			<column label="Titleview" />
			<column  />
		</columns>
	</grid>
	<zscript><![CDATA[
		    class Book {
		    	private int id;
		    	private String title;
		    	public int getId() {
		    		return id;
		    	}
		    	public void setId(int i) {
		    		id = i;
		    	}
		    	public String getTitle() {
		    		return title;
		    	}
		    	public void setTitle(String t) {
		    		title = t;
		    	}
		    }

		    class MyRowRenderer implements RowRenderer {
		    	
		    	public void render(Row row, Object data)  {
		    		Book b = (Book)data;
		    		row.appendChild(new Label("" + b.getId()));
		    		final Textbox tb = new Textbox(b.getTitle());
		    		row.appendChild(tb);
		    		final Label title = new Label(b.getTitle());
		    		row.appendChild(title);
		    		
		    		Button btn = new Button("Save changes");
		    		btn.addEventListener(Events.ON_CLICK, new org.zkoss.zk.ui.event.EventListener(){
		    			public void onEvent(Event event) {
		    				String str_Title = tb.getText();
		    				title.setValue(str_Title);
		    			}
		    		});
		    		
		    		row.appendChild(btn);
		    	}
		    }
		    
		    Book b1 = new Book();
		    b1.setId(1);
		    b1.setTitle("b1");
		    
		    Book b2 = new Book();
		    b2.setId(2);
		    b2.setTitle("b2");
		    
		    List bookList = new ArrayList();
		    bookList.add(b1);
		    bookList.add(b2);
		    
		    SimpleListModel model = new SimpleListModel(bookList);
		    grid.setModel(model);
		    MyRowRenderer renderer = new MyRowRenderer();
		    grid.setRowRenderer(renderer);
		    
		]]></zscript>
</window>
</zk>

link publish delete flag offensive edit

answered 2010-05-04 10:39:47 +0800

mirjalali gravatar image mirjalali
27 1

Thanks a lot for your code.
But, there is no data-binding here anymore.
For example, the value of the Label is updated automatically in data-binding, but here, you have to take care of everything.
I was wondering if there exists an equivalent java code for "data-binding".

Thanks again.

link publish delete flag offensive edit

answered 2010-05-04 14:57:22 +0800

terrytornado gravatar image terrytornado flag of Germany
9393 3 7 16
http://www.oxitec.de/

updated 2010-05-04 15:00:16 +0800

Hi @mirjalali


below are the partial (but running) codes from a LoC (Line of Codes) demonstration that should show zul vs. java.
These are the codes for a Richlet and shows the integration of the automatically DataBinder in java
as aquivalent to the same in zul:

I hope i don't forget a class.

best
Stephan


myPersonRichlet.java

import org.zkoss.zk.ui.GenericRichlet;
import org.zkoss.zk.ui.Page;

/**
 * Richlet sample that shows the automatically Databinder working in java code
 * with the org.zkoss.zkplus.databind.DataBinder class.<br>
 * <br>
 * needed classes:<br>
 * Person.java<br>
 * PersonDAO.java<br>
 * PersonDAOImpl.java<br>
 * PersonList.java<br>
 * PersonListItemRenderer.java<br>
 * PersonSearchDialog.java <br>
 * <br>
 * From the zl 3.6.3 documentation; page: 234 .<br>
 * One Richlet per URL Like servlets, a richlet is created and shared for the
 * same URL. In other words, the richlet (at least the service method) must be
 * thread-safe. On the other hands, components are not shareable. Each desktop
 * has an independent set of components. Therefore, it is generally not a good
 * idea to store components as a data member of a richlet. <br>
 * <hr>
 * 
 * 
 * @author sgerth sge(at)forsthaus(dot)de
 */
public class MyPersonRichlet extends GenericRichlet {

	@Override
	public void service(Page page) {
		new MyPersonRichletImpl(page); // create and forget
	}

}

.
myPersonRichletImpl.java

import org.zkoss.util.resource.Labels;
import org.zkoss.zk.ui.Page;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zkex.zul.Columnchildren;
import org.zkoss.zkex.zul.Columnlayout;
import org.zkoss.zkplus.databind.BindingListModelList;
import org.zkoss.zkplus.databind.DataBinder;
import org.zkoss.zul.Button;
import org.zkoss.zul.Caption;
import org.zkoss.zul.Column;
import org.zkoss.zul.Columns;
import org.zkoss.zul.Div;
import org.zkoss.zul.Grid;
import org.zkoss.zul.Groupbox;
import org.zkoss.zul.Label;
import org.zkoss.zul.Listbox;
import org.zkoss.zul.Listitem;
import org.zkoss.zul.Panel;
import org.zkoss.zul.Panelchildren;
import org.zkoss.zul.Row;
import org.zkoss.zul.Rows;
import org.zkoss.zul.Separator;
import org.zkoss.zul.Textbox;
import org.zkoss.zul.Toolbar;
import org.zkoss.zul.Vbox;
import org.zkoss.zul.Window;

import com.zksample.backend.dao.impl.PersonDAOImpl;
import com.zksample.backend.model.Person;

/**
 * PersonRichlet implementation.
 * 
 * @author sgerth sge(at)forsthaus(dot)de
 * 
 */
public class MyPersonRichletImpl {

	private MyPersonRichletImpl myPersonRichletImpl;

	// Window as NameSpace
	private Window _main;
	// DataBinder
	private DataBinder binder;
	// Listbox that shows the Person Bean data
	private Listbox listBoxPerson;
	// Textbox for bean property: Person.lastName
	private Textbox txtb_LastName;
	// Textbox for bean property: Person.lastName
	private Textbox txtb_FirstName;
	// Textbox for bean property: Person.firstName
	private Textbox txtb_StreetName;
	// Textbox for bean property: Person.city
	private Textbox txtb_City;
	// Textbox for bean property: Person.phone
	private Textbox txtb_Phone;
	// Textbox for bean property: Person.fax
	private Textbox txtb_Fax;

	// Bean to bind
	private Person person;

	/**
	 * Constructor
	 * 
	 * @param page
	 */
	public MyPersonRichletImpl(Page page) {
		myPersonRichletImpl = this;

		_main = new Window();
		_main.setPage(page);
		set_main(_main);
		page.setTitle("myRichlet Page");

		binder = new DataBinder();
		page.setAttribute("binder", binder);

		Vbox vbox = new Vbox();
		vbox.setWidth("100%");
		vbox.setHeight("100%");
		_main.appendChild(vbox);

		vbox.appendChild(createPersonListbox());
		vbox.appendChild(createToolbarAndButtons());
		vbox.appendChild(createDetailFields());

		initDataBinding();

	}

	/**
	 * Creates the Listbox for the Person data.
	 * 
	 * @return Div with the person Listbox.
	 */
	private Div createPersonListbox() {

		Div div = new Div();

		Window win = new PersonList();
		win.setParent(div);

		listBoxPerson = (Listbox) win.getFellow("listBoxPerson");
		setListBoxPerson(listBoxPerson);

		if (listBoxPerson != null) {
			listBoxPerson.addEventListener("onSelect", new EventListener() {

				@Override
				public void onEvent(Event event) throws Exception {
					Listitem item = listBoxPerson.getSelectedItem();
					if (item != null) {
						// casting
						setPerson((Person) item.getAttribute("data"));
						System.out.println("onSelect(): " + (getPerson().getLastName()));
					}
				}
			});
		}

		return div;
	}

	/**
	 * Creates the Buttons.
	 * 
	 * @return Div with the Buttons
	 */
	private Div createToolbarAndButtons() {

		Div div = new Div();
		div.setWidth("100%");
		div.setSclass("z-toolbar");
		div.setStyle("padding:0");

		Separator sep;

		// +++++++++++++++++++++++++++++++++++++
		Toolbar tb = new Toolbar();
		tb.setWidth("100%");
		tb.setAlign("start");
		tb.setStyle("float:left");
		tb.setParent(div);

		Button btnHelp = new Button();
		btnHelp.setId("btnHelp");
		btnHelp.setLabel("Help");
		btnHelp.setTooltiptext(Labels.getLabel("btnHelp.label"));
		btnHelp.setImage("/images/icons/light_16x16.gif");
		btnHelp.addEventListener("onClick", new OnClickBtnHelpEventListener());
		btnHelp.setParent(tb);

		Button btnSearch = new Button();
		btnSearch.setId("btnSearch");
		btnSearch.setLabel("Search");
		btnSearch.setTooltiptext("I create a searchDialog Window with inside code.");
		btnSearch.setImage("/images/icons/btn_search2_16x16.gif");
		btnSearch.addEventListener("onClick", new OnClickBtnSearchEventListener());
		btnSearch.setParent(tb);

		sep = new Separator();
		sep.setOrient("vertical");
		sep.setSpacing("20");
		sep.setBar(true);
		sep.setParent(tb);

		// +++++++++++++++++++++++++++++++++++++
		Button btnNew = new Button();
		btnNew.setId("btnNew");
		btnNew.setLabel("Search 2");
		btnNew.setTooltiptext("I create a searchDialog Window from external code.");
		btnNew.setImage("/images/icons/btn_new2_16x16.gif");
		btnNew.addEventListener("onClick", new EventListener() {

			@Override
			public void onEvent(Event event) throws Exception {
				PersonSearchDialog psd = new PersonSearchDialog(myPersonRichletImpl);
			}
		});

		btnNew.setParent(tb);

		sep = new Separator();
		sep.setOrient("vertical");
		sep.setSpacing("20");
		sep.setBar(true);
		sep.setParent(tb);

		// ++++++++++++++++++++++++++++++++
		Button btnSave = new Button();
		btnSave.setId("btnSave");
		btnSave.setLabel("Save");
		btnSave.setTooltiptext("I'm the save button");
		btnSave.setImage("/images/icons/btn_save2_16x16.gif");
		btnSave.setParent(tb);

		Button btnEdit = new Button();
		btnEdit.setId("btnEdit");
		btnEdit.setLabel("Edit");
		btnEdit.setTooltiptext("I'm the edit button");
		btnEdit.setImage("/images/icons/btn_edit2_16x16.gif");
		btnEdit.setParent(tb);

		Button btnDelete = new Button();
		btnDelete.setId("btnDelete");
		btnDelete.setLabel("Delete");
		btnDelete.setTooltiptext("I'm the delete button");
		btnDelete.setImage("/images/icons/btn_delete2_16x16.gif");
		btnDelete.setParent(tb);

		Button btnCancel = new Button();
		btnCancel.setId("btnCancel");
		btnCancel.setLabel("Cancel");
		btnCancel.setTooltiptext("I'm the cancel button");
		btnCancel.setImage("/images/icons/btn_cancel2_16x16.gif");
		btnCancel.setParent(tb);

		return div;
	}

	/**
	 * Creates the detail fields for showing the person bean data.
	 * 
	 * @return Div with the detail fields.
	 */
	private Div createDetailFields() {

		Div div = new Div();
		div.setWidth("100%");
		div.setHeight("100%");

		Row row;
		Rows rows;
		Label label;
		Grid grid;
		Columns columns;
		Column column;

		// ++++++++++++ Containers ++++++++++++++++
		Columnlayout colLayout = new Columnlayout();
		colLayout.setParent(div);
		Columnchildren colChildren1 = new Columnchildren();
		colChildren1.setWidth("50%");
		colChildren1.setParent(colLayout);
		Columnchildren colChildren2 = new Columnchildren();
		colChildren2.setWidth("50%");
		colChildren2.setParent(colLayout);

		// +++++++++++++++ left GroupBox + Container
		Panel panelName = new Panel();
		panelName.setParent(colChildren1);
		Panelchildren panelchildrenName = new Panelchildren();
		panelchildrenName.setParent(panelName);

		Groupbox gbName = new Groupbox();
		gbName.setMold("3d");
		gbName.setParent(panelchildrenName);
		Caption captionGBName = new Caption();
		captionGBName.setLabel("Name and Address");
		captionGBName.setImage("/images/icons/view.gif");
		captionGBName.setParent(gbName);

		grid = new Grid();
		grid.setParent(gbName);

		columns = new Columns();
		columns.setParent(grid);

		column = new Column();
		column.setWidth("40%");
		column.setParent(columns);

		rows = new Rows();
		rows.setParent(grid);

		row = new Row();
		row.setParent(rows);
		label = new Label("Last Name");
		label.setId("lbl_LastName");
		label.setParent(row);
		txtb_LastName = new Textbox();
		txtb_LastName.setId("txtb_LastName");
		txtb_LastName.setWidth("98%");
		txtb_LastName.setParent(row);

		row = new Row();
		row.setParent(rows);
		label = new Label("First Name");
		label.setId("lbl_FirstName");
		label.setParent(row);
		txtb_FirstName = new Textbox();
		txtb_FirstName.setId("txtb_FirstName");
		txtb_FirstName.setWidth("98%");
		txtb_FirstName.setParent(row);

		row = new Row();
		row.setParent(rows);
		label = new Label("Street");
		label.setId("lbl_Street");
		label.setParent(row);
		txtb_StreetName = new Textbox();
		txtb_StreetName.setId("txtb_StreetName");
		txtb_StreetName.setWidth("98%");
		txtb_StreetName.setParent(row);

		row = new Row();
		row.setParent(rows);
		label = new Label("City");
		label.setId("lbl_City");
		label.setParent(row);
		txtb_City = new Textbox();
		txtb_City.setId("txtb_City");
		txtb_City.setWidth("98%");
		txtb_City.setParent(row);

		// +++++++++++++++ right GroupBox + Container
		Panel panelPhone = new Panel();
		panelPhone.setParent(colChildren2);
		Panelchildren panelchildrenPhone = new Panelchildren();
		panelchildrenPhone.setParent(panelPhone);

		Groupbox gbPhone = new Groupbox();
		gbPhone.setMold("3d");
		gbPhone.setParent(panelchildrenPhone);
		Caption captionGBPhone = new Caption();
		captionGBPhone.setLabel("Phone and Fax");
		captionGBPhone.setImage("/images/icons/telephone_16x16.png");
		captionGBPhone.setParent(gbPhone);

		grid = new Grid();
		grid.setParent(gbPhone);

		columns = new Columns();
		columns.setParent(grid);

		column = new Column();
		column.setWidth("40%");
		column.setParent(columns);

		rows = new Rows();
		rows.setParent(grid);

		row = new Row();
		row.setParent(rows);
		label = new Label("Phone");
		label.setId("lbl_Phone");
		label.setParent(row);
		txtb_Phone = new Textbox();
		txtb_Phone.setId("txtb_Phone");
		txtb_Phone.setWidth("98%");
		txtb_Phone.setParent(row);

		row = new Row();
		row.setParent(rows);
		label = new Label("Fax");
		label.setId("lbl_Fax");
		label.setParent(row);
		txtb_Fax = new Textbox();
		txtb_Fax.setId("txtb_Fax");
		txtb_Fax.setWidth("98%");
		txtb_Fax.setParent(row);

		return div;
	}

	/**
	 * Initiates the databinding. <br>
	 * 1. Bind a variable name to the bean.<br>
	 * 2. Attach the component.ID to a bean.property.<br>
	 * 3. Attach the listBox selectedItem to the bean.<br>
	 */
	private void initDataBinding() {

		// init the bean with the first record in the personList
		setPerson(new PersonDAOImpl().getFirstPersonInList());

		// add bindings
		binder.bindBean("person", person);
		binder.addBinding(listBoxPerson, "selectedItem", "person");
		binder.addBinding(txtb_LastName, "value", "person.lastName");
		binder.addBinding(txtb_FirstName, "value", "person.firstName");
		binder.addBinding(txtb_StreetName, "value", "person.street");
		binder.addBinding(txtb_City, "value", "person.city");
		binder.addBinding(txtb_Phone, "value", "person.phone");
		binder.addBinding(txtb_Fax, "value", "person.fax");

		binder.loadAll();

	}

	/**
	 * 
	 */
	public final class OnClickBtnHelpEventListener implements EventListener {
		@Override
		public void onEvent(Event event) throws Exception {

			Window win = new Window();
			win.setTitle("I'm a help window in modal mode");
			win.setWidth("300px");
			win.setHeight("250px");
			win.setClosable(true);
			win.setParent(_main);

			Label lbl = new Label("This is a help text. I hope it can be useful for you.");
			lbl.setParent(win);

			win.doModal();
		}
	}

	public final class OnClickBtnSearchEventListener implements EventListener {

		@Override
		public void onEvent(Event event) throws Exception {

			Window win = new Window();
			win.setId("searchWindow");
			win.setTitle("Search for Customers");
			win.setHeight("100px");
			win.setWidth("300px");
			win.setClosable(true);
			win.setParent(_main);

			Grid grid = new Grid();
			grid.setParent(win);

			Columns columns = new Columns();
			columns.setParent(grid);

			Column column = new Column();
			column.setWidth("40%");
			column.setParent(columns);
			column = new Column();
			column.setWidth("60%");
			column.setParent(columns);

			Rows rows = new Rows();
			rows.setParent(grid);

			Row row = new Row();
			row.setParent(rows);

			Label label = new Label("Last Name");
			label.setId("lbl_SearchLastName");
			label.setParent(row);
			Textbox txtb_Search = new Textbox();
			txtb_Search.setId("txtb_SearchLastName");
			txtb_Search.setWidth("98%");
			txtb_Search.setParent(row);

			Separator sep = new Separator();
			sep.setBar(true);
			sep.setParent(win);

			Button btnOK = new Button();
			btnOK.setLabel("Search");
			btnOK.addEventListener("onClick", new OnClickBtnOKEventListener());
			btnOK.setParent(win);

			win.doModal();

		}
	}

	/**
	 * 
	 * @author sge
	 * 
	 */
	public final class OnClickBtnOKEventListener implements EventListener {

		@Override
		public void onEvent(Event event) throws Exception {

			System.out.println(event.getName());

			Window win = (Window) event.getTarget().getFellow("searchWindow");

			String lastName = ((Textbox) win.getFellow("txtb_SearchLastName")).getValue();

			listBoxPerson.setModel(new BindingListModelList(new PersonDAOImpl().getPersonsByLastName(lastName), true));

			win.onClose();

		}

	}

	// ++++++++++++++++ Getter/Setter ++++++++++++++++

	public Person getPerson() {
		return person;
	}

	public void setPerson(Person person) {
		this.person = person;
	}

	public Listbox getListBoxPerson() {
		return listBoxPerson;
	}

	public void setListBoxPerson(Listbox listBoxPerson) {
		this.listBoxPerson = listBoxPerson;
	}

	public Window get_main() {
		return _main;
	}

	public void set_main(Window main) {
		_main = main;
	}

}

.
PersonList.java

import org.zkoss.zkplus.databind.BindingListModelList;
import org.zkoss.zul.Div;
import org.zkoss.zul.Listbox;
import org.zkoss.zul.Listhead;
import org.zkoss.zul.Listheader;
import org.zkoss.zul.Window;

import com.zksample.backend.dao.PersonDAO;
import com.zksample.backend.dao.impl.PersonDAOImpl;

/**
 * Creates a listBox for the person data.<br>
 * 
 * @author sgerth sge(at)forsthaus(dot)de
 * 
 */
public class PersonList extends Window {

	private static final long serialVersionUID = 1L;

	private Listbox listBoxPerson;
	private Listheader lh_LastName;
	private Listheader lh_FirstName;
	private Listheader lh_City;
	private Listheader lh_Street;
	private Listheader lh_phone;

	private PersonDAO personDAO;

	public PersonList() {
		super();
		this.appendChild(createPersonList());
	}

	/**
	 * Creates the listBox for the person data.
	 * 
	 * @return Div with listBox
	 */
	public Div createPersonList() {

		Div div = new Div();
		div.setId("divListBoxPerson");

		listBoxPerson = new Listbox();
		listBoxPerson.setId("listBoxPerson");
		listBoxPerson.setWidth("100%");
		listBoxPerson.setHeight("300px");
		// listBoxPerson.setVflex("1");
		listBoxPerson.setMultiple(false);
		listBoxPerson.setMold("paging");
		listBoxPerson.setParent(div);

		Listhead listhead = new Listhead();
		listhead.setSizable(true);
		listhead.setParent(listBoxPerson);

		lh_LastName = new Listheader();
		lh_LastName.setLabel("last_name");
		lh_LastName.setWidth("20%");
		lh_LastName.setImage("/images/icons/create_doc.gif");
		lh_LastName.setParent(listhead);

		lh_FirstName = new Listheader();
		lh_FirstName.setLabel("first_name");
		lh_FirstName.setWidth("20%");
		lh_FirstName.setImage("/images/icons/create_doc.gif");
		lh_FirstName.setParent(listhead);

		lh_City = new Listheader();
		lh_City.setLabel("city");
		lh_City.setWidth("20%");
		lh_City.setImage("/images/icons/create_doc.gif");
		lh_City.setParent(listhead);

		lh_Street = new Listheader();
		lh_Street.setLabel("street");
		lh_Street.setWidth("20%");
		lh_Street.setImage("/images/icons/create_doc.gif");
		lh_Street.setParent(listhead);

		lh_phone = new Listheader();
		lh_phone.setLabel("phone");
		lh_phone.setWidth("20%");
		lh_phone.setImage("/images/icons/create_doc.gif");
		lh_phone.setParent(listhead);

		listBoxPerson.setPageSize(15);
		// init with data
		listBoxPerson.setModel(new BindingListModelList(getPersonDAO().getAllPersons(), true));
		listBoxPerson.setItemRenderer(new PersonListItemRenderer());

		return div;
	}

	// +++++++++++++++++++++ getter / setter ++++++++++++

	public void setPersonDAO(PersonDAO personDAO) {
		this.personDAO = personDAO;
	}

	public PersonDAO getPersonDAO() {
		if (personDAO == null) {
			personDAO = new PersonDAOImpl();
			setPersonDAO(personDAO);
		}
		return personDAO;
	}
}

.
PersonListItemRenderer.java

import org.zkoss.zul.Listcell;
import org.zkoss.zul.Listitem;
import org.zkoss.zul.ListitemRenderer;

import com.zksample.backend.model.Person;

/**
 * ListItemRenderer for the PersonListbox.<br>
 * 
 * @author sgerth sge(at)forsthaus(dot)de
 * 
 */
public class PersonListItemRenderer implements ListitemRenderer {

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

		Person person = (Person) data;

		Listcell lc;
		lc = new Listcell(person.getLastName());
		lc.setParent(item);
		lc = new Listcell(person.getFirstName());
		lc.setParent(item);
		lc = new Listcell(person.getCity());
		lc.setParent(item);
		lc = new Listcell(person.getStreet());
		lc.setParent(item);
		lc = new Listcell(person.getPhone());
		lc.setParent(item);

		item.setAttribute("data", data);
	}
}

.
PersonSearchDialog.java

import org.zkoss.zk.ui.SuspendNotAllowedException;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zkplus.databind.BindingListModelList;
import org.zkoss.zul.Button;
import org.zkoss.zul.Column;
import org.zkoss.zul.Columns;
import org.zkoss.zul.Grid;
import org.zkoss.zul.Label;
import org.zkoss.zul.Listbox;
import org.zkoss.zul.Row;
import org.zkoss.zul.Rows;
import org.zkoss.zul.Separator;
import org.zkoss.zul.Textbox;
import org.zkoss.zul.Window;

import com.zksample.backend.dao.PersonDAO;
import com.zksample.backend.dao.impl.PersonDAOImpl;

/**
 * Search Dialog for the person bean.<br>
 * 
 * @author sgerth sge(at)forsthaus(dot)de
 * 
 */
public class PersonSearchDialog extends Window {

	private static final long serialVersionUID = 1L;

	private Window personSearchDialog;
	private Textbox txtb_Search;
	private PersonDAO personDAO;

	public PersonSearchDialog(final MyPersonRichletImpl myPersonRichletImpl) throws SuspendNotAllowedException, InterruptedException {
		System.out.println("PersonSearchDialog created");

		personSearchDialog = this;

		this.setId("searchWindow");
		this.setTitle("Search for Customers");
		this.setHeight("100px");
		this.setWidth("300px");
		this.setClosable(true);
		this.setParent(myPersonRichletImpl.get_main());

		Grid grid = new Grid();
		grid.setParent(this);

		Columns columns = new Columns();
		columns.setParent(grid);

		Column column = new Column();
		column.setWidth("40%");
		column.setParent(columns);
		column = new Column();
		column.setWidth("60%");
		column.setParent(columns);

		Rows rows = new Rows();
		rows.setParent(grid);

		Row row = new Row();
		row.setParent(rows);

		Label label = new Label("Last Name");
		label.setId("lbl_SearchLastName");
		label.setParent(row);
		txtb_Search = new Textbox();
		txtb_Search.setId("txtb_SearchLastName");
		txtb_Search.setWidth("98%");
		txtb_Search.setParent(row);

		Separator sep = new Separator();
		sep.setBar(true);
		sep.setParent(this);

		Button btnOK = new Button();
		btnOK.setLabel("Search");

		btnOK.addEventListener("onClick", new EventListener() {

			@Override
			public void onEvent(Event event) throws Exception {
				System.out.println("PersonSearchDialog " + event.getTarget() + " " + event.getName());

				// process searching
				// Window w = (Window) myPersonRichletImpl.get_main();

				Listbox listBoxPerson = myPersonRichletImpl.getListBoxPerson();
				listBoxPerson.setModel(new BindingListModelList(getPersonDAO().getPersonsByLastName(txtb_Search.getValue()), true));

				personSearchDialog.onClose();
			}
		});
		btnOK.setParent(this);

		this.doModal();
	}

	// ++++++++++++++++ getter / setter ++++++++++++

	public void setPersonDAO(PersonDAO personDAO) {
		this.personDAO = personDAO;
	}

	public PersonDAO getPersonDAO() {
		if (personDAO == null) {
			personDAO = new PersonDAOImpl();
			setPersonDAO(personDAO);
		}
		return personDAO;
	}
}

.
Person.java

import java.io.Serializable;

/**
 * Person Bean.<br>
 * 
 * @author sgerth sge(at)forsthaus(dot)de
 * 
 */
public class Person implements Serializable {

	private static final long serialVersionUID = -4591732272301777879L;

	private int id = 0;
	private String firstName = "";
	private String lastName = "";
	private String city = "";
	private String street = "";
	private String phone = "";
	private String fax = "";

	public Person() {
	}

	public Person(int id, String firstName, String lastName, String city, String street, String phone, String fax) {
		this.setId(id);
		this.firstName = firstName;
		this.lastName = lastName;
		this.city = city;
		this.street = street;
		this.phone = phone;
		this.fax = fax;
	}

	public void setId(int id) {
		this.id = id;
	}

	public int getId() {
		return id;
	}

	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}

	public String getFirstName() {
		return firstName;
	}

	public void setLastName(String lastName) {
		this.lastName = lastName;
	}

	public String getLastName() {
		return lastName;
	}

	public void setCity(String city) {
		this.city = city;
	}

	public String getCity() {
		return city;
	}

	public void setStreet(String street) {
		this.street = street;
	}

	public String getStreet() {
		return street;
	}

	public void setPhone(String phone) {
		this.phone = phone;
	}

	public String getPhone() {
		return phone;
	}

	public void setFax(String fax) {
		this.fax = fax;
	}

	public String getFax() {
		return fax;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((city == null) ? 0 : city.hashCode());
		result = prime * result + ((fax == null) ? 0 : fax.hashCode());
		result = prime * result + ((firstName == null) ? 0 : firstName.hashCode());
		result = prime * result + id;
		result = prime * result + ((lastName == null) ? 0 : lastName.hashCode());
		result = prime * result + ((phone == null) ? 0 : phone.hashCode());
		result = prime * result + ((street == null) ? 0 : street.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Person other = (Person) obj;
		if (city == null) {
			if (other.city != null)
				return false;
		} else if (!city.equals(other.city))
			return false;
		if (fax == null) {
			if (other.fax != null)
				return false;
		} else if (!fax.equals(other.fax))
			return false;
		if (firstName == null) {
			if (other.firstName != null)
				return false;
		} else if (!firstName.equals(other.firstName))
			return false;
		if (id != other.id)
			return false;
		if (lastName == null) {
			if (other.lastName != null)
				return false;
		} else if (!lastName.equals(other.lastName))
			return false;
		if (phone == null) {
			if (other.phone != null)
				return false;
		} else if (!phone.equals(other.phone))
			return false;
		if (street == null) {
			if (other.street != null)
				return false;
		} else if (!street.equals(other.street))
			return false;
		return true;
	}

}


.
PersonDAO.java

import java.util.List;

import com.zksample.backend.model.Person;

/**
 * DAO methods for the person bean.<br>
 * 
 * @author sgerth sge(at)forsthaus(dot)de
 * 
 */
public interface PersonDAO {

	/**
	 * EN: Gets back a list off all persons.<br>
	 * DE: Gibt eine Liste aller Personen Objekte zurueck.<br>
	 * 
	 * @return List of Persons / Liste von Personen
	 */
	public List<Person> getAllPersons();

	/**
	 * EN: Gets back a list off all persons by their LastName.<br>
	 * DE: Gibt eine Liste aller Personen zurueck deren Nachname mit dem
	 * Parameter uebereinstimmt.<br>
	 * 
	 * @param lastName
	 *            LastName for searching
	 * 
	 * @return List of Persons / Liste von Personen
	 */
	public List<Person> getPersonsByLastName(String lastName);

	/**
	 * EN: Gets back the first persons in the list.<br>
	 * DE: Gibt das erste Personen Objekt in der Liste zurueck.<br>
	 * 
	 * @return Person obj / Person obj
	 */
	public Person getFirstPersonInList();

}

.
PersonDAOImpl.java

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang.StringUtils;

import com.zksample.backend.dao.PersonDAO;
import com.zksample.backend.model.Person;

/**
 * EN: DAO method implementation for the person bean.<br>
 * DE: DAO Methoden Implementierung fuer den person bean.<br>
 * 
 * @author sgerth sge(at)forsthaus(dot)de
 * 
 */
public class PersonDAOImpl implements PersonDAO {

	@Override
	public List<Person> getAllPersons() {
		List<Person> result = new ArrayList<Person>();

		Person person;
		person = new Person(1, "Hans", "Möller", "Hamburg", "Hauptstrasse 23", "034568234", "3786487634");
		result.add(person);
		person = new Person(2, "Werner", "Meier", "Freiburg", "Hauptstrasse 6", "74837468234", "45653786487634");
		result.add(person);
		person = new Person(3, "Lutz", "Hafflinger", "Berlin", "An der Siegessäule 234", "2347468234", "6123786487634");
		result.add(person);
		person = new Person(4, "Bill", "Gates", "New York", "50, street 1234", "2347468234", "111213786487634");
		result.add(person);
		person = new Person(5, "Shawn", "Cassidy", "New Orleans", "23, baker street 343", "1247468234", "1323786487634");
		result.add(person);
		person = new Person(6, "Hans", "Müller", "Hamburg", "Hauptstrasse 23", "034568234", "2223786487634");
		result.add(person);
		person = new Person(7, "Uli", "Huber", "Mannheim", "In den Weihern 12", "034568234", "1113786487634");
		result.add(person);
		person = new Person(8, "Stephan", "Schneider", "Olvenstedt", "Hasselbachplatz 44", "034568234", "1233786487634");
		result.add(person);
		person = new Person(9, "Volker", "Schindler", "Frankfurt", "Am breiten Weg 21", "034568234", "2133786487634");
		result.add(person);
		person = new Person(10, "Rüdiger", "Krombach", "München", "Werner-Siemens-Ring 45", "034568234", "1563786487634");
		result.add(person);
		person = new Person(11, "Felix", "Haudrauf", "Bischoffingen", "Hauptstrasse 81", "034568234", "1873786487634");
		result.add(person);
		person = new Person(12, "Björn", "Weissglut", "Stuttgart", "Ambrosiusstrasse 34", "034568234", "1673786487634");
		result.add(person);
		person = new Person(13, "Klaus", "Ritter", "Ober Ursel", "Stoffelweg 66", "034568234", "4443786487634");
		result.add(person);
		person = new Person(14, "Michael", "Urbräu", "Unter Ursel", "Neben den Gleisen 34", "034568234", "4553786487634");
		result.add(person);
		person = new Person(15, "Helmut", "Riegeler", "Hügelheim", "Am Bach 12", "034568234", "663786487634");
		result.add(person);
		person = new Person(16, "Xaver", "Ganther", "Stendal", "Hauptstrasse 45", "034568234", "773786487634");
		result.add(person);
		person = new Person(17, "Hans", "Meier", "Hamburg", "Hauptstrasse 23", "034568234", "883786487634");
		result.add(person);
		person = new Person(18, "Werner", "Meier", "Freiburg", "Hauptstrasse 6", "74837468234", "993786487634");
		result.add(person);
		person = new Person(19, "Lutz", "Ritter", "Berlin", "An der Siegessäule 234", "2347468234", "7773786487634");
		result.add(person);
		person = new Person(20, "Bill", "Gates", "New York", "50, street 1234", "2347468234", "443786487634");
		result.add(person);
		person = new Person(21, "Shawn", "Cassidy", "New Orleans", "23, baker street 343", "1247468234", "5553786487634");
		result.add(person);
		person = new Person(22, "Hans", "Meier", "Stendal", "Hauptstrasse 23", "034568234", "4323786487634");
		result.add(person);
		person = new Person(23, "Uli", "Haudrauf", "Mannheim", "In den Weihern 12", "034568234", "1763786487634");
		result.add(person);
		person = new Person(24, "Stephan", "Schneider", "Olvenstedt", "Hasselbachplatz 44", "034568234", "7243786487634");
		result.add(person);
		person = new Person(25, "Volker", "Schindler", "Hügelheim", "Am breiten Weg 21", "034568234", "3763786487634");
		result.add(person);
		person = new Person(26, "Rüdiger", "Krombach", "München", "Werner-Siemens-Ring 45", "034568234", "17233786487634");
		result.add(person);
		person = new Person(27, "Felix", "Haudrauf", "Bischoffingen", "Hauptstrasse 81", "034568234", "3453786487634");
		result.add(person);
		person = new Person(28, "Björn", "Cassidy", "Stuttgart", "Ambrosiusstrasse 34", "034568234", "5643786487634");
		result.add(person);
		person = new Person(29, "Klaus", "Ritter", "Ober Ursel", "Stoffelweg 66", "034568234", "5673786487634");
		result.add(person);
		person = new Person(30, "Michael", "Riegeler", "Mannheim", "Neben den Gleisen 34", "034568234", "8883786487634");
		result.add(person);
		person = new Person(31, "Helmut", "Riegeler", "München", "Am Bach 12", "034568234", "9993786487634");
		result.add(person);
		person = new Person(32, "Xaver", "Ganther", "Stendal", "Hauptstrasse 45", "034568234", "9873786487634");
		result.add(person);
		person = new Person(33, "Hans", "Miller", "Hamburg", "Hauptstrasse 23", "034568234", "3453786487634");
		result.add(person);
		person = new Person(34, "Werner", "Meier", "Freiburg", "Hauptstrasse 6", "74837468234", "2953786487634");
		result.add(person);
		person = new Person(35, "Lutz", "Hafflinger", "Berlin", "An der Siegessäule 234", "2347468234", "5433786487634");
		result.add(person);
		person = new Person(36, "Bill", "Gates", "New York", "50, street 1234", "2347468234", "9993786487634");
		result.add(person);
		person = new Person(37, "Shawn", "Cassidy", "New Orleans", "23, baker street 343", "1247468234", "9123786487634");
		result.add(person);
		person = new Person(38, "Hans", "Riegeler", "Hamburg", "Hauptstrasse 23", "034568234", "3873786487634");
		result.add(person);
		person = new Person(39, "Uli", "Urbräu", "Mannheim", "In den Weihern 12", "034568234", "9153786487634");
		result.add(person);
		person = new Person(40, "Stephan", "Ritter", "Olvenstedt", "Hasselbachplatz 44", "034568234", "1093786487634");
		result.add(person);
		person = new Person(41, "Volker", "Haudrauf", "Frankfurt", "Am breiten Weg 21", "034568234", "1043786487634");
		result.add(person);
		person = new Person(42, "Rüdiger", "Krombach", "Hügelheim", "Werner-Siemens-Ring 45", "034568234", "1023786487634");
		result.add(person);
		person = new Person(43, "Felix", "Haudrauf", "Bischoffingen", "Hauptstrasse 81", "034568234", "1003786487634");
		result.add(person);
		person = new Person(44, "Björn", "Weissglut", "Stuttgart", "Ambrosiusstrasse 34", "034568234", "1083786487634");
		result.add(person);
		person = new Person(45, "Klaus", "Ritter", "Ober Ursel", "Stoffelweg 66", "034568234", "2346487634");
		result.add(person);
		person = new Person(46, "Michael", "Urbräu", "Bischoffingen", "Neben den Gleisen 34", "034568234", "8763786487634");
		result.add(person);
		person = new Person(47, "Helmut", "Riegeler", "Hamburg", "Am Bach 12", "034568234", "34653786487634");
		result.add(person);

		return result;
	}

	@Override
	public List<Person> getPersonsByLastName(String lastName) {

		List<Person> allList = new ArrayList<Person>();
		List<Person> result = new ArrayList<Person>();

		allList = getAllPersons();

		if (StringUtils.isEmpty(lastName) && StringUtils.isBlank(lastName)) {
			result = allList;
			return result;
		}

		int i = 0;
		for (Person person : allList) {
			if (((Person) allList.get(i)).getLastName().equalsIgnoreCase(lastName)) {
				result.add(person);

			}
			i = i + 1;
		}

		return result;
	}

	@Override
	public Person getFirstPersonInList() {
		Person person = null;

		List<Person> list = getAllPersons();

		if (list.size() > 0) {
			person = (Person) list.get(0);
		}

		return person;
	}

}

link publish delete flag offensive edit

answered 2010-05-04 18:50:22 +0800

robertpic71 gravatar image robertpic71
1275 1

Hi,

many examples here... :-)

The the root-cause:

I think there is bug: the databinder seems to setup a wrong event-handling.
It seems, that the event is fired for the last row with cursor hold. Everything works fine, if you use only the button with the "cursor holding row".

So, i think you should post an bug.

One more example and work-a-round, by handling the event inside the controller/composer:

The zul-file: (i moved the databinderinit to the composer and removed all binder-events)

<?page title="Books"?>
<zk xmlns="http://www.zkoss.org/2005/zul" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.zkoss.org/2005/zul http://www.zkoss.org/2005/zul/zul.xsd " >
		
<window id="win" width="100%" height="100%" apply="demo.BookController">
	<grid model="@{win$composer.bookList}"  >
		<columns>
			<column label="id" />
			<column label="TitleEdit" />
			<column label="Titleview" />
			<column  />
		</columns>
		<rows >
			<row self="@{each=book}" >
				<label value="@{book.id}" />
				<textbox value="@{book.title, save-when='none'}" />
				<label value="@{book.title}"/>
				<button id="btnSave" label="Save changes" />
			</row>
		</rows>
	</grid>
</window>
</zk>

The composer/controller:

package demo;

import ...

@SuppressWarnings("serial")
public class BookController extends GenericForwardComposer {
	
	AnnotateDataBinder binder;
	ArrayList<Book> bookList;
	
	public void doAfterCompose(Component comp) throws Exception {
		super.doAfterCompose(comp);
		binder = new AnnotateDataBinder(comp);
				
		Book b1 = new Book();
		b1.setId(1);
		b1.setTitle("b1");

		Book b2 = new Book();
		b2.setId(2);
		b2.setTitle("b2");

		bookList = new ArrayList<Book>();
		bookList.add(b1);
		bookList.add(b2);
		
		binder.loadAll();
	}
	/*
	 * Handle the Save-button, retrieve the row and execute
	 * a binding-save
	 */
	public void onClick$btnSave(ForwardEvent event) {
		Component row =  event.getOrigin().getTarget().getParent();
		binder.saveComponent(row);
	}
	public List<Book> getBookList() {
		return bookList;
	}
}

- I setup my own binder-instance inside the afterCompose and have to init the first load (binder.loadAll()).
- the composer handles the onClick-Event and perform the binding-save for the target-row

And it's of course a "matter of taste", but i prefer that the "controller manage the events".

/Robert

link publish delete flag offensive edit

answered 2010-05-05 06:02:44 +0800

samchuang gravatar image samchuang
4084 4

@robertpic71

thanks for the example

link publish delete flag offensive edit

answered 2010-05-05 19:11:33 +0800

mirjalali gravatar image mirjalali
27 1

Thanks a lot robertpic71.
Can that be done without a controller, i.e. is there a way to access the "binder" object in the zul file?

link publish delete flag offensive edit

answered 2010-05-05 21:55:29 +0800

robertpic71 gravatar image robertpic71
1275 1

You can store the binder to any component (in my example: win) and retrieve the binder with getAttribute("binder")

Here is the zscript example:
+ root-option for the databinder
+ id for the window-component for storing the databinder
+ onSave method
+ onClick event-handling with zscript
- remove all binding-events

<?init class="org.zkoss.zkplus.databind.AnnotateDataBinderInit" root="./win"?>
<?page title="Books"?>
<zk xmlns="http://www.zkoss.org/2005/zul" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.zkoss.org/2005/zul http://www.zkoss.org/2005/zul/zul.xsd " >
		<zscript><![CDATA[
		    class Book {
		    	private int id;
		    	private String title;
		    	public int getId() {
		    		return id;
		    	}
		    	public void setId(int i) {
		    		id = i;
		    	}
		    	public String getTitle() {
		    		return title;
		    	}
		    	public void setTitle(String t) {
		    		title = t;
		    	}
		    }
		    
		    Book b1 = new Book();
		    b1.setId(1);
		    b1.setTitle("b1");
		    
		    Book b2 = new Book();
		    b2.setId(2);
		    b2.setTitle("b2");
		    
		    List bookList = new ArrayList();
		    bookList.add(b1);
		    bookList.add(b2);
		    
		    public void onSave(Component row) {
		    	AnnotateDataBinder binder = (AnnotateDataBinder) win.getAttribute("binder");
		    	binder.saveComponent(row);
		    	
		    }	
		]]></zscript>
<window id="win" width="100%" height="100%" >
	<grid model="@{bookList}"  >
		<columns>
			<column label="id" />
			<column label="TitleEdit" />
			<column label="Titleview" />
			<column  />
		</columns>
		<rows >
			<row self="@{each=book}" >
				<label value="@{book.id}" />
				<textbox value="@{book.title, save-when='none' }" />
				<label value="@{book.title}"/>
				<button id="btnSave" label="Save changes" onClick="onSave(self.getParent())"/>
			</row>
		</rows>
	</grid>
</window>
</zk>

Note:
1.) zscript will be interpreted
2.) In my opinion, your example should work also - this is a bug (the event is always fired for the row with the last onChange, but should fired for the row with the button).

/Robert

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-30 04:08:10 +0800

Seen: 1,126 times

Last updated: May 05 '10

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