JSF skip Required-Validation without immediate=true - validation

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?

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)

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;
}
}

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.

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

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>

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.

Related

Dynamic disable validator when click checkbox

I got one number validator and one checkbox in my jsf. When a checkbox is selected then the number validator will check validation. When checkbox is unselected, the validation will skip it.
Please see my code
<h:outputText value="#{trancheResources.label_enable}:" />
<p:selectBooleanCheckbox id="enableCheckBox" itemLabel="#{trancheResources.label_yes}" value="#{trancheBean.enableCheck}" disabled="#{trancheBean.readonly}">
</p:selectBooleanCheckbox>
<p:outputLabel for="acceptableMinVal" value="#{trancheResources.label_acceptableMinVal}:" />
<pe:inputNumber id="acceptableMinVal" value="#{trancheBean.trancheValidation.podMin}" disabled="#{trancheBean.readonly}" maxValue="999"
required="#{trancheBean.requiredIfEnableCheck}" requiredMessage="#{trancheResources.label_acceptableMinVal} is required.">
<f:validateDoubleRange disabled="#{trancheBean.cValidation}" minimum="1.00" />
</pe:inputNumber>
<p:outputLabel for="acceptableMaxVal" value="#{trancheResources.label_acceptableMaxVal}:" />
<pe:inputNumber id="acceptableMaxVal" value="#{trancheBean.trancheValidation.podMax}" disabled="#{trancheBean.readonly}" maxValue="999"
required="#{trancheBean.requiredIfEnableCheck}" requiredMessage="#{trancheResources.label_acceptableMaxVal} is required.">
<p:ajax event="keyup" listener="#{trancheBean.acceptableMaxValOnkeyup}" ></p:ajax>
</pe:inputNumber>
<p:outputLabel for="exceptionMinVal" value="#{trancheResources.label_exceptionMinVal}:" />
<pe:inputNumber id="exceptionMinVal" value="#{trancheBean.trancheValidation.podExceptionMin}" disabled="#{trancheBean.readonly}" maxValue="999"/>
<p:outputLabel for="exceptionMaxVal" value="#{trancheResources.label_exceptionMaxVal}:" />
<pe:inputNumber id="exceptionMaxVal" value="#{trancheBean.trancheValidation.podExceptionMax}" disabled="#{trancheBean.readonly}" maxValue="999"/>
Please guide me to a solution. I have no idea on how to solve this.
I'll provide you with this sample answer and you can use it to apply it to yours. This approach is based on Pankaj Kathiriya's comment since that seems to be what you want to do.
In the sample code below, you have two <h:inputText> (substitute this component with yours <pe:inputNumber>). Their rendered attribute value will change every time you check/uncheck the <p:selectBooleanCheckBox>. When rendered evaluates to true, the <h:inputText> with validation will appear, the one without validation disappears (and vice versa).
The <selectBooleanCheckBox> will fire a ValueChangeEvent every time you check/uncheck it. You also need to make sure to set immediate to true so that it can be processed first (one phase before). Then call renderResponse in your listener to skip the remaining life cycles. Validation will kick in for the <h:inputText> with validation if you don't and you will see a validation error message when the switch occurs. Finally, for the <h:selectBooleanCheckBox>, you want to submit the form when the selection/deselection occurs. This can be done with javascript by setting its onchange attribute to submit() (e.g. onchange = "submit()"). Try to run the code so this could all make sense.
Again, keep in mind this is just a sample to help guide you to your solution.
public class SampleBean {
private boolean renderValidatedForm;
private String firstInput;
private String secondInput;
//Constructor ommitted
//Setters and getters ommitted
public void toggleRender(ValueChangeEvent e) {
boolean valueCheck = (Boolean) e.getNewValue();
renderValidatedForm = valueCheck;
FacesContext.getCurrentInstance().renderResponse();
}
}
The xhtml
<h:form>
<h:panelGrid>
<h:panelGroup>
<h:outputLabel for="enableCheckBox" value="Check to view form with validation"/>
<p:selectBooleanCheckbox id="enableCheckBox" value="#{sampleBean.renderValidatedForm}"
onchange="submit()"
valueChangeListener="#{sampleBean.toggleRender}"
immediate="true"/>
</h:panelGroup>
<h:panelGroup>
<h:outputLabel for="withValidation" value="Form with validation"
rendered="#{sampleBean.renderValidatedForm}"/>
<h:inputText id="withValidation" value="#{sampleBean.firstInput}"
required="true" rendered="#{sampleBean.renderValidatedForm}"/>
<h:message for="withValidation"/>
</h:panelGroup>
<h:panelGroup>
<h:outputLabel for="noValidation" value="Form without validation"
rendered="#{!sampleBean.renderValidatedForm}"/>
<h:inputText id="noValidation" value="#{sampleBean.secondInput}"
rendered="#{!sampleBean.renderValidatedForm}"/>
</h:panelGroup>
</h:panelGrid>
<h:commandButton value="Submit"/>
</h:form>

How to validate values instantly, but check for required only on full submit?

I am currently adding validation to a form. There are two things to check: The correctness of the value itself (e.g. if it is a positive integer or valid email) and whether all required fields were filled in.
However, if by some means (f:ajax or IceFaces partialSubmit attribute) I make the validation for type correctness happen at once (e.g. when the field loses focus), it will also check the required attribute in this same step. In most cases this is no problem, as the user already entered a value and is likely to correct it rather than go back to a blank field.
However, in the case where he actually wants to clear the field again, he can no longer do so without getting an error. In consequence, I only want to check the required-ness of fields on finally submitting the page.
At the moment, my only idea to separate the two validation types is by performing all required-checks in the backing beans action method, thus tying it to directly to the final submit via button.
Is there another way?
(For background: The reason why one might want to clear the field again is that requirements can change depending on other selections in the form. So one might decide to not provide this field after all and only after that correct the option that actually makes this field optional.)
Just let the required attribute evaluate true when the submit button has really been pressed.
The answer however depends on the way how your submit button executes its logic (standard, f:ajax, ICEfaces, etc). But it basically boils down to that you could check the request parameter map for a request parameter which indicates that the desired submit button has been pressed.
E.g., if it's a standard command button:
<h:form id="form">
...
<h:commandButton id="submit" value="Submit" action="#{bean.submit}" />
</h:form>
Then you could check for it by checking if the button's client ID is present in the request parameter map:
<c:set var="submitButtonPressed" value="#{not empty param['form:submit']}" />
...
<h:inputText ... required="#{submitButtonPressed}" />
<h:inputText ... required="#{submitButtonPressed}" />
<h:inputText ... required="#{submitButtonPressed}" />
Or, if it's a <f:ajax> button:
<h:form id="form">
...
<h:commandButton id="submit" value="Submit" action="#{bean.submit}">
<f:ajax execute="#form" ... />
</h:commandButton>
</h:form>
Then you could check it by checking if javax.faces.source parameter equals the button's client ID:
<c:set var="submitButtonPressed" value="#{param['javax.faces.source'] == 'form:submit'}" />
...
<h:inputText ... required="#{submitButtonPressed}" />
<h:inputText ... required="#{submitButtonPressed}" />
<h:inputText ... required="#{submitButtonPressed}" />
You could even combine both:
<c:set var="submitButtonPressed" value="#{not empty param['form:submit'] or param['javax.faces.source'] == 'form:submit'}" />
...
<h:inputText ... required="#{submitButtonPressed}" />
<h:inputText ... required="#{submitButtonPressed}" />
<h:inputText ... required="#{submitButtonPressed}" />

Invoke aciton method with input value as parameter

I have this view:
<h:form id="carlin">
<h:outputText id="carlinInput" value="#{userBean.model.varAjax}"/>
<a class="btn" data-toggle="modal" href="#myModal" >Launch Modal</a>
</h:form>
And I have a modal dialog that shows another form:
<h:form>
<h:inputText value="#{userBean.model.varAjax}"/>
<h:commandLink action="#{userBean.processPage1()}" value="Ok">
<f:ajax render=":carlin:carlinInput" />
</h:commandLink>
</h:form>
I need to set the value typed on the <h:inputText> and pass it as a parameter to my <h:commandLink action="#{userBean.processPage1()}" value="OK">`
Here is my processPage1() method:
public void processPage1(String zip) {
this.model.varAjax = zip;
}
I have tried this:
<h:commandLink action="#{userBean.processPage1(userBean.model.varAjax)}" value="OK">
But it doesn't work. If I pass a hardcoded value, it works:
<h:commandLink action="#{userBean.processPage1('teste')}" value="OK">
But I need to pass what the user typed on that inputText to my action method. How can I achieve this?
This is not the right approach. You need to specify the client IDs of the input components which you need to process/execute by the execute attribute of <f:ajax>.
<h:form>
<h:inputText id="varAjax" value="#{userBean.model.varAjax}"/>
<h:commandLink action="#{userBean.processPage1}" value="Ok">
<f:ajax execute="varAjax" render=":carlin:carlinInput" />
</h:commandLink>
</h:form>
This way JSF will set the model value with the submitted value.
public void processPage1() {
System.out.println(model.getVarAjax()); // Look, JSF has already set it.
}
An alternative is to use execute="#form" which will process the entire form and this is what you usually need in standard ajaxified buttons.
<f:ajax execute="#form" render=":carlin:carlinInput" />
Note that componenent libraries like PrimeFaces and RichFaces have already made the #form the default execute attribute, so you don't need to explicitly specify it in their command components. In standard <f:ajax> it namely defaults to #this in command components which is indeed unintuitive.

How to submit two forms in jsf with Ajax or without Ajax

I have basically two problems.
When I press the button in Form1, it is working fine, but I can't see the messages from FacesContext.
Another problem is in Form2. When I press the button only once, it goes to the server but nothing happens, no submit. But when I press it on second time, it is working fine. There is of course the same problem like in form one, that I can't see the messages from FacesContext. Could you please help and tell me what is causing that or is there another solution for having multiple forms inside one page?
<p:tabView>
<p:tab title="Form1">
<h:form id="form1">
<p:inputText id="txtInput" value="#{controller.selected.defaultLayout}" />
<h:commandButton value="Submit other form" action="#{controller.createMenu()}">
<f:ajax execute="#form" render="#form" />
</h:commandButton>
</h:form>
</p:tab>
<p:tab title="Form2">
<h:form id="form2">
<p:inputText id="txtInput2" value="#{controller.selected.defaultTheme}" />
<h:commandButton value="Submit other form" action="#{controller.createMenu2()}">
<f:ajax execute="#form" render="#form" />
</h:commandButton>
</h:form>
</p:tab>
</p:tabView>
Controller:
public String createMenu() {
Menu menu = current.getMenuMenuId();
try {
//current.getMenuMenuId().setMenuCreated(true);
//getFacade().edit(current);
JsfUtil.addSuccessMessage(ResourceBundle.getBundle("resources/Bundle").getString("MenuCreated"));-----> never visible!
return "";
} catch (Exception e) {
JsfUtil.addErrorMessage(e, ResourceBundle.getBundle("resources/Bundle").getString("PersistenceErrorOccured"));
return null;
}
}
EDIT: I took the outer -tags off and then the page is not working anymore, then I get the error message:
javax.faces.FacesException: <f:ajax> contains an unknown id ':form2' - cannot locate it in the context of the component j_idt77
at com.sun.faces.renderkit.html_basic.AjaxBehaviorRenderer.getResolvedId(AjaxBehaviorRenderer.java:285)
at com.sun.faces.renderkit.html_basic.AjaxBehaviorRenderer.appendIds(AjaxBehaviorRenderer.java:272)
at com.sun.faces.renderkit.html_basic.AjaxBehaviorRenderer.buildAjaxCommand(AjaxBehaviorRenderer.java:214)
at com.sun.faces.renderkit.html_basic.AjaxBehaviorRenderer.getScript(AjaxBehaviorRenderer.java:86)
at javax.faces.component.behavior.ClientBehaviorBase.getScript(ClientBehaviorBase.java:103)
Thank you!
Sami
Nesting forms is not valid html. This will cause unexpected behavior. Remove the outer form and see which of your issues persist.
UPDATE:
Primefaces tabview works without form as well. However if you have input elements and command buttons inside your tabs you need a form. But this is a html requirement and not PF specific. You should remove the outer form only and not the inner forms. Please update your question with your current version.

How to let validation depend on the pressed button?

I have created form and I want to show previous existing items on a table while a new one is creating. I'd like to show matching items as form is filling up. But when I try to filter the list without having the form completed, the validation messages appear and the table doesn't get updated.
Don't know if it's possible, but what I want to do something like this:
<h:form id="form">
<h:outputText value="Name: "/>
<p:inputText value="#{itemsBean.name}" id="name" required="true"/>
<br/>
<h:outputText value="Description: "/>
<p:inputText value="#{itemsBean.description}" id="description" required="true"/>
<p:commandButton value="Save" update="form" actionListener="#{itemsBean.save}"/> //validate and save
<p:commandButton value="Filter" update="form" actionListener="#{itemsBean.updateItemsList}"/> //don't validate, and update the table.
<p:dataTable id="list" value="#{itemsBean.itemsList}" var="item">
<p:column>
<h:outputText value="#{item.name}"/>
</p:column>
<p:column>
<h:outputText value="#{item.description}"/>
</p:column>
</p:dataTable>
</h:form>
I'm very new to JSF.
I understand that you want to filter based on the name input field. The <p:commandButton> sends by default an ajax request and has a process attribute wherein you can specify which components you'd like to process during the submit. In your particular case, you should then process only the name input field and the current button (so that its action will be invoked).
<p:commandButton process="#this name" ... />
The process attribute can take a space separated collection of (relative) client IDs of the components, wherein #this refers to the current component. It defaults in case of <p:commandButton> to #form (which covers all input fields of the current form and the pressed button), that's why they were all been validated in your initial attempt. In the above example, all other input fields won't be processed (and thus also not validated).
If you however intend to skip the required validation for all fields whenever the button in question is been pressed, so that you can eventually process multiple fields which doesn't necessarily need to be all filled in, then you need to make the required="true" a conditional instead which checks if the button is been pressed or not. For example, let it evaluate true only when the save button has been pressed:
<p:inputText ... required="#{not empty param[save.clientId]}" />
...
<p:inputText ... required="#{not empty param[save.clientId]}" />
...
<p:commandButton binding="#{save}" value="Save" ... />
This way it won't be validated as required="true" when a different button is pressed. The trick in the above example is that the name of the pressed button (which is essentially the client ID) is been sent as request parameter and that you could just check its presence in the request parameter map.
See also:
Understanding PrimeFaces process/update and JSF f:ajax execute/render attributes
I Have tested this with non-ajax submits:
<p:inputText ... required="#{not empty param.includeInSave1}" />
...
<p:inputText ... required="true" />
...
<p:commandButton value="Save1" ajax="false">
<f:param name="includeInSave1" value="true" />
</p:commandButton>
<p:commandButton value="Save2" ajax="false" />
The first input is required validated only on Save1 button submit.
Additionally to the BalusC answer (very useful and complete) I want to add that when you use a <h:commandButton /> it will validate (required, custom validations) all the fields in the <h:form /> where the command button is located, therefore when you need to use more than one command button you could consider that it is a good practice to use different <h:form /> to different responsibilities to avoid unexpected behavior in submit actions of the command buttons.
It is well explained in a BalusC answer: Multiple h:form in a JSF Page
If your form has validations and you do not update the <h:form /> or you do not show messages, you could get a headache thinking that the <h:commandButton /> is not firing your action, but likely is a validation problem that has not been shown.
Change your filter commandbutton like this to ignore validation:
<p:commandButton value="Filter" update="list" actionListener="#{itemsBean.updateItemsList}" process="#this"/>
EDIT:
The related post on SO, I think this will solve your issue too
JSF 2.0: How to skip JSR-303 bean validation?

Resources