1

Form validation before global command

asked 2014-09-11 04:45:55 +0800

M4tt gravatar image M4tt
39 5

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.

delete flag offensive retag edit

2 Answers

Sort by ยป oldest newest most voted
1

answered 2014-09-11 06:06:35 +0800

chillworld gravatar image chillworld flag of Belgium
5367 4 9
https://github.com/chillw...

updated 2014-09-11 12:15:41 +0800

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 :

Zul:

<div form="@id('fx') @load(vm.entity) @save(vm.entity, before='someCommand')">
    <textbox  value="@bind(fx.field) @validator('beanValidator')" />
</div>

Java:

@Command
public void someCommand () {
    BindUtils.postGlobalCommand(null,null,"myGlobalCommandHere",null);
}

Edit:

Oke, I played a little around local.
Mine suggestion : Remove all the different viewmodels and make ons bigger viewmodel.
Look at this example :

index.zul:

<?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>

include1.zul:

<?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>

include2.zul:

<?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>

TestVM.java:

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.

link publish delete flag offensive edit

Comments

Hi chill, thank you so much, I think I just made it more complicated than how it was. :)

M4tt ( 2014-09-12 03:54:06 +0800 )edit

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
0

answered 2014-09-11 08:14:47 +0800

M4tt gravatar image M4tt
39 5

updated 2014-09-11 08:33:30 +0800

Hi 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.

link publish delete flag offensive edit
Your answer
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
2 followers

RSS

Stats

Asked: 2014-09-11 04:45:55 +0800

Seen: 93 times

Last updated: Sep 11 '14

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