I want to validate an input as an integer. Thus, any value with decimal fractions should be filtered. But I don't know how to achieve that. I have tried many things, but with the code below, if the input is "61.2", the value is converted to 61, just truncating decimal part. But I want to force a validation error. I am sure I can do it without a custom validator. Thanks
<p:inputText size="5" value="#{bean.intValue}" converter="#{Integer}">
<f:convertNumber pattern="#0" integerOnly="true" maxFractionDigits="0"/>
</p:inputText>
That's not possible as validation runs after conversion. You'd basically need to bind it to a String property instead of an Integer one in order to validate the unconverted value. You'd need to convert it afterwards in the property setter or the managed bean action method. So, if you make it a String property, you could use <f:validateRegex> for this.
<h:inputText value="#{bean.input}" validatorMessage="Please enter digits only">
<f:validateRegex pattern="\d*" />
</h:inputText>
Alternatively, and IMO better than manually converting it in the setter or action method, you could bring in a custom converter which extends the JSF standard IntegerConverter and validate the pattern in there right before conversion takes place.
#FacesConverter("digitsOnly")
public class DigitsOnlyConverter extends IntegerConverter {
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) throws ConverterException {
if (!value.matches("\\d*")) {
throw new ConverterException();
}
return super.getAsObject(context, component, value);
}
}
with
<h:inputText value="#{bean.input}" converterMessage="Please enter digits only">
<f:converter converterId="digitsOnly" />
<h:inputText>
place minFractionDigits = "0" and pattern=" # # #"
Related
I want to disable the default JSF validation and conversion of one input field inputtext in order to be able to validate it using jQuery.
<p:column headerText="Quantité">
<p:inputText widgetVar="input_qte" styleClass="my_qte" value="#{arti.qte}">
<f:validateBean disabled="true"/>
</p:inputText> \
<h:outputText styleClass="my_qtemax" value="#{arti.qtemax}" />
<div class="my_validator" style="display : none;">Valeur Invalide</div>
</p:column>
The #{arti.qte} is bound to a Double property.
How can I achieve this?
There's already no validation on that component, as far as I see in the information provided so far. Perhaps you specifically meant the implicit conversion when you bind a non-String type as input component's value? No, you can't disable this. You can only workaround it by supplying a custom converter which doesn't throw an exception, but just returns null on failure.
E.g. by just extending the standard JSF DoubleConverter and totally suppressing the ConverterException on getAsObject():
#FacesConverter("lenientDoubleConverter")
public class LenientDoubleConverter extends DoubleConverter {
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
try {
return super.getAsObject(context, component, value);
} catch (ConverterException ignore) {
return null;
}
}
}
Which is then used as:
<p:inputText ... converter="lenientDoubleConverter" />
Unrelated to the concrete problem, please note that client side validation/conversion is absolutely not reliable. As JavaScript runs fully at the client side, the enduser has full control over the code being executed. I.e. the enduser can easily disable, bypass, spoof it, etc. See also JSF2 Validation Clientside or Serverside?
I have specific use case for JSF validation. For example I have an inputText field:
<p:inputText id="input" required="#{myBean.required}" value="#{myBean.value}" maxlength="20" disabled="#{myBean.disabled}">
<p:ajax event="blur" process="#this" update="name" listener="#{myBean.listener}"/>
</p:inputText>
Value of input is number (in some cases it can also be a string, because this is part of composite component, but problem is better described if we assume this is a number). This input is part of the form, at the end of form I have submit button:
<p:commandButton value="Save" actionListener="#{myBean.save}"/>
What are my requests:
When submit button is pressed all validation should be processed and this is OK, this works fine.
When blur event is fired on input field if field is not empty a number validation should be processed, and this is also OK. At the end I update field with id name with some value.
Now I have a problem. My third request is when input is empty validation on input should not be processed. This is special case in which I will clear field with id name. This is also case when i remove text which is already entered in input, remove focus from component (press TAB for example) and in that case AJAX request should also be processed and name input will also be cleared.
How I can disable validation of this input field in case when it is empty, and just for this ajax event?
Let the input's required attribute check if the save button is pressed or not (which can be identified by the presence of its client ID in the request parameter map).
<h:form>
<p:inputText ... required="#{not empty param[save.clientId] and myBean.required}" />
<p:commandButton binding="#{save}" ... />
</h:form>
(note: do not bind it to a bean property! the code is as-is)
This way it would only evaluate true when the save button is actually pressed.
Or, if you have problems with binding and/or don't have a problem hardcoding the button's client ID:
<h:form id="formId">
<p:inputText ... required="#{not empty param['formId:buttonId'] and myBean.required}" />
<p:commandButton id="buttonId" ... />
</h:form>
Just remove the required attribute as you accept the input if the input is empty. Then write a custom validator which accepts only empty input or numerical input.
<p:inputText id="input" value="#{myBean.value}" maxlength="20" disabled="#{myBean.disabled}" validator="customerNumericInputValidator"> <p:ajax event="blur" process="#this" update="name" listener="#{myBean.listener}"/> </p:inputText>
public class customerNumericInputValidator implements Validator {
#Override
public void validate(FacesContext facesContext, UIComponent uIComponent,
Object object) throws ValidatorException {
String number = (String) object;
number = Strings.nullToEmpty(number).trim();
//if the request is a full request then number can not be empty
if(!FacesContext.getCurrentInstance().isPostback() && Strings.isNullOrEmpty(number))
{
FacesMessage message = new FacesMessage();
message.setSummary(Messages.getMessage("error empty value"));
message.setSeverity(FacesMessage.SEVERITY_ERROR);
throw new ValidatorException(message);
}
if(!Strings.isNullOrEmpty(number))
{
if(!isNumber(number))
{
FacesMessage message = new FacesMessage();
message.setSummary(Messages.getMessage("error not numerical value"));
message.setSeverity(FacesMessage.SEVERITY_ERROR);
throw new ValidatorException(message);
}
}
}
}
Requirements in an app I'm developing say that when performing a search, the user should not be able to search for City without entering State, and vice versa, they shouldn't be able to search for State without entering City.
search.xhtml
<h:inputText id="city" binding="#{city}" value="#{search.city}" validator="#{search.validateCity}">
<f:attribute name="state" value="#{state}"/>
</h:inputText>
<h:inputText id="state" binding="#{state}" value="#{search.state}" validator="#{search.validateState}">
<f:attribute name="city" value="#{city}"/>
</h:inputText>
Search.java
public void validateCity(FacesContext context, UIComponent component, Object convertedValue) {
UIInput stateComponent = (UIInput) component.getAttributes().get("state");
String state = (String) stateComponent.getValue();
if(convertedValue.toString().length() > 0) {
if(state.length() < 1) {
throw new ValidatorException(new FacesMessage("Please enter State."));
}
}
}
public void validateState(FacesContext context, UIComponent component, Object convertedValue) {
UIInput cityComponent = (UIInput) component.getAttributes().get("city");
String city = (String) cityComponent.getValue();
if(convertedValue.toString().length() > 0) {
if(city.length() < 1) {
throw new ValidatorException(new FacesMessage("Please enter City."));
}
}
}
I've simplified down my code to show what I attempted with the standard cross field validation method. However, the problem I'm hitting is that in the validation phase, both City and State are showing Validation errors, I'm guessing because the two validators are getting in each others' way and therefore creating a loop of failure.
Is there a workaround I can use to get around this?
Thanks.
The components are validated in the order as they are declared in the component tree.
When you call UIInput#getValue() on a component which isn't validated yet, then it'll return null. Also, when you call UIInput#getValue() on a component which is already validated and been marked invalid, then it'll return null (or the old model value).
If you want to get the value of the second component during validation of the first component, then you should be using UIInput#getSubmittedValue() instead of UIInput#getValue(). You should only keep in mind that this returns the unconverted String.
Alternatively, you could take a look at OmniFaces <o:validateAllOrNone> component.
<h:inputText id="city" value="#{search.city}" />
<h:inputText id="state" value="#{search.state}" />
<o:validateAllOrNone id="cityAndState" components="city state" message="Please fill both city and state." />
<h:message for="cityAndState" />
So, you can validate input using JSR-303 annotations on the binding bean property:
class Ticket {
#MinAge(18)
Person person;
}
class Person {
#Min(1) #Max(100)
int age;
}
<p:inputText id="age" value="#{bean.ticket.person.age}" />
Here, the property Person.age is validated (between 1..100) with no problem.
The problem is, I want to validate the outer instance (person.age >= 18). But how to make the property bean.ticket.person be known to validation?
I want something like:
<p:inputText id="age" value="#{bean.ticket.person.age}">
<f:validate value="#{bean.ticket.person}" />
</p:inputText>
Or:
<p:inputText id="age" value="#{bean.ticket.person.age}">
<f:validator id="jsr303-validator" value="#{bean.ticket.person}" />
</p:inputText>
The problem is, I can't pass a value to <f:validator />. I want to add extra properties to the validation process, more then only the inputs appeared on the page.
P.S. This is a simplified example, the real application is:
...
<p:inputText id="principalLabel" value="${activeACL.principal.label}" readonly="true" />
<p:commandButton value="Choose..." onclick="choosePrincipalDialog.show()" />
...
<p:commandButton value="Save" action="${bean.saveACL}" oncomplete="editACLDialog.hide()" update="index" />
And activeACL of type ACL_DTO:
class ACL_DTO {
...
#IdRequired
Principal_DTO principal;
}
Here, choosePrincipalDialog's actionListener will implicit change the ${activeACL.principal.id}, which is initially null. IdRequired is a custom constraint which constrains an object's id member property is not null or -1.
Though, I can change to use #NotNull on the id property, and add a hidden-input to enable the validation on the id:
class Principal_DTO {
...
#NotNull
#Min(0)
Long id;
}
...
<h:inputHidden id="principalId" value="${activeACL.principal.id}" />
<h:inputText id="principalLabel" ...
But, in this way I can't reuse the validation messages any more. Give message like "This string should not be null", "This value should not be -1" to the user seems meaningless.
Firstly, I think that you should make sure to use the beans only as a place where you get your input available. After that, you assign the value to the model. In my opinion the beans should not be used directly as a model but rather as a web-form-backing beans (Every web form has different bean).
Secondly, I agree that you you come across scenarios where you have dependency to other data to preform the validation (e.g. If the user selected US as a country, the postcode etc. should not be left empty). You can have a look at here how to implement custom annotation:
Cross field validation with Hibernate Validator (JSR 303)
If you do not use bean validation you can always implement a custom validator class or even define a validation method directly in the bean: http://docs.oracle.com/javaee/6/tutorial/doc/bnavb.html#bnave
How can I validate an input text box based on a selection from the drop-down list?
You could pass the selected value of the dropdown as an attribute of the input component so that the validator can grab it.
E.g.
<h:selectOneMenu binding="#{menu}" value="#{bean.item}">
<f:selectItems value="#{bean.items}" />
</h:selectOneMenu>
<h:inputText value="#{bean.input}">
<f:attribute name="item" value="#{menu.value}" />
<f:validator validatorId="inputValidator" />
</h:inputText>
with
#FacesValidator("inputValidator")
public class InputValidator implements Validator {
#Override
public void validate(FacesContext context, UIComponent component, Object value) {
Object item = component.getAttributes().get("item");
// ...
}
}
Note that the ordering of the components matters. JSF processes UIInput components in the order they appear in the view. If the dropdown component is placed after the input text component, then you need to pass #{menu.submittedValue} as attribute, but at that point the value is not converted yet. You could if necessary workaround with a <h:inputHidden> which is placed after the both components and put the validator in there.