Dynamic disable validator when click checkbox - validation

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>

Related

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.

JSF Ajax reset previously rendered input component values?

I have a small (but vital) problem with JSF and ajax. The form is here:
<h:form>
<h:panelGrid id="pg1" columns="2">
<h:outputText value="Type: "/>
<h:selectOneMenu id="selectOne" value="#{personBean.type}">
<f:selectItems value="#{listBean.personTypes}"/>
<f:ajax event="valueChange" render="pg2"/>
</h:selectOneMenu>
</h:panelGrid>
<h:panelGrid id="pg2" columns="2">
<h:outputText value="Really bad?" rendered="#{personBean.type=='BAD'}"/>
<h:selectBooleanCheckbox id="checkbox" value="#{personBean.reallyBad}" rendered="#{personBean.type=='BAD'}">
<f:ajax event="click"/>
</h:selectBooleanCheckbox>
</h:panelGrid>
<h:commandButton value="Ajax Submit" action="#{personBean.printValues}">
<f:ajax execute="#form"/>
</h:commandButton>
</h:form>
The PersonBean is a simple bean with an enum PersonType that has two values: NICE, BAD and a Boolean called reallyBad. The ListBean returns the enum values in a list to populate the selectOneMenu.
Basically when I select BAD the panel for the boolean checkbox is rendered where I can tick it to say a person is reallyBad. I can then submit the form if I wish. The problem is when I tick the checkbox and then select NICE again, the checkbox is still ticked even though it is not rendered. So when I submit my form the person can be NICE and reallyBad, which doesn't make sense.
Rather than having to select BAD again to uncheck the box, is their a way that I can reset the checkbox and its input value to false when NICE is selected? I'm a bit of a noob to ajax with JSF! Thanks.
ps. I am printing the values of the two inputs on submit with the commandButtons action to verify the results...
You need to manually clear the checkbox when you change the menu.
<f:ajax listener="#{personBean.setReallyBad(false)}" render="pg2" />
By the way, the both <f:ajax event> values as you've in your code are the default values already. Just omit them.

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.

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?

JSF : How to refresh required field in ajax request

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.

Resources