48

I have multiple forms, where I have mandatory fields and optional fields.

To submit such a form I require the validation on the required-attribute to be executed, which works fine. To cancel such a form I use the attribute immediate="true" on the p:commandbutton, which makes its action happen during the Apply Request Values-Phase as addressed here: How to skip validation when a specific button is clicked?

However, for large forms I want to provide the user with a Save-Button, so he can proceed later.

For just saving the current state I also want to ignore the validation of the required-attribute. However, using immediate="true" is not working, because then my save method simple saves nothing, because the JSF lifecycle never hits the "UpdateModelValues"-Phase. (Acording to http://www.javacodegeeks.com/2012/01/jsf-and-immediate-attribute-command.html )

So, how to bypass the required-check but not skip half the lifecycle?

Community
  • 1
  • 1
dognose
  • 20,360
  • 9
  • 61
  • 107
  • Given the answer, this is technically a dupe of [How to let validation depend on the pressed button?](http://stackoverflow.com/q/8370675). – BalusC Aug 11 '15 at 15:25
  • 1
    @BalusC You are right, but the other question is about an exact "technical" detail. This one, I created when I wasn't so familiar with all the JSF-Wordings (I corrected it a little bit today) - and therefore it perfectly matches the corresponding google search, a *beginner* might submit: https://www.google.de/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#q=jsf%20skip%20validation%20without%20immediate (However, both are ranked high) – dognose Aug 11 '15 at 18:23

6 Answers6

76

Each Button creates an entry inside the Param-List as long as it's member of the form. So I simple applied a check for the presence of that entry to the "required" parameter:

<h:form id="form" prependId="true">
...
<p:inputText id="someId"
    required="#{param['form:save']==null}" ... />
...
<p:commandButton id="save" value="Save" />
<p:commandButton id="submit" value="Submit" />
<p:commandButton id="cancel" value="Cancel" immediate="true" />
</h:form>

When I click "Submit" the param['form:save'] is NULL, which then turns the expression to true so the validation is executed.

When I click "Save" the param['form:save'] is NOT NULL (but empty!), which resolves to false so the validation is ignored. (Or let's say JSF thinks it is not a required field due to the expression beeing evaluated to false)

dognose
  • 20,360
  • 9
  • 61
  • 107
  • 2
    on a sidenote: `true and` is obviously NOT required here ;) – dognose Jan 15 '13 at 11:19
  • @BalusC I'm using Primefaces. Not sure, if theres something equal. (Didn't find it by now) – dognose Jan 15 '13 at 11:30
  • Great work! fantastic. After 3 hours of getting crazy I found your answer. Super cool! – 98percentmonkey Nov 27 '14 at 14:46
  • It does also work with BootsFaces components. Make sure that, `ajax=true`. It does not work with `` and ``. See http://stackoverflow.com/questions/29882417/submit-form-but-ignore-required-true-with-fajax for more information. – alexander Jul 25 '15 at 08:02
  • 1
    I don't think this is a great user experience because the * on the required fields will only show up when the user clicks on submit or cancel. Is there any other way to accomplish this so that the required * shows up all the time? – Erick Sep 30 '18 at 19:38
  • 1
    @Erick Just generate the `*` with a label, that does contain the "regular" required condition. – dognose Oct 08 '18 at 10:02
6

if you want to skip validation when click on button then easly add parameter to button where you want to skip it. Example:

<p:commandButton value="button1" action="#{bean.action()}" >
   <f:param name="skipValidator" value="true"/>
</p:commandButton>

Then in validator you can read this parameter and if it is true then skip it:

@FacesValidator("com.validators.MyValidator")
public class MyValidator implements Validator{

  public void validate(FacesContext ct, UIComponent co, Object obj) throws ValidatorException { 
    if(!continueValidation()){
      return;
    }
    // validation process
  }

protected boolean continueValidation() {
    String skipValidator= FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("skipValidator");
    if (skipValidator != null && skipValidator.equalsIgnoreCase("true")) {
      return false;
    }
    return true;
  } 
}
Juraj
  • 738
  • 2
  • 9
  • 26
  • 1
    This approach doe not skip Standart Lifecycle Update Model Values but skip FacesValidator. Useful for like 'Clean' button. Tnks man. – aspadacio Aug 21 '17 at 17:22
5

This is an excellent question and a very helpful answer. This approach saves a lot of hassle with immediate="true".

I'd like to add this info (but am not allowed to comment yet). Your code examples seem to require JSF 2.0 or above (correct me). If you are like me damned to use JSF 1.1/1.2 then consider these changes/additions:

<h:form id="form">
...
<p:inputText id="someId" required="#{!empty param['save']}" ... />
...
<p:commandButton id="save" value="Save" />
</h:form>
  • There is no attribute prependId in JSF 1.1
  • Therefore in the param[...] you must only specify the button id
  • You are using a syntax ="{true and ...}" that might be a mistake (no #)?
  • As you can see from your own editing history the "null or not null" logic is not very intuitive :) Thats why I immediately liked the !empty ... version when I stumbled upon it.
SebastianH
  • 2,172
  • 1
  • 18
  • 29
  • `{true and ...}` is missing the "#", thats correct. also the true is obsolet. It is "there", because we are generating all our forms automatically (at design time), and have the option to define, whether something is required or not. Then, if a form allows to "save", we simple appended the param check. And because you are right - the null-thing is not very intuitive, we decided to leave the "original" value (true or false) along with that check for better readability. – dognose Jan 30 '14 at 08:24
  • JSF 1.1 by default prepends form's client ID. So you should still use `form:save`. I'm not sure why dognose explicitly declared `prependId="true"` as that's the default value already. – BalusC Jan 30 '14 at 08:44
  • @BalusC I tried that, but it does not work for me. If I use `required="#{!empty param['save']}"`, I get the intended validation errors when posting a half filled form. If I use `required="#{!empty param['form:save']}"` instead, no validation happenes - and I get lots database errors ;). – SebastianH Jan 30 '14 at 11:14
  • Right, you're using plain HTML `
    ` instead of JSF ``.
    – BalusC Jan 30 '14 at 11:16
  • Actually I dont. I use ``. The example above was based on dognoses. – SebastianH Jan 30 '14 at 11:26
  • The answer is incorrect. The solution depends on the subtle difference between `null` and an empty string. the EL `empty` operator does see that subtle difference and both would evaluate `true`. This has been [discussed by @BalusC before](https://stackoverflow.com/a/14185079/744133). The solution is to explicitly check for `== null` as in the other answer. – YoYo Jul 28 '17 at 19:50
1

In my case I didn't find the clientId of the button in the params but I found this param['javax.faces.source'] = buttonClientId in the requestmap. The value will be the clientId of the clicked button.

Shady Hussein
  • 513
  • 8
  • 24
1

An alternative to what others proposed is to use a custom BeanValidator that will validate the form if say, clicked the button with id save. Any other button not implicitly defined to perform validation will not validate but just submit your data available. Find the full nice and clean example here

Given
  • 585
  • 1
  • 7
  • 14
1

I use skipValidators for such a case (assuming all validations are skipped). Code from omnifaces

<h:form>
  <h:dataTable value="#{bean.items}" var="item">
    <h:column>
        <h:inputText value="#{item.value}" required="true" />
    </h:column>
  </h:dataTable>
  <h:commandButton value="add new row" action="#{bean.add}">
    <o:skipValidators />
  </h:commandButton>
  <h:commandButton value="save all data" action="#{bean.save}" />
  <h:messages />
</h:form>
dr0ps
  • 21
  • 3