Your welcome, I know sometimes you want sometimes to do beautiful things, and forget the easy solution.
chillworld ( 2014-09-12 06:07:24 +0800 )edit-
FEATURED COMPONENTS
First time here? Check out the FAQ!
Hi,
Is that possible to validate my form before a global command?
Something like below:
<div form="@id('fx') @load(vm.entity) @save(vm.entity, before='myGlobalCommandHere')">
<textbox value="@bind(fx.field) @validator('beanValidator')" />
</div>
What I'm trying to do is to create an "input-field-only" div that can be injected into anywhere I want. So, for example, I can use it in a normal form (1 save button) or in a wizard (2 buttons,prev and next) with the same div.
I don't have a good solution by far, so if I can use global command here, thing might be much easier. Or any other suggest to achieve that goal is also welcome.
Thank you.
Hi M4tt.
Save before a globalCommand should not be possible (you can always try and test)
Documentation for that.
Now there is always a solution and a little adaptation could be do the trick :
<div form="@id('fx') @load(vm.entity) @save(vm.entity, before='someCommand')">
<textbox value="@bind(fx.field) @validator('beanValidator')" />
</div>
@Command
public void someCommand () {
BindUtils.postGlobalCommand(null,null,"myGlobalCommandHere",null);
}
Oke, I played a little around local.
Mine suggestion :
Remove all the different viewmodels and make ons bigger viewmodel.
Look at this example :
<?xml version="1.0" encoding="UTF-8"?>
<zk>
<window border="normal" title="hello" apply="org.zkoss.bind.BindComposer" viewModel="@id('vm') @init('be.chillworld.TestVM')">
<include id="formInput" src="@load(vm.include)"/>
<button label="change" onClick="@command('refresh')"/>
</window>
</zk>
<?xml version="1.0" encoding="UTF-8"?>
<zk xmlns="http://www.zkoss.org/2005/zul">
<div>
<textbox value="@load(vm.include1) @save(vm.include1, before='refresh')" constraint="no empty"/>
</div>
</zk>
<?xml version="1.0" encoding="UTF-8"?>
<zk xmlns="http://www.zkoss.org/2005/zul">
<div>
<textbox value="@load(vm.include2) @save(vm.include2, before='refresh')" constraint="no empty"/>
</div>
</zk>
package be.chillworld;
import org.zkoss.bind.annotation.BindingParam;
import org.zkoss.bind.annotation.Command;
import org.zkoss.bind.annotation.NotifyChange;
import org.zkoss.zul.Tabbox;
import org.zkoss.zul.Tab;
/**
*
* @author chillworld
*/
public class TestVM {
private int counter;
private String include1;
private String include2;
@Command
@NotifyChange("include")
public void refresh(){}
public String getInclude() {
switch (counter++) {
case 0 : return "include1.zul";
default : counter = 0;
return "include2.zul";
}
}
public String getInclude1() {
return include1;
}
public void setInclude1(String include1) {
this.include1 = include1;
}
public String getInclude2() {
return include2;
}
public void setInclude2(String include2) {
this.include2 = include2;
}
}
As you can see the included zul's talk with the main VM.
The constraint do work (leave textbox empty) before we go to next page.
If you hit the button multiple times, you'll also see that the previous value is returned so it's saved into the VM.
Like this you shouldn't have trouble's calling other VM's, you can create your 'save' or 'insert' operation at the end.
Greetz chill.
Your welcome, I know sometimes you want sometimes to do beautiful things, and forget the easy solution.
chillworld ( 2014-09-12 06:07:24 +0800 )editHi chill,
Thank you for replying, I didn't know there is an util class, it would help a lot. :)
Maybe my understanding about the form validation is wrong, but here what I want is triggering the validation before I click a button outside the "input-field-only" div.
For example, like I said, a wizard page with several steps, each step has it's own input-field div, and user can switch between steps by click the prev or next button.
I know it's a bit complicated, so I'd show what I've done for easy understanding. Sorry for the long post in advanced.
Wizard.zul
<div align="center" xmlns:n="native" apply="org.zkoss.bind.BindComposer" viewModel="@id('vm') @init('vm.WizardVM'))">
<div>
<div align="left">
<label value="@load(vm.state.UIState.title)"/>
</div>
<n:hr/>
<!-- input-field-only here, it would be Input1Div.zul here -->
<include id="formInput" src="@load(vm.state.UIState.uri)"/>
<n:hr/>
<n:div >
<button id="prevBtn" label="prev" disabled="@load(not vm.state.UIState.prevBtnState)" onClick="@command('prevStep')" iconSclass="z-icon-arrow-left"/>
<!-- A local command and a global-command here -->
<button id="nextBtn" label="next" disabled="@load(not vm.state.UIState.nextBtnState)" onClick="@command('nextStep') @global-command('goNext')" iconSclass="z-icon-arrow-right"/>
</n:div>
</div>
WizardVM.java
public class WizardVM {
private WizardState state;
@Wire("#formInput")
private Include input;
private Component view;
@AfterCompose
public void afterCompose(@ContextParam(ContextType.VIEW) Component view, @ExecutionArgParam(AttributeUtil.ENTITY) Object entity) {
Selectors.wireComponents(view, this, false);
this.view = view;
WizardState initState = new SetupStep1(null);
updateEntity(initState.getEntity());
this.state = initState;
}
public WizardState getState() {
return state;
}
@NotifyChange
public void setState(WizardState state) {
this.state = state;
}
private void updateEntity(Object entity) {
input.setDynamicProperty(AttributeUtil.ENTITY, entity);
}
@NotifyChange("state")
@Command
public void nextStep(MouseEvent event) {
//*******************************************
//Global-command "Input1Div.goNext" is also invoked to trigger the form validation. If validation is passed (use a EventQueue to communicate maybe?), then go to next step
//else just return
//*******************************************
//go next step
if(passed){
WizardState next = state.getNext();
if (next != null) {
updateEntity(next.getEntity());
setState(next);
}
}
}
@NotifyChange("state")
@Command
public void prevStep(MouseEvent event) {
//same as nextStep() here
if(passed){
WizardState prev = state.getPrev();
if (prev != null) {
updateEntity(prev.getEntity());
setState(prev);
}
}
}
}
WizardState.java
public interface WizardState<T> {
public WizardState getNext();
public WizardState getPrev();
public WizardUIState getUIState();
public T getEntity();
public void setEntity(T entity);
}
Input1Div.zul
<div apply="org.zkoss.bind.BindComposer" viewModel="@id('vm') @init('vm.Input1VM'))" validationMessages="@id('vmsgs')">
<div form="@id('fx') @load(vm.entity) @save(vm.entity, before='saveEntity')" >
<!-- **********************************
You can see I have to add an invisible button here to trigger validation
********************************** -->
<button id="btn" visible="flase" onClick="@command('saveEntity')"/>
<div align="left">
<div>
<label value="name"/>
</div>
<div>
<textbox id="cn" value="@bind(fx.name) @validator('beanValidator')" placeholder="input name" />
</div>
<div>
<label value="@load(vmsgs[cn])" />
</div>
</div>
</div>
</div>
Input1VM.java
public class Input1VM {
private Entity entity;
@Wire("#btn")
Button btn;
@AfterCompose
public void afterCompose(@ContextParam(ContextType.VIEW) Component view, @ExecutionArgParam(AttributeUtil.ENTITY) Object entity) {
Selectors.wireComponents(view, this, false);
this.entity = (Entity) entity;
}
public Entity getEntity() {
return entity;
}
public void setEntity(Entity entity) {
this.entity = entity;
}
@GlobalCommand
public void goNext(){
//trigger invisible button for validation
Events.sendEvent(Events.ON_CLICK, btn, null);
}
@Command("saveEntity")
public void saveEntity() {
//save entity
//give WizardVM.nextStep&prevStep a green light
}
}
Sorry for the messy code, I've tried my best to simplify them.
You can see the problem here is I can't trigger form validation when clicking the button in the outside div (Wizard.zul), so I declared a global-command in the inner div view model (Input1VM.java), which will trigger the form validation by sending a click event to an invisible button. It might work but I don't think it's the right way. That's the reason why I ask this question here.
Thank you.
Asked: 2014-09-11 04:45:55 +0800
Seen: 93 times
Last updated: Sep 11 '14
How to Call Child ViewModel Method from Parent Window? [closed]
@global-command, how to set queueName when invoke globalCommand?
how can i get data from another page
Post Global Command From Listener
Equivalent to global command on MVC ?
Why does the order of NotifyChange may alter the result of the objects?