-
FEATURED COMPONENTS
First time here? Check out the FAQ!
Hi,
I have a main windows with a list box to show a list of records. When a row is selected, another modal popup window for editing the selected record will be triggered by right click the context menu item. I have databinding in the main window and I expect all changes made in the modal popup window will be reflected back to the main window. Unfortunately, it is not the case. Can I use any databinding concepts to tackle this problem ?
Appreciate anyone could give me a hand and resolve the subject problem. Million Thanks. / Jonathan
Main Window
<?page title="School" contentType="text/html;charset=UTF-8"?> <?init class="org.zkoss.zkplus.databind.AnnotateDataBinderInit"?> <zk> <window id="schoolctlview" title="School" border="normal" apply="model.SchoolViewCtl"> <listbox id="lbSchool" mold="paging" pageSize="10" selectedItem="@{selected}" context="GridMenu"> <auxhead sclass="category-center"> <auxheader colspan="1"> <image src="/img/funnel.png" /> <textbox id="filter21" /> </auxheader> <auxheader colspan="1"> <image src="/img/funnel.png" /> <textbox id="filter22" /> </auxheader> <auxheader colspan="1"> <image src="/img/funnel.png" /> <textbox id="filter23" /> </auxheader> <auxheader colspan="1"> <image src="/img/funnel.png" /> <textbox id="filter24" /> </auxheader> <auxheader colspan="1"> <image src="/img/funnel.png" /> <textbox id="filter25" /> </auxheader> </auxhead> <listhead> <listheader label="School Code" /> <listheader label="School Name" /> <listheader label="Tel" /> <listheader label="Fax" /> <listheader label="Email" /> </listhead> </listbox> <menupopup id="GridMenu"> <menuitem id="mitemView" label="View" /> </menupopup> </window> </zk>
<?page id="pageSchool"title="School" contentType="text/html;charset=UTF-8"?> <window id="wSchool" title="School" border="normal" mode="modal"> <zscript><![CDATA[ import model.School; School sch = (School)execution.getArg().get("data"); ]]></zscript> <label value="Name:" /> <textbox id="nameTb" value="@{sch.school_name}"/> <button label="OK" xmlns:w="http://www.zkoss.org/2005/zk/client" w:onClick="this.$f('wSchool').fire('onClose');"/> </window>
Control
package model; 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.util.GenericForwardComposer; import org.zkoss.zkplus.databind.AnnotateDataBinder; import org.zkoss.zul.ListModel; import org.zkoss.zul.ListModelList; import org.zkoss.zul.Listbox; import org.zkoss.zul.Listcell; import org.zkoss.zul.Listitem; import org.zkoss.zul.ListitemRenderer; import org.zkoss.zul.Menuitem; import org.zkoss.zul.Window; public class SchoolViewCtl extends GenericForwardComposer { private Listbox lbSchool; private Menuitem mitemView; private AnnotateDataBinder binder; @Override public void doAfterCompose(Component comp) throws Exception { super.doAfterCompose(comp); List allSchools = new SchoolDAO().findAll(); ListModelList model = new ListModelList(allSchools); model.addSelection(allSchools.get(0)); lbSchool.setModel(model); lbSchool.setItemRenderer(new ListitemRenderer() { public void render(Listitem listItem, Object data) throws Exception { final School sch = (School) data; listItem.setValue(sch); new Listcell(sch.getSchool_code()).setParent(listItem); new Listcell(sch.getSchool_name()).setParent(listItem); new Listcell(sch.getTel()).setParent(listItem); new Listcell(sch.getFax()).setParent(listItem); new Listcell(sch.getEmail()).setParent(listItem); } }); } public void onClick$mitemView() { Window wSchool = new Window(); Map data = new HashMap(); data.put("data", (School)lbSchool.getSelectedItem().getValue()); wSchool = (Window)Executions.getCurrent().createComponents("school.zul", self, data); binder = new AnnotateDataBinder(wSchool); binder.loadAll(); } }
hi
Thank you very much
I try with small example based on this, but it is not working.
Here is the link
Regards Senthil M
Hi tita
you can refer to
http://www.zkoss.org/forum/listComment/19829-ZK-MVVM-Modal-Window
Hi,
I have a problem similar to jchiu one.
I have a window that opens a modal by clicking a button; the modal contains a form and I want that after I fill in all the form, the modal closes itself and results are shown in the window below. In reality nothing of that happens and I have null pointer exception. I already read all post about this topic and I also studied terrytornado examples.... but nothing!
I really hope that someone could help me...
attivita.zul
<?taglib uri="http://www.zkoss.org/dsp/web/core" prefix="c" ?> <?variable-resolver class="org.zkoss.zkplus.spring.DelegatingVariableResolver"?> <vlayout> <label sclass="title" value="${labels.attivita}" /> <window id="attivitaWindow" sclass="cardSys" border="none" apply="org.zkoss.bind.BindComposer" viewModel="@id('vm') @init('it.iks.smash.web.controller.AttivitaVM')" > <!-- bottone per aprire la modal window della ricerca --> <div id="button" apply="it.iks.smash.web.controller.AttivitaVM"> <button id="apriModal" label="Apri modal window" /> </div> ...
AttivitaVM.java controller for attivita.zul
@VariableResolver(org.zkoss.zkplus.spring.DelegatingVariableResolver.class) public class AttivitaVM extends SelectorComposer<Component>{ private static final long serialVersionUID = 1L; static Logger log = Logger.getLogger(AttivitaVM.class.getName()); @WireVariable(value = "attivitaService") private IAttivitaService attivitaService; private List<AttivitaAbstract> listAttivita; private AttivitaAbstract selectedAttivita; private AttivitaDettaglio attivitaDettaglio; @Wire private Textbox userTextBox; @Wire private Textbox cosdiaTextBox; @Wire private Listbox attivita; private AnnotateDataBinder binder; public Listbox getAttivita() { return attivita; } @Wire private Window attivitaWindow; private QueryManagerVM queryManagerController; public void setAttivita(Listbox attivita) { this.attivita = attivita; } @Listen("onClick = #apriModal") public void showModal(Event e) { log.info("@Listen(onClick=#apriModal)"); Window queryManager= new Window(); final HashMap<String, Object> map = new HashMap<String, Object>(); map.put("AttivitaVM", this); queryManager = (Window)Executions.getCurrent().createComponents("/WEB-INF/view/query-manager.zul", attivitaWindow, map); queryManager.doModal(); binder = new AnnotateDataBinder(queryManager); binder.loadAll(); } .....
query-manager.zul: the zul of the modal window
<?taglib uri="http://www.zkoss.org/dsp/web/core" prefix="c" ?> <?variable-resolver class="org.zkoss.zkplus.spring.DelegatingVariableResolver"?> <window id="queryManagerModal" closable="true" position="center,center" apply="org.zkoss.bind.BindComposer" title="Query Manager" border="normal" viewModel="@id('vm') @init('it.iks.smash.web.controller.QueryManagerVM')" validationMessage="@id('vmsg')" form="@id('fx') @load(vm.queryManagerBean) @save(vm.queryManagerBean, before='eseguiQuery') " > <vlayout> .... <div id="button" apply="it.iks.smash.web.controller.QueryManagerVM" > <button id="eseguiQuery" label="Ricerca" onClick="@Command('eseguiQuery')"/> </div> </vlayout> </window>
QueryManagerVM.java: controller for the modal window query-manager.zul
@VariableResolver(org.zkoss.zkplus.spring.DelegatingVariableResolver.class) public class QueryManagerVM extends SelectorComposer<Component>{ private static final long serialVersionUID = 1L; static Logger log = Logger.getLogger(AttivitaVM.class.getName()); @Wire("#queryManagerModal") private Window queryManagerModal; @WireVariable(value = "attivitaService") private IAttivitaService attivitaService; private AttivitaVM controllerAttivita;//controller della pagina delle attività private QueryManager queryManagerBean=new QueryManager(); .... @Init public void init(@ExecutionArgParam("AttivitaVM") AttivitaVM controllerAttivita) { log.info("init:: inizializzazione"); setControllerAttivita(controllerAttivita); log.info("doAfterCompose(Component comp):: setControllerAttivita()"); // la lista attività ha il controller della modalwindow getControllerAttivita().setQueryManagerController(this); log.info("doAfterCompose(Component comp):: getControllerAttivita()"); } @Listen("onClick=#eseguiQuery") public void search(){ log.info("onClick$eseguiQuery()"); if(queryManagerBean.getTextboxUser().isEmpty()) log.info("textboxuser vuota"); log.info("queryManagerBean.getTextboxUser() "+queryManagerBean.getTextboxUser()); HashMap<String, Condizione> condizioni=new HashMap<String, Condizione>(); condizioni=(HashMap<String, Condizione>) searchCheckTipoAttivita(); condizioni.putAll(searchCampiRicerca()); condizioni.putAll(searchBonificoRicerca()); if(condizioni.isEmpty()) log.info("onClick$eseguiQuery:: condizioni empty"); else log.info("onClick$eseguiQuery:: condizioni"+condizioni.keySet().toString()); List<AttivitaAbstract> listAttivita=attivitaService.ricerca(condizioni); for(int i=0; i<listAttivita.size(); i++){ log.info("search():: listAttività["+i+"]: "+listAttivita.get(i)+", "); } //getControllerAttivita().setLista(listAttivita); queryManagerModal.detach(); } .....
Thank you to anybody that could help me
only Pseudo-Code:
void doNew() { School school = new School(); setSelectedSchool(school); } You must told the binder to save the UI components data to the bean properties. (because in costas sample zul file is standing ... save-when='none'...) void doSave(){ getBinder.saveAll(); myDataBase.saveMyBeanData(getSelectedSchool()); }
best
Stephan
PS: Try to debug the article module in ZKsample2.
Online-demo: http://www.zk-web.de/zksample2/
wondering a trivial question. based on the code Costas provided, i try to add a new button to create a new school. This i thouht should be very simple by setting selectedSchool to new School(). However, no matter what had been entered into Modal Window, when I click save button, it always return a empty instance of School back to SchoolsListController. Any code / concepts I missed here? Really appreciate further assistance and I had been sitting and researching internet for 2 days. Many Thanks. / Jonathan.
Jonathan,
You will get all you need if you follow Stephan's links... Actually these are more or less the same links i followed to learn zk (thx stephan!)
Anyway if you are more impatient you can read below a fully working example of how to edit a list using an edit dialog.
The main schools list page:
<?page title="Schools" contentType="text/html;charset=UTF-8"?> <zk> <window id="winSchools" title="Schools" border="normal" height="100%" width="100%" apply="schools.SchoolsListController"> <vlayout> <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 }" 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> </vlayout> </window> </zk>
The controller of the main schools page:
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")); } /** * 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.doModal(); } catch (SuspendNotAllowedException e) { e.printStackTrace(); } catch (InterruptedException 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 page:
<?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> <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>
And finally the school editor 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; } }
Hope that helps
/Costas
Hi Costas,
Million thanks for your reply. Your understanding to my question is exactly the same what I want to achieve. I am really interested in your point 2. Appreciate if you would share some lights by illustrating the handshake of data Map & updateListView(). I actually very green in developing using ZK and I found using ListitemRenderer from reference manual but not quite sure after I close the modal dialog how to refresh the new values captured.
Once again. Many thanks for your time and grateful to have your further guidence.
Jonathan
Asked: 2011-10-18 10:03:22 +0800
Seen: 2,274 times
Last updated: Feb 06 '13