Zak
Zak

Reputation: 327

How to skip PreRenderView event when validation has failed?

I have a use case in which I want to validate a bunch of viewParams and if I find validation errors, skip the preRenderView event and just display the error messages. Is this possible?

e.g.

<f:metadata>
            <f:viewParam id="param1" name="p1" value="#{someBean.param1}" />
            <f:viewParam id="param2" name="p2" value="#{someBean.param2}" />
            <f:event type="javax.faces.event.PostValidateEvent" listener="#{someBean.validateParams}" />
            <f:event type="javax.faces.event.PreRenderViewEvent" listener="#{someBean.viewAction}" />
        </f:metadata>

The method validateParams() is used to do multi-field validation and would probably go something like this:

    public void validateParams(ComponentSystemEvent event) {
       UIComponent source = event.getComponent();

       Integer value1 = (Integer) ((UIInput) source.findComponent("param1")).getLocalValue();
       Integer value2 = (Integer) ((UIInput) source.findComponent("param2")).getLocalValue();

       boolean valid1 = validOneField(value1);
       boolean valid2 = validOneField(value2);
       boolean valid12 = validBothFields(valid1, valid2);

       if(!valid1);//add facesMessage
       if(!valid2);//add facesMessage
       if(!valid12);//add facesMessage

       if (!valid1 || !valid2 || !valid12)
          FacesContext.getCurrentInstance().renderResponse();
    }

My understanding is that regardless of the forced render response, viewAction() would still be called. I could easily modify viewAction() to take the validation into account but I want to skip it completely due to other reasons (some messy code in that method that I rather not touch, etc.). Is there a way I could completely bypass viewAction() and display the validation error messages?

Edit: Using BalusC suggestion of FacesContext.getCurrentInstance().ValidationFailed()

i've revised validateParams() to:

    public void validateParams(ComponentSystemEvent event) {
       UIComponent source = event.getComponent();

       Integer value1 = (Integer) ((UIInput) source.findComponent("param1")).getLocalValue();
       Integer value2 = (Integer) ((UIInput) source.findComponent("param2")).getLocalValue();

       boolean valid1 = validOneField(value1);
       boolean valid2 = validOneField(value2);
       boolean valid12 = validBothFields(valid1, valid2);

       if(!valid1);//add facesMessage
       if(!valid2);//add facesMessage
       if(!valid12);//add facesMessage

       if (!valid1 || !valid2 || !valid12)
          FacesContext.getCurrentInstance().ValidationFailed();
          FacesContext.getCurrentInstance().renderResponse();
    }

and the modified viewAction() as follows:

public void viewAction(ComponentSystemEvent cse) {
    if(!FacesContext.getCurrentInstance().isValidationFailed()) {
        // viewAction() code
    }
}

This seems to be working for me now. Hopefully, the view actions in JSF 2.2 won't require me to check whether validation failed since I believe they won't be called at all (the FacesContext.renderResponce() will skip invoke application step, which is where view actions are called).

Upvotes: 1

Views: 1494

Answers (1)

BalusC
BalusC

Reputation: 1109735

You can check FacesContext#isValidationFailed() for that.

public void viewAction() {
    if (!FacesContext.getCurrentInstance().isValidationFailed()) {
        // ...
    }
}

As you're manually performing validation instead of using JSF standard Validators for some unclear reason (are you well aware that you can specify a validator, <f:validator> and <f:validateXxx> on <f:viewParam>?), you'd need to manually invoke FacesContext#validationFailed() on validation failure.

Upvotes: 1

Related Questions