-
FEATURED COMPONENTS
First time here? Check out the FAQ!
I'm using form validation on a ZUL file where for various reasons I cannot perform absolutely all the validation required until I try to persist the data in the related MVVM 'save' command method.
In this case an exception may occur when the save/persist call is made to underlying DAO tier. In this case I want to push an error message into a ZUL label that displays an element of the 'ValidationMessages' map.
How would I do that from the MVVM view class?
You cannot get ValidationContext in command method, it is too late.
You can write a inner validator in the viewModel, so this validator can share data with this viewModel, (however if the validator mark validation, the command method will not be invoked)
or you can do the validation in the command method directly.
Can you supply an example please?
Here's a snippet to show my context, a command method that will delete an entry,
@Command @NotifyChange({ "selectedResource", "resources" }) public void deleteEntry() { if (fSelectedResource.getID() == ID_UNASSIGNED) { getResources().remove(fSelectedResource); fSelectedResource = null; } else { Messagebox.show("Delete [" + fSelectedResource.getTitle() + "] entry. Are you sure?", "Delete resource required entry", new Messagebox.Button[] { Messagebox.Button.YES, Messagebox.Button.NO }, Messagebox.QUESTION, new EventListener<ClickEvent>() { public void onEvent(ClickEvent e) { switch (e.getButton()) { case YES: try { resourceRequiredManager .delete(fSelectedResource.getID()); getResources().remove(fSelectedResource); fSelectedResource = null; } catch (UnknownResourceRequiredException ex) { // how to set validation error??!! } catch (PersistenceException ex) { // how to set validation error??!! } break; } } }); } }
The case you try to resolve is not a 'validation', it is kind of error handling (so it shouldn't use validation concept).
and, since you are using Messagebox to show a message to show up a confirm window, which means, it goes zk MVC(onEvent) way, it is not controlled by the MVVM binder, directly.
I have some example for you how to do this kind case in MVVM only or MVVM + UI(MVC) togehter.
<hbox> <window title="Base case" border="1" apply="org.zkoss.bind.BindComposer" viewModel="@id('vm') @init('org.zkoss.mvvm.examples.confirm_delete.ConfirmDeleteBase')"> <vbox> <listbox model="@bind(vm.items)" selectedItem="@bind(vm.selected)" width="200px"> <template name="model" > <listitem> <listcell label="@load(each)" /> </listitem> </template> </listbox> </vbox> <label value="@load(vm.message)" /> <hbox> <button label="delete" disabled="@load(empty vm.selected)" onClick="@command('delete')" /> </hbox> </window> </hbox>
package org.zkoss.mvvm.examples.confirm_delete; import java.util.ArrayList; import java.util.List; import org.zkoss.bind.annotation.Command; import org.zkoss.bind.annotation.NotifyChange; public class ConfirmDeleteBase { List<String> items = new ArrayList<String>(); String selected; String message; public ConfirmDeleteBase(){ items.add("A"); items.add("B"); items.add("C"); } public List<String> getItems(){ return items; } public String getSelected() { return selected; } public void setSelected(String selected) { this.selected = selected; } public String getMessage() { return message; } @Command @NotifyChange({"message","items","selected"}) public void delete(){ if(selected==null){ message = "You have to select an item"; }else{ try{ if(daoDelete(selected)){ items.remove(selected); message = selected + " was deleted"; selected = null; }else{ message = selected + " wasn't deleted"; } }catch(Exception x){ message = x.getMessage(); } } } protected boolean daoDelete(String data){ if("B".equals(selected)){ throw new RuntimeException("Oops, I simulate delete "+data+" fial here"); } return true; } }
<hbox> <window title="Case 1" border="1" apply="org.zkoss.bind.BindComposer" viewModel="@id('vm') @init('org.zkoss.mvvm.examples.confirm_delete.ConfirmDelete1')"> <vbox> <listbox model="@bind(vm.items)" selectedItem="@bind(vm.selected)" width="200px"> <template name="model" > <listitem> <listcell label="@load(each)" ></listcell> </listitem> </template> </listbox> </vbox> <label value="@load(vm.message)" ></label> <hbox> <button label="delete" disabled="@load(empty vm.selected)" onClick="@command(vm.needToConfirm?'showConfirm':'delete')" ></button> </hbox> <window title="Confirm " mode="modal" visible="@load(not empty vm.confirmMessage)" border="1" width="300px"> <vbox hflex="1" pack="center" align="center" style="padding:10px"> <label value="@load(vm.confirmMessage)"></label> <hlayout> <button label="Delete" onClick="@command('delete')" ></button> <button label="Cancel" onClick="@command('cancelConfirm')" ></button> </hlayout> </vbox> </window> </window> </hbox>
package org.zkoss.mvvm.examples.confirm_delete; import org.zkoss.bind.annotation.Command; import org.zkoss.bind.annotation.NotifyChange; public class ConfirmDelete1 extends ConfirmDeleteBase{ String confirmMessage; public String getConfirmMessage(){ return confirmMessage; } @Command @NotifyChange("confirmMessage") public void cancelConfirm(){ confirmMessage = null; } @Command @NotifyChange("confirmMessage") public void showConfirm(){ confirmMessage = "Do you really want to delete "+selected; } @Override @Command @NotifyChange({"message","items","selected","confirmMessage"}) public void delete(){ super.delete(); confirmMessage = null; //clean confirmMessage and notify } public boolean isNeedToConfirm(){ //simulate C doesn't need to be confirm if("C".equals(selected)){ return false; } return true; } }
<hbox> <window title="Case 1" border="1" apply="org.zkoss.bind.BindComposer" viewModel="@id('vm') @init('org.zkoss.mvvm.examples.confirm_delete.ConfirmDelete2')"> <vbox> <listbox model="@bind(vm.items)" selectedItem="@bind(vm.selected)" width="200px"> <template name="model" > <listitem> <listcell label="@load(each)" ></listcell> </listitem> </template> </listbox> </vbox> <label value="@load(vm.message)" ></label> <hbox> <button label="delete" disabled="@load(empty vm.selected)" onClick="@command(vm.needToConfirm?'showConfirm':'delete')" ></button> </hbox> </window> </hbox>
package org.zkoss.mvvm.examples.confirm_delete; import org.zkoss.bind.Binder; import org.zkoss.bind.annotation.Command; import org.zkoss.bind.annotation.ContextParam; import org.zkoss.bind.annotation.ContextType; import org.zkoss.bind.annotation.NotifyChange; import org.zkoss.zk.ui.event.EventListener; import org.zkoss.zul.Messagebox; import org.zkoss.zul.Messagebox.ClickEvent; public class ConfirmDelete2 extends ConfirmDeleteBase{ @Command public void showConfirm(@ContextParam(ContextType.BINDER) final Binder binder){ Messagebox.show("Do you really want to delete "+selected,"Confirm", new Messagebox.Button[] { Messagebox.Button.YES,Messagebox.Button.NO }, Messagebox.QUESTION,new EventListener<ClickEvent>() { public void onEvent(ClickEvent event) throws Exception { switch (event.getButton()) { case YES: //if you call super.delete here, since original zk event is not control by binder //the change of viewmodel will not update to the ui. //so, I post a delete to trigger to process it in binder controll. binder.postCommand("delete", null); } } }); } @Override protected boolean daoDelete(String data){ try{ super.daoDelete(data); return true; }catch(Exception x){ Messagebox.show(x.getMessage()); } return false; } public boolean isNeedToConfirm(){ //simulate C doesn't need to be confirm if("C".equals(selected)){ return false; } return true; } }
In my ZUL file I have...
<panel title="@load(vm.viewTitle)" height="100%" width="100%" apply="org.zkoss.bind.BindComposer" viewModel="@id('vm') @init('com.eis.zk.plan.entity.detail.PlanEntityResourceEditVM')" binder="@init(queueName='DataAreaQueue')" validationMessages="@id('vmsgs')">
it is not a public object and I suggest you create your own message object in you viewmodel and control your self if you want show message for a command execution.
Asked: 2012-06-13 10:54:01 +0800
Seen: 308 times
Last updated: Jun 18 '12