How to avoid displaying of FacesMessage multiple times?

I need to display a FacesMessage for this component as shown below, enter image description here

The issue is that it is displayed on the UI multiple times as shown below, enter image description here

Secondly, the date entered was 40.06.2015 which is invalid, hence the FacesMessage, but it got converted into 10.07.2015. I have no idea how to prevent this. Any help is highly appreciated. I know that it can be easily handled with setLenient() on the DateFormat class, but somehow before it is available to me in the backened, the UI component converts it into date of next month.

The validator attached to this component is as follows: enter image description here

So, how to avoid this displaying of "Please enter date in correct format" multiple times?

I thought of using h:message rather than h:messages, and in the catch block of the validator method to go like this

FacesContext.getCurrentInstance().addMessage("formId:aboveCompId", message);

but nothing gets displayed on UI. Any suggestions?

Upvotes: 0

Views: 1542

Answers (1)

BalusC
BalusC

Reputation: 1108632

There are at least two problems with this approach.

  1. You're binding the component to a bean property. The symptoms suggest that the bean is not request scoped. This is a very bad idea. UI components are inherently request scoped and should not be bound as a property of a bean in a broader scope, else JSF will reuse them instead of creating a new one. If you continue doing so, all tag handlers (including validator bindings) will run over and over on the very same UI component instance across requests on same bean and thus accumulate with every postback (you would see an increasing amount of messages on every postback on the same view, caused by the very same validator being re-attached to the very same component instance).

  2. You're in the validator manually adding a faces message instead of throwing a ValidatorException with therein the faces message. So the JSF lifecycle incorrectly continues after validations phase without aborting it as per the specification.

See also:


Coming back to the concrete functional requirement.

  1. As to non-lenient date conversion, just explicitly use <f:convertDateTime>. The converter message can if necessary be customized via converterMessage attribute of the input component.

  2. As to date range validation, just wait until the converter is finished and grab the right Date as value and then compare by Date#before() or Date#after().

So, in a nutshell, this should do it for you:

private Date startDate;
private Date endDate;
<t:inputCalendar id="startDate" binding="#{startDateComponent}" value="#{bean.startDate}" 
    renderAsPopup="true" renderPopupButtonAsImage="true"
    popupDateFormat="dd.MM.yyyy" popupTodayDateFormat="dd.MM.yyyy"
    converterMessage="Please enter date in correct format"
>
    <f:convertDateTime pattern="dd.MM.yyyy" />
</t:inputCalendar>

<t:inputCalendar id="endDate" value="#{bean.endDate}"
    renderAsPopup="true" renderPopupButtonAsImage="true"
    popupDateFormat="dd.MM.yyyy" popupTodayDateFormat="dd.MM.yyyy"
    converterMessage="Please enter date in correct format"
>
    <f:convertDateTime pattern="dd.MM.yyyy" />
    <f:validator validatorId="dateRangeValidator" />
    <f:attribute name="startDateComponent" value="#{startDateComponent}" />
</t:inputCalendar>

Where dateRangeValidator is a true and reusable @FacesValidator which can be found in the 2nd "See also" link below. Do note that the first component is bound to the view and absoutely not to a bean, and that the validation is not tight coupled to a backing bean.

See also:

Upvotes: 5

Related Questions