I have a ajax event blur that validate if a email already exist on database and it works.
<h:outputText value="Email:" />
<p:inputText id="email" value="#{pessoaBean.pessoa.email}"
required="true" requiredMessage="Informar o email."
validatorMessage="Formato de email inválido" >
<p:ajax event="blur" listener="#{pessoaBean.verificaEmail}"
update="mensagens" />
<f:validateRegex
pattern="^[_A-Za-z0-9-\+]+(\.[_A-Za-z0-9-]+)*#[A-Za-z0-9-]+(\.[A-Za-z0-9]+)*(\.[A-Za-z]{2,})$" />
</p:inputText>
Bean Method:
public void verificaEmail() {
if (new PessoaDao().verificaEmail(pessoa) == true) {
FacesContext.getCurrentInstance().addMessage("formCadastrar:email",
new FacesMessage(FacesMessage.SEVERITY_ERROR, "Error",
"email already exist"));
}
}
When I submit my form with commandbutton it passes through my ajax validaton and submit my form even it have my error message displayed on screen.
My button code:
<p:commandButton value="Cadastrar"
actionListener="#{pessoaBean.cadastrar}"
update=":formPrincipal:tabelaPessoas,formCadastrar"
oncomplete="if (!args.validationFailed){PF('dialogCadastrar').hide();} "
/>
What happened here?
Don't do the validation work in a listener method, as JSF has proper validators for that. Acording to the official docs:
Individual Validators should examine the value and component that they are passed, and throw a ValidatorException containing a FacesMessage, documenting any failures to conform to the required rules.
So let's implement the one you need:
#FacesValidator("emailValidator")
public class EmailValidator implements Validator{
#Override
public void validate(FacesContext context, UIComponent component,
Object value) throws ValidatorException {
if (new PessoaDao().verificaEmail(value.toString()) == true) {
throw new ValidatorException(new FacesMessage(FacesMessage.SEVERITY_ERROR, "Error",
"email already exist"));
}
}
}
}
Then, you only need to attach the validator to the input you're interested in:
<p:inputText id="email" value="#{pessoaBean.pessoa.email}"
required="true" requiredMessage="Informar o email."
validatorMessage="Formato de email inválido" validator="emailValidator" />
This could of course be improved, you could add the regex validation into the code itself and also implement your own e-mail input composite component to be reused, with the validator already included.
See also:
Custom validation in JSF 2
JSF Composite Component tutorial
Related
usage:JSF 2.3.2 Mojarra
while adding ajax to my jsf i met such a case:
cannnot refresh: h:message id="phoneNumber-msg" during fulfill the form
<h:messages id="validation-messages" styleClass="validation-messages"/>
<h:form>
<h:outputLabel for="phoneNumber">Phone number</h:outputLabel>
<h:inputText id="phoneNumber" value="#{bean.phoneNumber}">
<f:validator validatorId="validators.PhoneNumber"/>
<f:ajax event="blur" execute="#this" render="phoneNumber-msg"/>
</h:inputText>
<h:message id="phoneNumber-msg" for="phoneNumber"/>
[...]
<h:commandButton value="Submit" action="#{userDetails.submit}"/>
</h:form>
and validators.PhoneNumber is a #FacesValidator:
#FacesValidator("validators.PhoneNumber")
public class PhoneNumberValidator implements javax.faces.validator.Validator {
#Override
public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException { ... }
}
ADDITIONALLY
The validation work properly(message from validators.PhoneNumber occured in both: id="validation-messages" and id="phoneNumber-msg") when refreshed by the "Submit" button that ends the form:
<h:commandButton value="Submit" action="#{userDetails.submit}"/>
</h:form>
If you think about different validation way -> at EmailAddress input I used my own class anotation (EmailAddressValidator implements ConstraintValidator) which validates by #ValidEmailAddress on the bean used in the form - it renders the email validation message properly, but here I would like to validate PhoneNumber in a different way.
Is it possible to render id="phoneNumber-msg" (that means proceeding validators.PhoneNumber during fulfill the form?
I'd like to have different validation messages for every validator for different input fields.
Is it possible in JSF to have a different validation messages for a single validator (e.g. <f:validateLongRange>) for every input field?
There are several ways:
The easiest, just set the validatorMessage attribute of the UIInput component.
<h:inputText ... validatorMessage="Please enter a number between 0 and 42">
<f:validateLongRange minimum="0" maximum="42" />
</h:inputText>
However, this is also used when you use other validators. It will override all messages of other validators attached to the input field, including required="true" and Bean Validation such as #NotNull. Not sure if that would form a problem then. If so, then head to following ways.
Create a custom validator which extends the validator of interest, such as LongRangeValidator in your specific case, wherein you catch the ValidatorException of the super.validate() call and then rethrow it with the desired custom message. E.g.
<h:inputText ...>
<f:validator validatorId="yourLongRangeValidator" />
<f:attribute name="longRangeValidatorMessage" value="Please enter a number between 0 and 42" />
</h:inputText>
with
#FacesValidator("yourLongRangeValidator")
public class YourLongRangeValidator extends LongRangeValidator {
public void validate(FacesContext context, UIComponent component, Object convertedValue) throws ValidatorException {
setMinimum(0); // If necessary, obtain as custom f:attribute as well.
setMaximum(42); // If necessary, obtain as custom f:attribute as well.
try {
super.validate(context, component, convertedValue);
} catch (ValidatorException e) {
String message = (String) component.getAttributes().get("longRangeValidatorMessage");
throw new ValidatorException(new FacesMessage(message));
}
}
}
Use OmniFaces <o:validator> which allows setting a different validator message on a per-validator basis:
<h:inputText ...>
<o:validator validatorId="jakarta.faces.Required" message="Please fill out this field" />
<o:validator validatorId="jakarta.faces.LongRange" minimum="0" maximum="42" message="Please enter a number between 0 and 42" />
</h:inputText>
See also:
Change the default message "Validation Error: Value is required" to just "Value is required"
How to customize JSF conversion message 'must be a number consisting of one or more digits'?
Internationalization in JSF, when to use message-bundle and resource-bundle?
JSF converter resource bundle messages
I am trying to write a simple create user page. I want the user to be able to type a desired username and if the username is already taken, then an output text shows up and says "Username already in use".
Here is my xhtml page
<tr>
<td>Username: </td>
<td>
<p:inputText id="username" value="#{createUserManagedBean.username}" required="true" requiredMessage="Username is required.">
<p:ajax event="keyup" update="uniqueUsernameMessage"/>
</p:inputText>
</td>
<td>
<h:outputText id="uniqueUsernameMessage" value="Username already in use" rendered="#{!createUserManagedBean.checkUniqueUsername()}" />
</td>
</tr>
Here is my managed bean
public boolean checkUniqueUsername()
{
if(!StringUtils.isBlank(getUsername()))
{
UserDTO userDTO = new UserDTO();
userDTO.setUsername(username);
boolean result = getUserService().validateUniqueUsername(userDTO);
return result;
}
else
return false;
}
My issue is that the message is not updating for each keyup event. The service was being called, but the element was not changing whether or not it would display or not depending on the method result.
Using the rendered attribute is absolutely not the right way to validate an input component. You should be using a real Validator implementation. Therein you can in case of invalidation just throw a ValidatorException with a FacesMessage. JSF will then take care that the FacesMessage ends up in the right <h:message> associated with the input component.
All in all, this should do:
<p:inputText id="username" value="#{createUserManagedBean.username}" ...>
<f:validator binding="#{uniqueUsernameValidator}" />
<p:ajax event="keyup" update="usernameMessage" />
</p:inputText>
<h:message id="usernameMessage" for="username" />
With
#ManagedBean
#RequestScoped
public class UniqueUsernameValidator implements Validator {
#EJB
private UserService userService;
#Override
public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
if (value == null || value.isEmpty()) {
return; // Let required="true" handle.
}
String username = (String) value;
if (userService.findByUsername(username) != null) {
throw new ValidatorException(new FacesMessage(
FacesMessage.SEVERITY_ERROR, "Username already in use. Please choose another", null));
}
}
}
See also:
How to perform validation in JSF, how to create a custom validator in JSF
Please note that the validator is a #ManagedBean instead of a #FacesValidator because the #EJB could otherwise not be injected. But if you're not using EJBs and are manually creating service classes and fiddling with transactions yourself, then you could probably just keep it a real #FacesValidator:
#FacesValidator("uniqueUsernameValidator")
public class UniqueUsernameValidator implements Validator {
Which is then instead to be referenced as follows:
<f:validator validatorId="uniqueUsernameValidator" />
See also:
How to inject in #FacesValidator with #EJB, #PersistenceContext, #Inject, #Autowired
Validator Class:
#FacesValidator("br.gov.valec.sicpd.util.CpfValidator")
public class CpfValidator implements Validator {
#Override
public void validate(FacesContext context, UIComponent component, Object value)
throws ValidatorException {
if (validateCpf(value.toString())) {
FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_ERROR,"Invalid Input","Invalid Input");
((UIInput) component).setValid(false); // this line doesnt work
throw new ValidatorException(msg);
}
}
JSF snippet:
<p:inputText label="CPF" id="inputCpf"
value="#{mainBean.owner.cpf}">
<f:validator validatorId="br.gov.valec.sicpd.util.CpfValidator" />
<p:ajax event="change" update="inputNameOwner"
listener="#{mainBean.searchOwner}" />
</p:inputText>
When the form is submitted via command button primefaces highlights it automatically. How can I achieve that when ajax is fired and validation fails?
The UIInput#setValid(false) is working fine. You just forgot to tell ajax to update the input component itself. Add inputCpf or #this to <p:ajax update>.
<p:ajax ... update="#this inputNameOwner" />
That explicit UIInput#setValid(false) call in validator is by the way unnecessary. Get rid of it. JSF already does it all by itself once it catches the ValidatorException thrown by your validator.
I've started learning JSF2.0, and have come across a problem. Any advice on how to proceed would be welcome.
I have renamed form elements and classes for simplicity sake.
I have a form, for example:
<h:form id="frmSearch">
<h:inputText id="dataPoint1" value="#{bean.dataPoint1}"/>
<div id="dataPoint1Error" class="msgError">Value not found in database.</div>
<h:inputText id="dataPoint2" value="#{bean.dataPoint2}"/>
<div id="dataPoint2Error" class="msgError">Value not found in database.</div>
<h:commandButton action="#{bean.validate}" type="submit" value="Search"/>
</h:form>
The CSS class "msgError" keeps the element hidden by default.
I would like to basically have a method in the "bean" class that validates the input by checking against the database, then if the value isn't found, unhide the error message, or if it is found, then execute another method which performs the actual functionality.
In my head, it would work sort of like this in the Java (forgive any syntax errors, just typing as I think):
#ManagedBean
public class Bean {
private String dataPoint1 = "";
private String dataPoint2 = "";
public boolean validate() {
if(dao.fieldExists(this.dataPoint1) && dao.fieldExists(this.dataPoint2)) { //check the database
performFunctionality();
return true;
}
else {
return false; //and show error div on screen
}
}
public void performFunctionality() {
//do whatever
}
//getters and setters
}
Any advice would be very welcome!
Thanks!
You're not utilizing JSF builtin validation facilities. Make use of it.
Here's how it can look like:
<h:form id="frmSearch">
<h:inputText id="dataPoint1" value="#{bean.dataPoint1}" validator="#{bean.validateDataPoint}" />
<h:message for="dataPoint1" />
<h:inputText id="dataPoint2" value="#{bean.dataPoint2}" validator="#{bean.validateDataPoint}" />
<h:message for="dataPoint2" />
<h:commandButton action="#{bean.performFunctionality}" value="Search">
<f:ajax execute="#form" render="#form" />
</h:commandButton>
</h:form>
with
public void validateDataPoint(FacesContext context, UIComponent component, Object convertedValue) {
if (!dao.fieldExists((String) convertedValue)) {
throw new ValidatorException(new FacesMessage("Value not found in database."));
}
}
That performFunctionality() must be executed by the command button's action method.
When validation fails (i.e. ValidatorException is been thrown), then the message will be displayed in the <h:message> associated with the input component and the action method won't be invoked. The validator attribute can alternatively also point to a fullworthy class which implements javax.faces.validator.Validator. The <f:ajax> is been added to make it an ajax submit.
See also:
How to perform validation in JSF, how to create a custom validator in JSF
Wherever you've learnt JSF, make sure that you've also read the chapters about conversion and validation. Don't think too much the PHP/ASP/JSP/jQuery way. JSF is a full fledged component based MVC framework.