0

Strange bug in Chrome (zk 5.0.8)

asked 2011-10-19 11:10:51 +0800

cyiannoulis gravatar image cyiannoulis
1191 10

While i was trying to help JChiu i posted a very simple example based on some code of my own. Playing a while with this sample i came up with a strange behavior happening only in Chrome (version 8.0.552.237).

Directions to anyone who wants to give it a try:
1. Open the page SchoolsList.zul
2. Scroll down at the end of the list.
3. Select a list item and press "edit" in the toolbar.
4. A dialog will popup. Press "exit" or close the dialog using the "X" button.
5. Press again the edit button. The dialog will popup again. Close the dialog.
6. Press again (ok, this is the last one) the edit button. The dialog pops up normally only this time you will see that the list box has been refreshed and it scrolls back at the begining of the list. This happens always on the third time!!

I am posting here the code. Any help would be much appreciated.

The model class (school.java)

package schools;

import java.io.Serializable;

public class School implements Serializable {

	private static final long serialVersionUID = 1L;
	
	private String code;
	private String name;
	private String address;
	
	public School(String code, String name, String address) {
		super();
		this.code = code;
		this.name = name;
		this.address = address;
	}

	public String getCode() {
		return code;
	}

	public void setCode(String code) {
		this.code = code;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getAddress() {
		return address;
	}

	public void setAddress(String address) {
		this.address = address;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((code == null) ? 0 : code.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;
		School other = (School) obj;
		if (code == null) {
			if (other.code != null)
				return false;
		} else if (!code.equals(other.code))
			return false;
		return true;
	}
	
}

The main list (SchoolsList.zul)

<?page title="Schools" contentType="text/html;charset=UTF-8"?>
<zk>
<window id="winSchools" title="Schools" border="normal" height="100%" width="100%"
		apply="schools.SchoolsListController">
	
	<toolbar>
		<toolbarbutton id="tbtnEdit" label="Edit" image="/images/tb-edit.png" />
		<toolbarbutton id="tbtnRemove" label="Remove" image="/images/tb-delete.png" />
	</toolbar>
	
	<listbox id="lbSchools" model="@{ controller.schools }" selectedItem="@{ controller.selectedSchool }" 
							fixedLayout="true" vflex="true">
	
		<listhead sizable="true">
			<listheader label="Code" width="50px" />
			<listheader label="Name" width="150px"/>
			<listheader label="Address" width="200px"/>	
		</listhead>

		<listitem self="@{each='school'}" value="@{school}" >					
			<listcell label="@{school.code}" />
			<listcell label="@{school.name}" />
			<listcell label="@{school.address}" />
		</listitem>

	</listbox>
	
</window>
</zk>

The SchoolsList composer

package schools;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zk.ui.SuspendNotAllowedException;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.util.GenericForwardComposer;
import org.zkoss.zkplus.databind.AnnotateDataBinder;
import org.zkoss.zul.Messagebox;
import org.zkoss.zul.api.Listbox;
import org.zkoss.zul.api.Window;

public class SchoolsListController extends GenericForwardComposer {

	private static final long serialVersionUID = 1L;
	
	private AnnotateDataBinder binder;
	
	private Window winSchools;

	private Listbox lbSchools;
	private List<School> schools;
	private School selectedSchool;
	
	@Override
	public void doAfterCompose(Component comp) throws Exception {
		
		try {
			super.doAfterCompose(comp);
		} 
		catch (Exception e) {
			e.printStackTrace();
		}

		/*
		 * create the data binder and bind this composer as the base model bean 
		 */
		binder = new AnnotateDataBinder(comp);
		binder.bindBean("controller", this);
		
		/*
		 * populate data models
		 */
		createModels();
		
	}
	
	public void onCreate(Event event) {
		
		/*
		 * populate ui with data 
		 */
		binder.loadAll();
	}
	
	/*
	 * Create some mock data models  
	 */
	private void createModels() {
		
		schools = new ArrayList<School>();
		
		schools.add(new School("1", "1st school", "address-1"));
		schools.add(new School("2", "2nd school", "address-2"));
		schools.add(new School("3", "3rd school", "address-3"));
		schools.add(new School("4", "4th school", "address-4"));
		schools.add(new School("5", "5th school", "address-5"));
		schools.add(new School("6", "6th school", "address-6"));
		schools.add(new School("7", "7th school", "address-7"));
		schools.add(new School("8", "8th school", "address-8"));
		schools.add(new School("9", "9th school", "address-9"));
		
		schools.add(new School("10", "1st school", "address-1"));
		schools.add(new School("12", "2nd school", "address-2"));
		schools.add(new School("13", "3rd school", "address-3"));
		schools.add(new School("14", "4th school", "address-4"));
		schools.add(new School("15", "5th school", "address-5"));
		schools.add(new School("16", "6th school", "address-6"));
		schools.add(new School("17", "7th school", "address-7"));
		schools.add(new School("18", "8th school", "address-8"));
		schools.add(new School("19", "9th school", "address-9"));
		schools.add(new School("21", "1st school", "address-1"));
		schools.add(new School("22", "2nd school", "address-2"));
		schools.add(new School("23", "3rd school", "address-3"));
		schools.add(new School("24", "4th school", "address-4"));
		schools.add(new School("25", "5th school", "address-5"));
		schools.add(new School("26", "6th school", "address-6"));
		schools.add(new School("27", "7th school", "address-7"));
		schools.add(new School("28", "8th school", "address-8"));
		schools.add(new School("29", "9th school", "address-9"));
		schools.add(new School("31", "1st school", "address-1"));
		schools.add(new School("32", "2nd school", "address-2"));
		schools.add(new School("33", "3rd school", "address-3"));
		schools.add(new School("34", "4th school", "address-4"));
		schools.add(new School("35", "5th school", "address-5"));
		schools.add(new School("36", "6th school", "address-6"));
		schools.add(new School("37", "7th school", "address-7"));
		schools.add(new School("38", "8th school", "address-8"));
		schools.add(new School("39", "9th school", "address-9"));
		schools.add(new School("41", "1st school", "address-1"));
		schools.add(new School("42", "2nd school", "address-2"));
		schools.add(new School("43", "3rd school", "address-3"));
		schools.add(new School("44", "4th school", "address-4"));
		schools.add(new School("45", "5th school", "address-5"));
		schools.add(new School("46", "6th school", "address-6"));
		schools.add(new School("47", "7th school", "address-7"));
		schools.add(new School("48", "8th school", "address-8"));
		schools.add(new School("49", "9th school", "address-9"));
	}
	
	/**
	 * Event handler method triggered when the "edit" toolbar button is pressed 
	 */
	public void onClick$tbtnEdit() {
		
		if (selectedSchool == null) {
			try {
				Messagebox.show("You have to select a school from the list first.", "Error", Messagebox.OK, Messagebox.ERROR);
			} 
			catch (InterruptedException e) {
				e.printStackTrace();
			}
			return;
		}

		Map<String, Object> parameters = new HashMap<String, Object>();
		parameters.put("SELECTED_SCHOOL", selectedSchool);
		parameters.put("PARENT_WINDOW", winSchools);
		Window editDialog = (Window) Executions.createComponents("/schools/SchoolEditor.zul", winSchools, parameters);
		
		try {
			editDialog.doOverlapped();
			editDialog.setPosition("center");
		} 
		catch (SuspendNotAllowedException e) {
			e.printStackTrace();
		} 

	}
	
	/**
	 * This method is actualy an event handler triggered only from the edit dialog
	 * and it is responsible to reflect the data changes made to the list.
	 */
	public void onSchoolSaved() {

		int index = lbSchools.getSelectedIndex();
		
		if (index == -1)
			return;
		
		binder.loadComponent( lbSchools.getItemAtIndexApi(index) );
	}
	
	/**
	 * Event handler method triggered when the "remove" toolbar button is pressed 
	 */
	public void onClick$tbtnRemove() {
		
		if (selectedSchool == null) {
			try {
				Messagebox.show("You have to select a school from the list first.", "Error", Messagebox.OK, Messagebox.ERROR);
			} 
			catch (InterruptedException e) {
				e.printStackTrace();
			}
			return;
		}
			
		try {
			
			/*
			 * This event listener is needed to catch the response given by the user in the confirmation dialog  
			 */
			EventListener eventListener = new EventListener() {
				
				@Override
				public void onEvent(Event event) throws Exception {
					 switch (((Integer) event.getData()).intValue()) {
	                    case Messagebox.OK:
	                        deleteSchool();
	                        break;
					 }
				}
			};
			
			Messagebox.show("Are you sure you want to delete " + selectedSchool.getName() +  "?", 
							"Warning", 
							Messagebox.OK | Messagebox.CANCEL, 
							Messagebox.QUESTION,
							eventListener);
		} 
		catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * Delete the selected school 
	 */
	private void deleteSchool() {
		schools.remove(selectedSchool);
		selectedSchool = null;
		binder.loadComponent(lbSchools);
	}
	

	public AnnotateDataBinder getBinder() {
		return binder;
	}

	public void setBinder(AnnotateDataBinder binder) {
		this.binder = binder;
	}

	public List<School> getSchools() {
		return schools;
	}

	public void setSchools(List<School> schools) {
		this.schools = schools;
	}

	public School getSelectedSchool() {
		return selectedSchool;
	}

	public void setSelectedSchool(School selectedSchool) {
		this.selectedSchool = selectedSchool;
	}
	
}

The edit dialog (SchoolEditor.zul)

<?page title="Schools" contentType="text/html;charset=UTF-8"?>
<zk>
<window id="winEditor" title="School Editor" border="normal" height="350px" width="400px" closable="true"
		apply="schools.SchoolEditorController">
	
  <vlayout>
	
	<toolbar>
		<toolbarbutton id="tbtnSave" label="Save" image="/images/tb-save.png" />
		<toolbarbutton id="tbtnExit" label="Exit" image="/images/tb-exit.png" />
	</toolbar>

	<grid id="gridSchool">
		<columns>
			<column width="100px"/>
			<column/>
		</columns>
		<rows>
			<row>
				<label value="Code" />
				<textbox value="@{ controller.selectedSchool.code, access='both', save-when='none' }"/>
			</row>
			<row>
				<label value="Name" />
				<textbox value="@{ controller.selectedSchool.name, access='both', save-when='none' }"/>
			</row>
			<row>
				<label value="Address" />
				<textbox value="@{ controller.selectedSchool.address, access='both', save-when='none' }"/>
			</row>
		</rows>
	</grid>	
	
  </vlayout>
	
</window>
</zk>

The SchoolEditor composer

package schools;

import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zk.ui.util.GenericForwardComposer;
import org.zkoss.zkplus.databind.AnnotateDataBinder;
import org.zkoss.zul.api.Window;

public class SchoolEditorController extends GenericForwardComposer {

	private static final long serialVersionUID = 1L;
	
	private AnnotateDataBinder binder;

	private School selectedSchool;
	
	private Window parentWindow;
	
	private Window winEditor;
	
	@Override
	public void doAfterCompose(Component comp) throws Exception {
		
		try {
			super.doAfterCompose(comp);
		} 
		catch (Exception e) {
			e.printStackTrace();
		}

		/*
		 * create the data binder and bind this composer as the base model bean 
		 */
		binder = new AnnotateDataBinder(comp);
		binder.bindBean("controller", this);
		
		/*
		 * retrieve parameters passed here by the caller
		 */
		selectedSchool = (School)arg.get("SELECTED_SCHOOL");
		parentWindow = (Window)arg.get("PARENT_WINDOW"); 
	}
	
	public void onCreate(Event event) {
		
		/*
		 * populate ui with data 
		 */
		binder.loadAll();
	}
	
	/**
	 * Event handler for closing this dialog using the "exit" toolbar button 
	 */
	public void onClick$tbtnExit() {
		winEditor.detach();
	}
	
	/**
	 * Event handler for saving the model values
	 */
	public void onClick$tbtnSave() {
		binder.saveAll();
		winEditor.detach();
		Events.sendEvent(new Event("onSchoolSaved", parentWindow));
	}
	
	public AnnotateDataBinder getBinder() {
		return binder;
	}

	public void setBinder(AnnotateDataBinder binder) {
		this.binder = binder;
	}

	public School getSelectedSchool() {
		return selectedSchool;
	}

	public void setSelectedSchool(School selectedSchool) {
		this.selectedSchool = selectedSchool;
	}
	
}

thanks to all
/Costas

delete flag offensive retag edit

1 Reply

Sort by ยป oldest newest

answered 2011-12-22 01:54:42 +0800

hawk gravatar image hawk
2295 1 5
http://hawkphoenix.blogsp... ZK Team

Hi,
It doesn't happen in Chrome 16.

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: 2011-10-19 11:10:51 +0800

Seen: 146 times

Last updated: Dec 22 '11

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