Reputation: 14126
I need to display a FacesMessage
for this component as shown below,
The issue is that it is displayed on the UI multiple times as shown below,
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:
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
Reputation: 1108632
There are at least two problems with this approach.
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).
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.
Coming back to the concrete functional requirement.
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.
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.
Upvotes: 5