JSF : How to refresh required field in ajax request - ajax

Ok, here you are the core problem.
The page. I have two required "input text".
A command button that changes the bean value and reRenderes the "job" object.
<a4j:form id="pervForm">
SURNAME:<h:inputText id="surname" label="Surname" value="#{prevManager.surname}" required="true" />
<br/>
JOB:<h:inputText value="#{prevManager.job}" id="job" maxlength="10" size="10" label="#{msg.common_label_job}" required="true" />
<br/>
<a4j:commandButton value="Set job to Programmer" ajaxSingle="true" reRender="job">
<a4j:actionparam name="jVal" value="Programmer" assignTo="#{prevManager.job}"/>
</a4j:commandButton>
<h:commandButton id="save" value="save" action="save" class="HATSBUTTON"/>
</a4j:form>
Here the simple manager:
public class PrevManager
{
private String surname;
private String job;
public String getSurname()
{
return surname;
}
public void setSurname(String surname)
{
this.surname = surname;
}
public String getJob()
{
return job;
}
public void setJob(String job)
{
this.job = job;
}
public String save()
{
//do something
}
}
Let's do this:
Write something on the Job input text (such as "teacher").
Leave empty the surname.
Save.
Validation error appears (surname is mandatory).
Press "Set job to Programmer": nothing happens.
Checking the bean value, I discovered that it is correctly updated, indeed the component on the page is not updated!
Well, according to the JBoss Docs I found:
Ajax region is a key ajax component.
It limits the part of the component
tree to be processed on the server
side when ajax request comes.
Processing means invocation during
Decode, Validation and Model Update
phase. Most common reasons to use a
region are:
-avoiding the aborting of the JSF lifecycle processing during the
validation of other form input
unnecessary for given ajax request;
-defining the different strategies when events will be delivered
(immediate="true/false")
-showing an individual indicator of an ajax status
-increasing the performance of the rendering processing
(selfRendered="true/false",
renderRegionOnly="true/false")
The following two examples show the
situation when a validation error does
not allow to process an ajax input.
Type the name. The outputText
component should reappear after you.
However, in the first case, this
activity will be aborted because of
the other field with required="true".
You will see only the error message
while the "Job" field is empty.
Here you are the example:
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:a4j="http://richfaces.org/a4j"
xmlns:rich="http://richfaces.org/rich">
<style>
.outergridvalidationcolumn {
padding: 0px 30px 10px 0px;
}
</style>
<a4j:outputPanel ajaxRendered="true">
<h:messages style="color:red" />
</a4j:outputPanel>
<h:panelGrid columns="2" columnClasses="outergridvalidationcolumn">
<h:form id="form1">
<h:panelGrid columns="2">
<h:outputText value="Name" />
<h:inputText value="#{userBean.name}">
<a4j:support event="onkeyup" reRender="outname" />
</h:inputText>
<h:outputText value="Job" />
<h:inputText required="true" id="job2" value="#{userBean.job}" />
</h:panelGrid>
</h:form>
<h:form id="form2">
<h:panelGrid columns="2">
<h:outputText value="Name" />
<a4j:region>
<h:inputText value="#{userBean.name}">
<a4j:support event="onkeyup" reRender="outname" />
</h:inputText>
</a4j:region>
<h:outputText value="Job" />
<h:inputText required="true" id="job1" value="#{userBean.job}" />
</h:panelGrid>
</h:form>
</h:panelGrid>
<h:outputText id="outname" style="font-weight:bold" value="Typed Name: #{userBean.name}" />
<br />
</ui:composition>
Form1: the behaviour is incorrect. I need to fill the job and then the name.
Form2: the behaviour is correct. I do not need to fill the job to see the correct value.
Unfortunately using Ajax region does not help (indeed I used it in a bad way ...) because my fields are both REQUIRED. That's the main different.
Any idea?
Many thanks.

This problem is also identified in JSF 2 and explained in detail in this related answer: How can I populate a text field using PrimeFaces AJAX after validation errors occur?
Summarized, the answer is that you need to clear the state of the EditableValueHolder component when it's about to be ajax-rendered, but which isn't included in the ajax-execute, by calling the methods setValue(null), setSubmittedValue(null), setLocalValueSet(false), setValid(true). Note: in JSF 2 you would have used the convenience method resetValue() instead.
Given that your "job" input field has the client ID prevForm:job, here's how you could clear it inside the action listener method associated with the "Set job to programmer" button:
UIInput input = (UIInput) context.getViewRoot().findComponent("prevForm:job");
input.setValue(null);
input.setSubmittedValue(null);
input.setLocalValueSet(false);
input.setValid(true);

Using a4j:actionparam will set the value, but will not help you bypass validation in this case. Validation happens on the component (not the bean property). So, when you submit, the component value is still empty. Hope this helps.

When you click "Set job to Programmer" nothing happens because you are not reRendering your message component. If you do, you'll be able to see the validation message.
You need to reRender the message because its a <a4j:commandButton/>, not a simple <h:commandButton/>
Try to use the prop. immediate in "Set job to Programmer" button and check if it will update the field.
<a4j:commandButton value="Set job to Programmer" ajaxSingle="true" reRender="job" immediate="true">
<a4j:actionparam name="jVal" value="Programmer" assignTo="#{prevManager.job}"/>
</a4j:commandButton>
*I dont think "ajaxSingle" necessary here..
Maybe you can get a new problem.. using immediate, the bean value will be not updated (MAYBE!). If it happens, make a bean method which sets manually the bean value.
Otherwise, if the bean value was updated and the field still empty, try to put the "job" field into a <a4j:outputPanel/> and reRender the outputPanel.
<a4j:outputPanel id="myPanel">
<h:inputText value="#{prevManager.job}" id="job" maxlength="10" size="10" label="#{msg.common_label_job}" required="true" />
</a4j:outputPanel/>
<a4j:commandButton value="Set job to Programmer" reRender="myPanel" immediate="true">
<a4j:actionparam name="jVal" value="Programmer" assignTo="#{prevManager.job}"/>
</a4j:commandButton>
More info about <a4j:outputPanel/> here.

Related

How to AJAX update components in single tab of p:accordionPanel from outside?

I have a p:accordionPanel which represents a list of items and in each tab there is a form. Upon submitting any of the repeating forms, it is possible that extra data in needed, which is when a p:dialog is popped up prompting the user to enter some more data. That dialog is defined outside the accordion panel because, unlike the items from the accordion, only one of them can be showing at a time so there is no need to augment the HTML served by repeating it in each tab of the accordion.
The definition of the accordion looks as follows (simplified but with all the relevant descriptors):
<p:accordionPanel id="myAccordion" value="#{managedBean.getAccordionList}" var="item" multiple="false" dynamic="true" cache="true">
<p:ajax event="tabChange" listener="#{managedBean.processTabChange}"/>
<p:tab title="#{item.tabTitle}" id="itemTab">
<h:form id="itemForm">
<h:outputLabel for="itemName" value="Item Name:"/>
<p:inputText id="itemName" title="Item Name:"
maxlength="16" value="#{appeal.itemName}">
</p:inputText>
Consequently, the HTML rendered for itemName is myAccordion:0:itemForm:itemName in the first instance, myAccordion:1:itemForm:itemName in the second, etc.
The dialog is defined as follows:
<p:dialog id="commentDialogID" header="Enter comment" widgetVar="commentDialog" modal="true" resizable="true" height="auto">
<h:form id="commentForm">
<h:outputLabel for="comment" value="Comment:"/>
<p:inputTextarea id="comment" title="Comment"
rows="6" cols="33"
value="#{managedBean.activeItem.comment}"
required="true">
<f:ajax render="comment"/>
</p:inputTextarea>
<h:commandButton value="Submit" action="#{managedBean.proceed}" onclick="PF('commentDialog').hide();">
<f:ajax render="*** ??? ***"/>
</h:commandButton>
</h:form>
</p:dialog>
What I have repeatedly been failing at are attempts to f:ajax update only a single tab in the accordion panel, the active one from which the dialog was popped up. I tried using
:myAccordion:#{managedBean.activeItem.displayIndex}:itemForm:itemName
:myAccordion:#{managedBean.activeItem.displayIndex}:itemForm
:myAccordion:#{managedBean.activeItem.displayIndex}:itemTab
in place of *** ??? *** but none of them would compile:
javax.faces.FacesException: <f:ajax> contains an unknown id ':myAccordion:0:itemForm' - cannot locate it in the context of the component j_idt20
If I skip the index token (e.g. :myAccordion:itemForm:itemName) it does compile but it does functionally nothing. The Item entity class has a getDisplayIndex which does accurately return the index of the active tab.
My problem is quite similar to that which is described in this question, which doesn't really have a good answer. Could it be a limitation of PrimeFaces?
I don't know what version of Primefaces you are using, but this seems to be a bug in Primefaces 5.1.1 where i could recreate this issue. By upgrading to Primefaces 5.2, the ajax EL could suddenly find the referenced id. I can post a MCVE if needed.
Edit: The MCVE:
XHTML:
<h:form id="itemForm">
<p:accordionPanel id="myAccordion" binding="#{accordionView}" value="#{playgroundController.users}" dynamic="true" activeIndex="#{playgroundView.activeIndex}" var="user" multiple="false">
<p:ajax event="tabChange" update="commentDialogID"/>
<p:tab title="#{user.name}">
<h:outputLabel for="itemName" value="Item Name:" />
<p:inputText id="itemName" title="Item Name:" maxlength="16"
value="#{user.amount}">
</p:inputText>
<p:commandButton value="showDialog" onclick="PF('commentDialog').show();"></p:commandButton>
</p:tab>
</p:accordionPanel>
</h:form>
<p:dialog id="commentDialogID" header="Enter comment" widgetVar="commentDialog" modal="true" resizable="true" height="auto">
<h:form id="commentForm">
<h:outputLabel for="comment" value="Comment:"/>
<p:inputTextarea id="comment" title="Comment"
rows="6" cols="33"
value="#{playgroundView.activeIndex}"
required="true">
<f:ajax render="comment"/>
</p:inputTextarea>
<p:commandButton value="Submit" onclick="PF('commentDialog').hide();" update=":itemForm:myAccordion:#{playgroundView.activeIndex}:itemName" ></p:commandButton>
</h:form>
</p:dialog>
PlaygroundView Bean:
Note that in this example the activeIndex has to have an initial value, otherwise this EL:
update=":itemForm:myAccordion:#{playgroundView.activeIndex}:itemName"
will resolve wrongly and will throw an error that it cannot find the id of the referenced component. This of course has the drawback that the first tab will be open when the page loads, but that's another issue
private String activeIndex = "0";
public String getActiveIndex() {
return activeIndex;
}
public void setActiveIndex(String activeIndex) {
this.activeIndex = activeIndex;
}
PlaygroundController Bean:
private List<User> users;
#Override
public void initializeView() {
createUsers();
}
public void createUsers() {
User user1 = new User();
User user2 = new User();
User user3 = new User();
user1.setName("User123");
user1.setAmount(1);
user2.setName("User456");
user2.setAmount(2);
user3.setName("User12312345111111111111111111111111111");
user3.setAmount(3);
List<User> userList = new ArrayList<User>();
userList.add(user1);
userList.add(user2);
userList.add(user3);
users = userList;
}
User:
public class User implements Serializable {
String name;
int amount = 0;
}
You should update the commandButton on the tabChange event.
<p:ajax event="tabChange" listener="#{managedBean.processTabChange}" update=":commentForm:commandButtonId"/>
The render attribute <f:ajax> inside the <h:commandButton>is evaluated during the render phase and not sooner afaik. So if you do not update it, it will always point to '0'. Check the source in your browser developer tool and check your ajax requests (things you should always do for debugging). You will see the full clientId with the ':0:' and you will not see it changing on the ajax requests.

Ajax validation, different Messages

Hi guys I have a real problem with my validation in JSF. I want to validate a Mail-Address if it's already used and the correct mail format. Here are the picture how it should look.
https://www.dropbox.com/s/bs9nshmuurauc2e/Unbenannt.JPG
I hope can understand the problem. I don't now how I can implement it.
Can I set different messages for different events?
I use primefaces 3.5 and jsf 2.1
<p:row>
<p:column style="width:400px">
<h:outputLabel for="email" styleClass="outputRight" value="#{msg['regi_mail']}" />
</p:column>
<p:column style="width:350px">
<p:inputText style="width:350px" requiredMessage="#{msg['regi_mail_valid']}" validatorMessage="#{msg['regi_mail_valid']}" id="email" value="#{regiBean.user.EMAIL}" required="true">
<f:validateRegex pattern="^[_A-Za-z0-9-\+]+(\.[_A-Za-z0-9-]+)*#[A-Za-z0-9-]+(\.[A-Za-z0-9]+)*(\.[A-Za-z]{2,})$" />
<f:ajax event="blur" render="format user" />
</p:inputText>
</p:column>
<p:column style="width:410px">
<h:panelGroup id="mail" class="fa fa-question-circle fa-2x" />
<p:overlayPanel for="mail" showEvent="mouseover" hideEvent="mouseout" hideEffect="fade">
<p:panel>
TEXTTEXTTEXT
</p:panel>
</p:overlayPanel>
<p:message id="format" for="email" />
</p:column>
</p:row>
<p:row>
<p:column style="width:400px">
<h:outputLabel styleClass="outputRight" value="Username" />
</p:column>
<p:column style="width:350px">
<h:outputLabel id="user" style="color: green;" value="#{regiBean.user.EMAIL}" />
</p:column>
<p:column>
<h:panelGroup id="us" class="fa fa-minus-square fa-2x" />
<h:panelGroup/>
</p:column>
</p:row>
I've done something like this but front end only different.
XHTML File
The Bean Code
I hope you will get some help from this.
This may be a little late, I see the question was asked in Feb already. However, seems this would be a case where you should rather supply a custom validator. Here is my suggestion:
Remove the validatorMessage attribute from you id="email" element. Also remove the f:validateRegex validator in that input element.
Create a custom validator. It should:
Have a #ManagedBean (or similar) annotation (so that the EL in your JSF page can reference it)
implement javax.faces.validator.Validator
override the validate() method. In it you do your validations, e.g. check your regexp as well as query the database for existing addresses via e.g. JPA (or an EJB business method). If validation fails, you throw a javax.faces.validator.ValidatorException, that is constructed with a javax.faces.application.FacesMessage instance containing the relevant error message (there are various constructors, find an applicable one).
If you do not want to code something in this validator, but "pass it in" from the JSF page, you could do that via attribute passing. Useful if you e.g. would want to pass in your (i18z'ed) error message, values of other fields on the form, etc. etc. The only things available inside the validate() method by default is the FacesContext, the UIComponent, and the value that is validated. (See example below.)
Modify your JSF similar to the example below.
Example - Validator class:
#ManagedBean public class MyEmailValidator implements Validator {
#EJB UserEJBLocal userEJB; // supposing you want to use a method in there to get list of e-mail addresses
private static final String REGEXP = "^[_A-Za-z0-9-\+]+(\.[_A-Za-z0-9-]+)*#[A-Za-z0-9-]+(\.[A-Za-z0-9]+)*(\.[A-Za-z]{2,})$";
#Override public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
if (! Pattern.matches(REGEXP, value.toString())) {
throw new ValidatorException(new FacesMessage(component.getAttributes().get("formatMsg")));
}
List existingAddresses = userEJB.getAllAddresses(); // or whatever method your are using to obtain current addresses, e.g. JPA.
if (existingAddresses.contains(value.toString()) {
throw new ValidatorException(new FacesMessage(
FacesMessage.SEVERITY_ERROR,
"The address already exists." // could also be passed in as attribute, etc.
));
}
}
}
Example - JSF snippet:
<p:inputText id="email" value="#{regiBean.user.EMAIL}"
requiredMessage="#{msg['regi_mail_valid']}" required="true"
>
<f:validator binding="${myEmailValidator}" />
<f:attribute name="formatMsg" value="#{msg['regi_mail_valid']}" />
: <!-- other attributes, if needed -->
<f:ajax event="blur" render="email-msg user" />
</p:inputText>
:
<p:message id="email-msg" for="email" />
Well, the above example may not be complete, but might point you in the right direction.
OK, so maybe you want to check the current row's e-mail against the e-mails in the other rows? You are a bit out of luck... The only way I can think of is to somehow gather them all into a list, which you can pass via another attribute to the validator. Not very easy with a dynamic table... You might want to rethink your process.

Passing <p:inputText> values to Bean using ajax

I am having the h:inputText which having a text and by ajax request how can i send it's values to bean class and the values will be validated in further action begin at bean class ..
view page code is
<h:form>
<p:panel id="panel" header="Login Panel" style="margin:0 auto;width:350px;margin-top:15%;">
<p:panelGrid columns="3" id="pgrid1" styleClass="theme" >
<p:outputLabel value="User Name:" />
<p:inputText id="name" value="#{loginBean.name}" required="true" requiredMessage="Name is required">
<f:ajax event="blur" render="label" listener="loginBean.validateName" ></f:ajax>
<!--Here the ajax event working properly but how can i get the inputText value when ajax event is invoked-->
</p:inputText>
<p:message for="name" style="color: red;" />
</p:panelGrid>
<p:commandButton type="Submit" value="Submit" action="#{loginBean.validate}" update="pgrid1" />
</p:panel>
My Bean class Code is :
public void validateName(AjaxBehaviorEvent e)
{
//Here i need inputText value..how can i handle this task..!!
}
JSF has already set the #{loginBean.name} value at that moment. Just access it directly.
public void validateName(AjaxBehaviorEvent e)
{
System.out.println(name); // Look, JSF has already set it.
// ...
}
You've by the way an EL syntax error in <f:ajax listener> which causes the listener method never to be invoked, but I'll bet it to be just carelessness during preparing the question as you mentioned that it is "working properly". In the future questions, please edit code in the real development environment and copypaste real working code instead of blindly editing the code in the question editor.

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>

JSF skip Required-Validation without immediate=true

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.

Resources