Validating three dependent h:selectOneMenus - validation

i want to validate a jsf selectOne Menu:
<h:selectOneMenu id="day" value="#{registerService.dayOfBirth}">
<f:selectItems value="#{registerService.days}" />
<f:validator validatorId="dateValidator" />
<f:attribute name="monthId" value="#{component.parent.parent.clientId}:month" />
<f:attribute name="yearId" value="#{component.parent.parent.clientId}:year" />
</h:selectOneMenu>
<h:selectOneMenu id="month" value="#{registerService.monthOfBirth}">
<f:selectItems value="#{registerService.months}" />
</h:selectOneMenu>
<h:selectOneMenu id="year" value="#{registerService.yearOfBirth}">
<f:selectItems value="#{registerService.years}" />
</h:selectOneMenu>
My Validator is this:
#FacesValidator(value="dateValidator")
public class DateValidator implements Validator {
public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
String year = (String) component.getAttributes().get("yearId");
String month = (String) component.getAttributes().get("monthId");
UIInput yearInput = (UIInput) context.getViewRoot().findComponent(year);
UIInput monthInput = (UIInput) context.getViewRoot().findComponent(month);
FacesMessage message = null;
int yearValue = (Integer) yearInput.getValue();
int monthValue = (Integer) monthInput.getValue();
int dayValue = (Integer) value;
Calendar calendar = Calendar.getInstance();
calendar.set(yearValue, monthValue, dayValue);
int daysOfMonth = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
if (daysOfMonth < dayValue) {
message = new FacesMessage ("Date is not valid!", "Email Validation Error");
message.setDetail("This month does not have so many days!");
message.setSeverity(FacesMessage.SEVERITY_ERROR);
throw new ValidatorException(message);
}
}
}
And i get this error message:
java.lang.IllegalArgumentException: j_idt12
at javax.faces.component.UIComponentBase.findComponent(UIComponentBase.java:655)
at de.hof.tschuwwa.controller.validators.DateValidator.validate(DateValidator.java:27)
at javax.faces.component.UIInput.validateValue(UIInput.java:1165)
at javax.faces.component.UISelectOne.validateValue(UISelectOne.java:146)
at javax.faces.component.UIInput.validate(UIInput.java:983)
at javax.faces.component.UIInput.executeValidate(UIInput.java:1249)
at javax.faces.component.UIInput.processValidators(UIInput.java:712)
at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1261)
at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1261)
at javax.faces.component.UIForm.processValidators(UIForm.java:253)
at com.sun.faces.context.PartialViewContextImpl$PhaseAwareVisitCallback.visit(PartialViewContextImpl.java:552)
at com.sun.faces.component.visit.PartialVisitContext.invokeVisitCallback(PartialVisitContext.java:183)
at javax.faces.component.UIComponent.visitTree(UIComponent.java:1689)
at javax.faces.component.UIForm.visitTree(UIForm.java:371)
at javax.faces.component.UIComponent.visitTree(UIComponent.java:1700)
at javax.faces.component.UIComponent.visitTree(UIComponent.java:1700)
at com.sun.faces.context.PartialViewContextImpl.processComponents(PartialViewContextImpl.java:399)
at com.sun.faces.context.PartialViewContextImpl.processPartial(PartialViewContextImpl.java:263)
... 32 more
So the exception is thrown here:
UIInput yearInput = (UIInput) context.getViewRoot().findComponent(year);
My other validators are all working but they arent with selectOneMenu they
are with inputText.

You can't pass autogenerated IDs. Give the parent naming container component a fixed ID:
<h:form id="myForm">
Or, better, just pass the whole component along:
<f:attribute name="month" value="#{month}" />
<f:attribute name="year" value="#{year}" />
...
<h:selectOneMenu binding="#{month}" ... />
<h:selectOneMenu binding="#{year}" ... />
and obtain them as follows:
UIInput yearInput = (UIInput) component.getAttributes().get("year");
UIInput monthInput = (UIInput) component.getAttributes().get("month");
Or, better yet, create a composite component based on the whole.

Related

jsf inputText don't execute change listener event

i have two .xhtml pages with two similar inputText elements ("customer id" and "customer name"), in both pages the inputText for "customer id" launch a request ajax event to looking for the name of the customer and to put it in the inputText for "customer name".
when i run the web application and use the first pages everything work fine, but if i don't use the first page and go to the second page (via commandlink in first page) without use the first page then the inputText for search the customer name don't work, indeed not enter to the testBean2.searchCustId method.
the code:
first page
<h:form>
<h:commandLink action="page2">PAGE 2</h:commandLink><br/>
<h:outputText value="customer id: "/>
<h:inputText id="custoId" label="CUSTOMER_ID" value="#{testBean.custId}" required="true">
<a4j:ajax event="change" listener="#{testBean.searchCustId(testBean.custId)}" render="custoName"/>
<f:validateLength minimum="1" maximum="12"/>
</h:inputText>
<rich:message for="custoID" ajaxRendered="true"/>
<h:outputText value="Customer name: "/>
<h:inputText id="custoName" label="CUSTOMER_NAME" value="#{testBean.custName}"/>
<rich:message for="custoName" ajaxRendered="true"/>
</h:form>
second page
<h:form>
<h:outputText value="customer id: "/>
<h:inputText id="custoId2" label="CUSTOMER_ID2" value="#{testBean2.custId}" required="true">
<a4j:ajax event="change" listener="#{testBean2.searchCustId(testBean2.custId, 0)}" render="custoName2"/>
<f:validateLength minimum="1" maximum="12"/>
</h:inputText>
<rich:message for="custoId2" ajaxRendered="true"/>
<h:outputText value="customer name: "/>
<h:inputText id="custoName2" label="CUSTOMER_NAME2" value="#{testBean2.custName}"/>
<rich:message for="custoName2" ajaxRendered="true"/>
</h:form>
now jsf managed bean
testBean
public class TestBean {
private String custId;
private String custName;
public TestBean() {
}
//getter and setter
public void searchCustId(String ced){
custName = ced + "- SOME CUSTOMER NAME"; //THIS IS FOR TESTING
}
}
testBean2
public class TestBean2 {
private String custId;
private String custName;
public TestBean2() {
}
//getter and setter
public void searchCustId(String ced, int que){
custName = ced + " - " + que; //THIS IS FOR TESTING
}
}
what may be happening?
i'm new on this and my english is not good :)
You can use f:setPropertyActionListener.
<a4j:ajax event="change" listener="#{myBean.listener}">
<f:setPropertyActionListener target="#{myBean.someProperty}" value="your_value_here"/>
</a4j:ajax>
But from your code it looks like you are trying to pass the very one value that's used on h:inputText, that's not necessary:
<h:inputText id="custoId" label="CUSTOMER_ID" value="#{testBean.custId}" required="true">
<a4j:ajax event="change" listener="#{testBean.searchCustId}" render="custoName"/>
<f:validateLength minimum="1" maximum="12"/>
</h:inputText>
After Ajax event the values testBean.searchCustId will automatically be updated on Managed bean after passing the validation, so your listener could be:
public class TestBean {
private String custId;
private String custName;
public TestBean() {
}
//getter and setter
public void searchCustId(){
custName = custId + "- SOME CUSTOMER NAME"; //THIS IS FOR TESTING
}
}

Change default message of f:validateRegex

I have input for email:
<h:inputText value="#{registrationBean.email}" id="email" label="#{msgs.email}">
<f:validateLength minimum="5" maximum="50" />
<f:validateRegex
pattern="^[_A-Za-z0-9-\+]+(\.[_A-Za-z0-9-]+)*#[A-Za-z0-9-]+(\.[A-Za-z0-9]+)*(\.[A-Za-z]{2,})$" />
</h:inputText>
<h:message for="email"/>
So, how I can change message, when validateRegex not matched? Now message is:
Regex pattern of '^[_A-Za-z0-9-\+]+(\.[_A-Za-z0-9-]+)*#[A-Za-z0-9-]+(\.[A-Za-z0-9]+)*(\.[A-Za-z]{2,})$' not matched
But I want something like „Incorrect e-mail…”
Thanks.
You can use the validatorMessage attribute of inputText. In your case you can use this:
<h:inputText value="#{registrationBean.email}" id="email" label="#{msgs.email}" validatorMessage="Incorrect e-mail…">
<f:validateLength minimum="5" maximum="50" />
<f:validateRegex pattern="^[_A-Za-z0-9-\+]+(\.[_A-Za-z0-9-]+)*#[A-Za-z0-9-]+(\.[A-Za-z0-9]+)*(\.[A-Za-z]{2,})$" />
</h:inputText>
<h:message for="email"/>
You can use validator:
public class EmailValidator implements Validator {
private static Pattern patt = Pattern.compile(Constants.getEmailRegExp());
#Override
public void validate(FacesContext arg0, UIComponent comp, Object arg2)
throws ValidatorException {
if (arg2 == null || arg2.toString().trim().length() == 0) {
return;
}
if (!patt.matcher(arg2.toString().trim()).matches()) {
String label = (String) comp.getAttributes().get("label");
throw new ValidatorException(new FacesMessage(
FacesMessage.SEVERITY_ERROR, (label == null || label.trim().length() == 0 ? "Email: " : label+": ") +
"Invalid format", null));
}
}
}
Register it via annotation or in faces-config.xml:
<validator>
<validator-id>email-validator</validator-id>
<validator-class>path.EmailValidator</validator-class>
</validator>
And use it
<h:inputText id="email" label="#{msg.email}"
value="#{registrationForm.email}"
size="40" maxlength="80" required="true">
<f:converter converterId="lowerCase" />
<f:validator validatorId="email-validator" />
</h:inputText>

JSF form is not submitted

Please check this form the form data is submitted but setAttendancedata method is working..
but classname, sectionname, date is not set in variable ..
xhtml:
<p:panel header="Attendance Entry" style="margin-top:10px">
<p:growl id="msgs" showDetail="true" />
<h:form id="attendance">
<h:panelGrid id="detail" columns="10" styleClass="grid"
cellspacing="10" cellpadding="40">
<h:outputText value="Date: " />
<h:outputText value="" id="popupDate">
<f:convertDateTime pattern="yyyy-mm-dd" />
</h:outputText>
<p:calendar value="#{StudentAttendanceComponent.date}"
id="popupCal" />
<h:outputText value="Class :" />
<p:selectOneMenu id="classname"
value="#{StudentAttendanceComponent.classname}">
<f:selectItem itemLabel="Select Class Name" itemValue="" />
<f:selectItems value="#{PreferencesClassComponent.classnames}" />
</p:selectOneMenu>
<h:outputText value="Section :" />
<p:selectOneMenu id="sectionname"
value="#{StudentAttendanceComponent.sectionname}">
<f:selectItem itemLabel="Select Section Name" itemValue="" />
<f:selectItems value="#{PreferencesSectionComponent.sectionnames}" />
</p:selectOneMenu>
<p:commandButton ajax="false" immediate="true" value="Go"
action="#{StudentAttendanceComponent.setAttendanceData}"
update="msgs" icon="ui-icon-check"></p:commandButton>
</h:panelGrid>
</h:form>
Model:
#Scope("session")
#Component("StudentAttendanceComponent")
public class StudentAttendanceComponentImpl implements
StudentAttendanceComponent {
/**
* Data type variable that provides CRUD operations for StudentAttendance
* entities
*
*/
#Autowired
StudentMasterService studentMasterService;
private Date date = new Date();
private String[] attData;
private StudentAttendance studentattendance;
private String classname;
private String sectionname;
private List<StudentAttendance> studentAttendances;
#Autowired
private StudentAttendanceDAO studentAttendanceDAO;
/**
* Service injected by Spring that provides CRUD operations for
* StudentAttendance entities
*
*/
#Autowired
private StudentAttendanceService studentAttendanceService;
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
public String getClassname() {
return classname;
}
public void setClassname(String classname) {
this.classname = classname;
}
public String getSectionname() {
return sectionname;
}
public void setSectionname(String sectionname) {
this.sectionname = sectionname;
}
public void setAttendanceData() {
// TODO Auto-generated method stub
System.out.println(classname+sectionname);
FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_INFO,
"Filter Data", "Class " + classname + ", section " + sectionname+", date " + getDate().getDate());
FacesContext.getCurrentInstance().addMessage("msgs", msg);
}
The problem you have is, that you set the immediate="true" attribute within your p:commandButton. Because of this attribute, several JSF Lifecycles are skipped.
Check these links:
http://docs.oracle.com/javaee/1.4/tutorial/doc/JSFIntro10.html
http://balusc.blogspot.co.at/2006/09/debug-jsf-lifecycle.html#AddImmediateTrueToUICommandOnly
http://balusc.blogspot.co.at/2006/09/debug-jsf-lifecycle.html#WhenShouldIUseTheImmediateAttribute

JSF validate on submit form

I'm working on a JSF 2.0 form, I have a managedbean with 2 fields
import java.util.Date;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
#ManagedBean
#RequestScoped
public class StackOverflow {
private Date firstDate;
private Date secondDate;
public void submit(){
//validate here and show error on form
}
}
and the xhtml like:
<h:inputText value="#{stackOverflow.firstDate}">
<f:convertDateTime pattern="d/M/yyyy" />
</h:inputText>
<h:inputText value="#{stackOverflow.secondDate}">
<f:convertDateTime pattern="d/M/yyyy" />
</h:inputText>
<h:commandLink action="#{stackOverflow.submit}">
<span>Submit</span>
</h:commandLink>
I want to validate the first and second date that the second date is not before the first date
Here's one of the ways:
<h:messages globalOnly="true"/>
<h:form>
<h:inputText value="#{stackOverflow.firstDate}" binding="#{firstDate}">
<f:convertDateTime pattern="d/M/yyyy" />
</h:inputText>
<h:inputText value="#{stackOverflow.secondDate}" validator="dateValidator">
<f:attribute name="firstDate" value="#{firstDate}" />
<f:convertDateTime pattern="d/M/yyyy" />
</h:inputText>
<h:commandButton value="Submit" action="#{stackOverflow.submit}"/>
</h:form>
with
#FacesValidator(value="dateValidator")
public class DateValidator implements Validator {
#Override
public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
UIInput sd = (UIInput)component.getAttributes().get("firstDate");
Date firstDate = (Date)sd.getValue();
Date secondDate = (Date)value;
if(!firstDate.before(secondDate)){
FacesMessage msg = new FacesMessage("Entered dates are invalid: first date must be before second date");
throw new ValidatorException(msg);
}
}
}

AjaxBehaviorEvent primefaces3.2

My problem is that the following code returns null but if I look when debuging source then submittedValue has the correct date.
Java:
public void changeOneMenuP(AjaxBehaviorEvent event) {
String id = (String) event.getComponent().getAttributes().get("value");
if(id != null) {
listEntity = escDao.findByxxxx(id, true);
}
}
XHTML:
<h:selectOneMenu id="idSelect" immediate="true" style="width:120px" value="#EntityBB.idUni}" label="#{bundleComunes.unidad}">
<f:selectItem itemLabel="#{bundleComunes.seleccionar}..." itemValue="" />
<f:selectItems value="#{configuracionBB.listEntity}" var="lUni" itemValue="#lUni.id}" itemLabel="#{lUni.desc}" />
<p:ajax event="change" update="sisArm" listener="#{entityBB.changeOneMenuP}" />
</h:selectOneMenu>
Any Idea????
better don't mix primefaces p:ajax with Pure JSF
try using f:ajax
<f:ajax event="change" render="sisArm" listener="#{entityBB.changeOneMenuP}" />
Also , you better access your id like this
public void changeOneMenuP(AjaxBehaviorEvent event) {
listEntity = escDao.findByxxxx(getidUni(), true);//or just idUni
}

Resources