Can we pass parameter values to JSF Validator in xhtml page.
For example <h:inputText value='#{myvalue}' validator='#{validator.method(param)}' /> or is there any way to do so.
Because i have a dataTable in which there are two columns with fields dealerType (selectOneMenu) and dealerNumber(inputText) where dealerNumber text strength validation is based on previous dealerType.
You may access the value of the selectOneMenu in the validator method of the inputText like this:
public void validate(FacesContext context, UIComponent component, Object value)
throws ValidatorException {
UIInput input = (UIInput) context.getViewRoot().findComponent("selectOneMenuID");
String str = (String) input.getSubmittedValue();
// now do the validation based on 'str'
}
Related
I have some inputtext in a form which is managed by a bean #Named and i would like to centralize the information concerning this fields such as which validator is assigned to which field.
If i directly write the name of the #FaceValidator, it works.
<h:inputText validator="validatorLogin"/>
If i tried to put the name of the validator with a bean property such as String validatorLogin = validatorLogin.
It will throw an error in the .xhtml like "Expression must be a method expression but is a value expression".
If i try to still run the code it will throw the following exception "validator=#{bean.validatorLogin}: Method not found".
<h:inputText validator="#{bean.validatorLogin}"/>
I expect the validator name to be set in the bean and the bean to feed the validator id in the inputtext field. So all informations about the form are centralized in one bean.
As well is it dumb to do so or is it something that will make the code more organized ?
As the validator attribute documentation states, there is no way to provide a validatorId via bean property to this attribute:
validator: MethodExpression representing a validator method that will be called
during Process Validations to perform correctness checks on the value
of this component. The expression must evaluate to a public method
that takes FacesContext, UIComponent, and Object parameters, with a
return type of void.
You would normally either hard code a validatorId as you did in your first example, or a method expression (in your second example) that resolves to a method like this:
public void validatorLogin(FacesContext context, UIComponent component, Object value)
throws ValidatorException {
// ...
}
Of course it's up to this bean implementation how the input is validated then. If you want to combine both approaches, you can delegate validation to one (or multiple) validators known by ID in your validatorLogin method:
public void validatorLogin(FacesContext context, UIComponent component, Object value)
throws ValidatorException {
final Collection<String> validatorIds = determineValidatorIds(context, component);
for (String validatorId : validatorIds) {
Validator<Object> validator = context.getApplication().createValidator(validatorId);
validator.validate(context, component, value);
}
}
private Collection<String> determineValidatorIds(FacesContext context, UIComponent component) {
// return hard coded validatorIDs or determine them on arbitrary logic.
}
If you urgently need to provide a validatorId via bean property, you can do so by using the f:validator tag within your input component:
<h:inputText id="txt" value="#{myBean.textValue}">
<f:validator validatorId="#{myBean.arbitraryValidatorId}" />
</h:inputText>
I'm building a form in primefaces and need to run validation on a specific field of all items in a <p:dataList>. Specifically I need to make sure there are only a maximum 3 different values in any number of items in the list.
<p:dataList value="#{myBean.myItems}" var="it"
id="myDataList" rowIndexVar="rowIndex">
...
<p:inputNumber value="#{it.fieldToValidate}">
<f:validator validatorId="myValidator" />
</p:inputNumber>
...
</p:dataList>
And the validator:
#FacesValidator(value = "myValidator")
public class MyValidator implements Validator {
#Override
public void validate(FacesContext context, UIComponent component, Object value)
throws ValidatorException {
if (component == null)
return;
Set<BigDecimal> myValues = new HashSet<BigDecimal>();
//now add all values to the set, but how to get them?
if (myValues.size() > 3) {
throw new ValidatorException(new FacesMessage(
FacesMessage.SEVERITY_ERROR, "To many different values",
"There can be only three"));
}
}
}
I have read Validation across multiple fields in JSF/PrimeFaces and
JSF doesn't support cross-field validation, is there a workaround? and
How validate two password fields by ajax?
but they don't solve my problem because I don't know the contents of my data list beforehand.
I am using JSF-2.1.7, Primefaces-6.0.4 and jdk-1.6, ancient I know but it can't be helped...
I am new in JSF, and my question is realted to the Validator. I have an FileUploader (primefaces) and a Form. when the Submit button is clicked , a method should check the DataTable inside of the Form and also a validator should check if any file has been uploaded via FileUploader. Hence, I have put a Hidden button which calls the validator.
In my Bean I have the following getter and setter:
public List<Attachment> getAttachmentList() {
return attachmentList;
}
public void setAttachmentList(List<Attachment> attachmentList) {
this.attachmentList= attachmentList;
}
and then in my validator I have the following code:
#FacesValidator("uploadValidator")
public class uploadValidator implements Validator {
public uploadValidator() {
// TODO Auto-generated constructor stub
}
#Override
public void validate(FacesContext context, UIComponent component,
Object value) throws ValidatorException {
FacesMessage msg =
new FacesMessage(" this is the uploader message.",
"this is the uploader message.");
msg.setSeverity(FacesMessage.SEVERITY_ERROR);
throw new ValidatorException(msg);
}
when I call the validator from my XHTML file (<f:validator validatorId="uploadValidator" />), in Primefaces growl message, I recieve the error :
Conversion Error setting value '[]' for 'null Converter
Here is XHTML code:
<h:inputHidden id="hidenB" value="#{myBean.attachmentList}">
<f:validator validatorId="uploadValidator" />
</h:inputHidden>
I know the problem is when I pass value to "Object value" but i don't know how to resolve it.
In Validator I just need to know if the attachmentList is empty or not, while in myBean i do other things with attachmentList, How can I send just a boolean value to the Validator ? can I have another getter and setter that send a Boolean value ?? if yes then I don't need a converter
Thanks in advance for any help.
hi i wrote a custom a validator which gets the system name and compare it against the id in database, now i wanna apply a check if this value is exactly the same, user must be allowed to click the button and move on else some error message should be displayed. and i am really confused how to call the validator() on through ajax.
my view page code is
<h:commandButton action="sample?faces-redirect=true" value="submit">
<f:ajax execute="#{csample.UserValidator}" render="#form" >
<h:inputText name="idtext" value="#{csampleBean.id}" />
</f:ajax>
</h:commandButton>
and my custom validator
public void UserValidator(FacesContext context, UIComponent toValidate, Object value)
throws UnknownHostException, ValidatorException, SQLException, NamingException
{
java.net.InetAddress localMachine = java.net.InetAddress.getLocalHost();
String machine= localMachine.getHostName();
String query = "select * from USER_ where USER_ID = '"+machine+"'";
Context initContext = new InitialContext();
Context envContext = (Context)initContext.lookup("java:/comp/env");
DataSource ds = (DataSource)envContext.lookup("jdbc/myoracle");
Connection conn = ds.getConnection();
Statement stat = conn.createStatement();
//get customer data from database
ResultSet result = stat.executeQuery(query);
if (query==machine)
// what to do here
conn.close();
need some guidance
You need to create a class implementing the Validator interface. On validation fail, 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.
You can register the custom validator to JSF by annotating it with #FacesValidator with therein the validator ID. You can reference it in <h:inputXxx validator> or <f:validator validatorId>.
Here's a kickoff example:
#FacesValidator("userValidator")
public class UserValidator implements Validator {
#Override
public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
// ...
if (!valid) {
String message = "Sorry, validation has failed because [...]. Please try again.";
throw new ValidatorException(new FacesMessage(FacesMessage.SEVERITY_ERROR, message, null));
}
}
}
Which is been used as follows (note: <h:inputText> does not have name attribute! instead use id; also note that your initial code snippet has some nesting which isn't making any sense):
<h:inputText id="idtext" value="#{csampleBean.id}" validator="userValidator">
<f:ajax render="idtextMessage" />
</h:inputText>
<h:message id="idtextMessage" for="idtext" />
<h:commandButton action="sample?faces-redirect=true" value="submit" />
See also:
How to perform validation in JSF, how to create a custom validator in JSF
Unrelated to the concrete problem, your JDBC code is leaking DB resources. Please fix that as well.
I have a simple request scoped entity / pojo which has a Enum and a String as properties.
public Enum Type
{
None,
Email,
Fax;
}
#ManagedBean(name = "testEntity")
#RequestScoped
public class TestEntity
{
private Type type; //Default = None
private String address;
//getter and setter
}
This Enum has a field 'Email' which identifies a e-mail address with a related address.
In JSF I now want to enable/disable a validator of a address InputText field regarding the currently selected type in a SelectOneMenu.
<h:form id="formId">
<p:selectOneMenu id="type" value="#{testEntity.type}>
<p:ajax event="change" update=":formId:address"/>
<f:selectItem itemLabel="E-mail" itemValue="Email"/>
<f:selectItem itemLabel="Fax" itemValue="Fax"/>
</p:selectOneMenu>
<p:inputText id="address" value="#{testEntity.address}">
<f:validator validatorId="emailValidator" disabled="#{testEntity.type != 'Email'}"/>
</p:inputText>
<!-- button to call bean method with testEntity as param -->
</h:form>
It is not working the validator is never active but the ajax call is working since I can see the change value in other fields.
That's unfortunately not possible. The <f:xxx> tags are taghandlers (not UI components) which run during view build time, not during view render time. So if it's disabled during building of the view, it'll always be disabled until the view is recreated (e.g. by new request or a non-null navigation).
You'd need to have a "global" validator which delegates further to the desired validator based on the type attribute.
E.g.
<p:inputText ... validator="#{testEntity.validateAddress}" />
with
public void validateAddress(FacesContext context, UIComponent component, Object value) throws ValidatorException {
if (type == Email) {
context.getApplication().createValidator("emailValidator").validate(context, component, value);
}
}
Update OmniFaces has recently added a new <o:validator> tag which should solve exactly this problem as follows:
<o:validator validatorId="emailValidator" disabled="#{testEntity.type != 'Email'}"/>
See the showcase example here.
Maybe someone is interested in how I solved it thanks to BalusC help.
Pass type component clientId to custom converter.
<f:attribute name="typeComponentId" value=":formId:type"/>
Validator:
public class TestEntity implements Validator
{
#Override
public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException
{
final String typeComponentId = (String)component.getAttributes().get("typeComponentId");
final UIInput compType = (UIInput)context.getViewRoot().findComponent(typeComponentId);
if(compType != null)
{
final Type type = (Type)compType.getValue();
if(type == Type.Email)
new EmailValidator().validate(context, component, value);
}
}
}
Edit:
Not working inside a ui:repeat component such as p:datatable.