2
votes

I am using primefaces 3.2.

I've got the following situation:

<h:form id="someForm">
  ..
  <p:dataTable id="someDataTable" value="#{BackingBean.list}" var="element" ..>
    <p:column>
      <p:calendar id="someCalendar" value=#{element.date} ../>
      <p:message id="someCalendarMessage" for=":someForm:someDataTable:someCalendar"/>
    <p:column>
  </p:dataTable>    
  ..
</h:form>

The "someDataTable" is updated dynamically and then all the data are submitted to the server side. In the backing bean I want to send message for calendar "someCalendar" if the entered date doesn't satisfy some condition. I try to find the component using this code:

FacesContext facesContext = FacesContext.getCurrentInstance();
facesContext.addMessage(facesContext.getViewRoot().findComponent(":someForm:someDataTable:" + "i" + ":someCalendar").getClientId(), new FacesMessage(FacesMessage.SEVERITY_ERROR, Utils.getResourceBundleString("dictionary", "error") + ":", Utils.getResourceBundleString("dictionary", "some_message")));
return;

Where i is the index of the "element" in the dataTable which the same as index in the list located in the BackingBean.

The problem is that I get NullPointerException since the facesContext.getViewRoot().findComponent(..) method cannot find the component, although I checked the generated id of the calendar in the view and it is :someForm:someDataTable:0:someCalendar for the first element and it should be :someForm:someDataTable:1:someCalendar for the next element etc.

Why the facesContext.getViewRoot().findComponent(..) method cannot find the component inside the ? The is updated dynamically and maybe the server side doesn't get the updated component tree after submission is done?

Thanks in advance.

1

1 Answers

3
votes

This is because the p:dataTable is a repeated component and during view build time there is only one calendar in the view root. It has the id someForm:someDataTable:someCalendar.

Only during view render time the table rows are created and the row-dependent ids generated.

You should use JSF build-in validation facilities to check your dates:

in the view:

<p:calendar id="someCalendar" value=#{element.date} 
            validator="#{BackinBean.validateDate}"/>
<p:message id="someCalendarMessage" for="someCalendar"/>

(someCalendar in the for attribute is sufficient)

and in the backing bean:

public void validateDate(
               FacesContext context, 
               UIComponent component, 
               Object value) throws ValidatorException {

        if (/* date is not valid */) {
            throw new ValidatorException(
               new FacesMessage("Date is not valid"));
        }

}

The FacesMessage from the validation method will automatically be displayed in the correct table row.