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
Related
I have a JSF form. I want a message to be displayed, when a user entered 0 in qty field and clicked on the Add To Card button.
Here is the JSF form:
<h:form>
<h:inputText id="qtyField" value="#{booksBean.qty}">
<!--What kind of validation should i use here?-->
<f:ajax event="blur" render="qtyMsg"/>
</h:inputText>
<h:message id="qtyMsg" for="qtyField"/>
<h:commandButton value="Add To Card"
action="#{booksBean.orderBook()}"
rendered="#{booksBean.qty>0}">
<f:ajax execute="#form" rendered="#form"/>
</h:commandButton>
</h:form>
Do I need a custom validator class just to simply compare a number value with a zero?
Like this:
#FacesValidator("myValidator")
public class MyValidator implements Validator {
#Override
public void validate(FacesContext context, UIComponent component, Object value) {
if (intValue== 0 || intValue <0) {
throw new ValidatorException(new FacesMessage(...));
}
//...
}
Is there any shorter way without creating a custom validator class?
You can use f:validateLongRange for this.
<h:inputText value="#{backingBean.input1}">
<f:validateLongRange minimum="1" />
</h:inputText>
Checks whether the local value of a component is within a certain
range. The value must be any numeric type or String that can be
converted to a long.
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
In my jsf application i want to validate a field which should only be validated, when one option in a SelectOneRadio is checked.
I found out, that <f:validator> has an attribute, called "disabled".
Can i use this, to check the value from another field?
I tried, but i haven't access to the value from my bean.
<h:selectOneRadio value="#{myBean.checkedSelectOneRadioValue}">
<f:selectItems value="#{myBean.valuesForSelectOneRadio}" />
</h:selectOneRadio>
<f:validator validatorId="myValidator" disabled="#{myBean.checkedSelectOneRadioValue == 'TEST'}" />
Is there any way to reach that without writing own validatorhandler?
Thanks!
The <f:validator> is a tag handler, not an UI component. All its attributes are per definition evaluated during view build time, not during view render time. The view build time is that moment when the XHTML file is been parsed into a JSF component tree as available by context.getViewRoot(). The very same view is usually reused across postbacks to the same view by returning null/void in (ajax) actions.
So you can't let a tag handler attribute depend on a render time attribute which can change during a postback request. One of the ways is to perform that check inside the custom validator itself.
E.g.
<h:inputText>
<f:validator validatorId="myValidator" />
<f:attribute name="radio" value="#{myBean.checkedSelectOneRadioValue}" />
</h:inputText>
with
#Override
public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
if (!"TEST".equals(component.getAttributes().get("radio"))) {
return;
}
// Perform actual validation here.
}
You can alternatively also use OmniFaces <o:validator> instead. It extends the standard <f:validator> with request based evaluation of EL in attributes.
<h:inputText>
<o:validator validatorId="myValidator" disabled="#{bean.checkedSelectOneRadioValue == 'TEST'}" />
</h:inputText>
See also the showcase example and the source code from which an extract of relevance is posted below:
#Override
public void apply(FaceletContext context, UIComponent parent) throws IOException {
if (!ComponentHandler.isNew(parent)) {
return;
}
final javax.faces.validator.Validator validator = createValidator(context);
final RenderTimeAttributes attributes = collectRenderTimeAttributes(context, validator);
final ValueExpression disabled = getValueExpression(context, "disabled", Boolean.class);
((EditableValueHolder) parent).addValidator(new javax.faces.validator.Validator() {
#Override
public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
if (disabled == null || Boolean.FALSE.equals(disabled.getValue(context.getELContext()))) {
attributes.invokeSetters(context.getELContext(), validator);
validator.validate(context, component, value);
}
}
});
}
With JSF 2.0 you can use f:ajax for a partial submit. Add this tag to your h:selectOneRadio:
<h:selectOneRadio value="#{myBean.checkedSelectOneRadioValue}">
<f:ajax render="idOfInputText"/>
<f:selectItems value="#{myBean.valuesForSelectOneRadio}" />
</h:selectOneRadio>
...
<h:inputText id="idOfInputText">
<f:validator validatorId="myValidator"
disabled="#{myBean.checkedSelectOneRadioValue eq 'TEST'}" />
</h:inputText>
Replace the renderattribute content with the real id of your input field with the validator. This assumes that the selectOneRadio and the inputText are inside the same NamingContainer.
To avoid extended discussions in comments, i will provide my suggestions as an answer to discuss it further...
At first it should be
disabled="#{myBean.checkedSelectOneRadioValue == 'TEST'}
or
disabled="#{myBean.checkedSelectOneRadioValue eq 'TEST'}
Additional, at least in ICEFaces (and MyFaces should have this function, too), you may use:
<h:selectOneRadio value="#{myBean.checkedSelectOneRadioValue}" partialSubmit="true">
<f:selectItems value="#{myBean.valuesForSelectOneRadio}" />
</h:selectOneRadio>
This should force an ajax request after changing the value of selectoneradio and the validator-disabled check should be able to get it from the bean.
If that does not work, there may be autoSubmit or similar in MyFaces...
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.
I would like to perform validation in some of my input components such as <h:inputText> using some Java bean method. Should I use <f:validator> or <f:validateBean> for this? Where can I read more about it?
The standard way is to implement the Validator interface.
#FacesValidator("fooValidator")
public class FooValidator implements Validator {
#Override
public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
// ...
if (valueIsInvalid) {
throw new ValidatorException(new FacesMessage("Value is invalid!"));
}
}
}
The #FacesValidator will register it to JSF with validator ID myValidator so that you can reference it in validator attribute of any <h:inputXxx>/<h:selectXxx> component as follows:
<h:inputText id="foo" value="#{bean.foo}" validator="fooValidator" />
<h:message for="foo" />
Whenever the validator throws a ValidatorException, then its message will be displayed in the <h:message> associated with the input field.
You can also use EL in validator attribute of any <h:inputXxx>/<h:selectXxx> component wherein you reference a managed bean method having exactly the same method signature (the same method arguments) as Validator#validate(). I.e. taking FacesContext, UIComponent and Object arguments in this order.
<h:inputText id="foo" value="#{bean.foo}" validator="#{bean.validateFoo}" />
<h:message for="foo" />
public void validateFoo(FacesContext context, UIComponent component, Object value) throws ValidatorException {
// ...
if (valueIsInvalid) {
throw new ValidatorException(new FacesMessage("Value is invalid!"));
}
}
This is only useful if the validator needs to access another property present in the same managed bean. If it doesn't need to, then this approach is considered tight-coupling (poor practice thus), and you should split out the validator to its own class implementing the Validator interface.
You can also use <f:validator> taghandler, which would be the only way if you intend to attach multiple validators on the same component:
<h:inputText id="foo" value="#{bean.foo}">
<f:validator validatorId="fooValidator" />
</h:inputText>
<h:message for="foo" />
This will execute the #FacesValidator("fooValidator") shown above.
You can also use <f:validator binding> to reference a concrete validator instance somewhere in the EL scope, which can be specified and supplied the following way:
<h:inputText id="foo" value="#{bean.foo}">
<f:validator binding="#{fooValidator}" />
</h:inputText>
<h:message for="foo" />
#Named("fooValidator")
public class FooValidator implements Validator {
#Override
public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
// ...
if (valueIsInvalid) {
throw new ValidatorException(new FacesMessage("Value is invalid!"));
}
}
}
Note that thus #Named is being used instead of #FacesValidator. The old #ManagedBean is also supported here instead of #Named. Historically, this was a trick in order to be able to use #EJB and #Inject in a validator. See also How to inject in #FacesValidator with #EJB, #PersistenceContext, #Inject, #Autowired
Or this way, which in turn can easily be supplied as a lambda:
<h:inputText id="foo" value="#{bean.foo}">
<f:validator binding="#{bean.fooValidator}" />
</h:inputText>
<h:message for="foo" />
public Validator getFooValidator() {
return (context, component, value) -> {
// ...
if (valueIsInvalid) {
throw new ValidatorException(new FacesMessage("Value is invalid!"));
}
};
}
Also here applies the same problem of tight-coupling when this validator doesn't need any other property from the same bean.
To get a step further, you can use JSR303 bean validation. This validates fields based on annotations. So you can have just a
#Foo
private String foo;
Without the need to explicitly register any validator in XHTML side. If you're using JPA for persistence, by default this validator will also be executed during insert/update in DB. Since it's going to be a whole story, here are just some links to get started:
Hibernate Validator - Getting started
JSF 2.0 tutorial - Finetuning validation
There's also a <f:validateBean> tag, but this is only useful if you intend to disable the JSR303 bean validation. You then put the input components (or even the whole form) inside <f:validateBean disabled="true">.
See also:
JSF doesn't support cross-field validation, is there a workaround?
How to perform JSF validation in actionListener or action method?