Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JSF 2.0: How to skip JSR-303 bean validation?

How to skip JSR-303 Bean validation with JSF, when a button is clicked?

A bit lengthy question to explain a few approaches... Consider a list in a form:

<h:form id="form">
    <h:commandButton value="Add row">
        <f:ajax execute="foo" listener="#{bean.add()}" render="foo" />
    </h:commandButton>
    <h:dataTable id="foo" var="foo" value="#{bean.foos}">
        <h:column>
            Name: <h:inputText id="field" value="#{foo.name}" required="true" />
            <h:messages for="field" />
        </h:column>
        <h:column>
            <h:commandButton value="Remove">
                <f:ajax execute=":form:foo" listener="#{bean.remove(foo)}" render=":form:foo" />
            </h:commandButton>
        </h:column>
    </h:dataTable>
</h:form>

When user clicks add or remove row, the action should execute without validation. The problem is, JSF re-renders the whole list and tries to validate it. If there are draft changes that don't validate, validation errors occur and the listener method is never called (as failed validation prevents that). However, adding immediate="true" into f:ajax allows method to execute despite of validation errors. However, validation errors still occur and are shown here.

I see two options:

1) Use immediate="true" and do not show validation errors

For non-validating buttons, set immediate="true" and for h:messages do:

<h:messages rendered="#{param['SHOW_VALIDATION']}" />

Then set Save-button (that should actually try to save the form) to send that parameter:

<h:commandButton>
    <f:param name="SHOW_VALIDATION" value="true" />
</h:commandButton>

This causes validation occur, but messages are simply not shown except when SHOW_VALIDATION parameter is present.

2) Declare validation in facelets conditionally:

<h:inputText>
    <f:validateRequired disabled="#{!param['VALIDATE']}" />
</h:inputText>

And Save-button:

<h:commandButton>
    <f:param name="VALIDATE" value="true" />
</h:commandButton>

This causes fields to validate only when the VALIDATE parameter is present (=when the Save-button has been pressed).

But these seem sort of a hacks. How can I simply use JSR-303 Bean Validation but skip it when declared?

like image 529
Tuukka Mustonen Avatar asked Jan 31 '11 15:01

Tuukka Mustonen


3 Answers

Set your event handlers as immediate=true and call FacesContext.renderResponse() before exiting them.

UPDATE:

Modifications in your example form:

<h:form id="form">
    <h:commandButton value="Add row">
        <!-- Added immediate="true" to call bean.add() before validation phase -->
        <f:ajax execute="foo" listener="#{bean.add()}" render="foo" immediate="true"/>
    </h:commandButton>
    <h:dataTable id="foo" var="foo" value="#{bean.foos}">
        <h:column>
            Name: <h:inputText id="field" value="#{foo.name}" required="true" />
            <h:messages for="field" />
        </h:column>
        <h:column>
            <h:commandButton value="Remove">
                <!-- Added immediate="true" to call bean.remove() before validation phase -->
                <f:ajax execute=":form:foo" listener="#{bean.remove(foo)}" render=":form:foo" immediate="true"/>
            </h:commandButton>
        </h:column>
    </h:dataTable>
</h:form>

Modifications in your bean code:

...
public void add() {
    // Your add() code
    ...
    // Added FacesContext.renderResponse() call to skip to render response phase
    FacesContext.getCurrentInstance().renderResponse();
}
...
public void remove() {
    // Your remove() code
    ...
    // Added FacesContext.renderResponse() call to skip to render response phase
    FacesContext.getCurrentInstance().renderResponse();
}
...
like image 74
gpeche Avatar answered Nov 16 '22 03:11

gpeche


You can disable the bean validation with the tag f:validateBean that has an attribute disabled.

Example:

<h:inputText value="#{bean.name}">
   <f:validateBean disabled="#{anotherBean.flag}"/>
</h:inputText>
like image 24
victor herrera Avatar answered Nov 16 '22 02:11

victor herrera


We have just published a solution for this problem. The full detail is here: http://www.springfuse.com/2011/12/15/skip-jsf-validation-depending-on-action.html

In short, it leverages the binding attribute of the validateBean tag. Doing so enable you to intercept the validate method and decide, based on the button clicked, whether to let it go through or not.

like image 2
Nicolas Romanetti Avatar answered Nov 16 '22 04:11

Nicolas Romanetti