Reputation: 41
I am using Prime faces 3.4.1 as component framework and JSF 2.0 as the server side framework
Following is my requirement
1) I have a field with label as "Meeting Required". Then I have SelectOneRadio with two options "No" and "Yes" with default value as "No". I am using JSF/HTML component h:SelectOneRadio.
2) I have another field which is Calendar component and this is a primefaces calendar component. When the user selects "Yes" which indicates the "Meeting is required" and the user should select a date from the calendar control.
3) If the user selects "Yes" and does not select a date, then a Validation message should be displayed indicating that the date should be selected.
I created a Custom Validation component and attached to the SelectOneRadio and I am able to see the selected value in the Custom validator. Now, I try to get the value from the Calendar component to check if the value is empty, through UIComponent.getParent().findCompoent("rvmDate"), I get the component but I do not know how to check if the date component is empty or contain any values.
Please help me out to get the date value selected by the user.
Please help me out to resolve the issue. Or is there any other way? Please find the source code.
<h:selectOneRadio id="rvmMeetingOption"
readonly="#{wipMB.rvmMeetingOptionReadOnly}"
value="#{wipMB.requirementsMeeting}"
disabled="#{wipMB.rvmMeetingOptionDisabled}"
validator="#{wipMB.validateRVMDate}"
validatorMessage="Please enter RVM Date>
<f:selectItem itemLabel="No" itemValue="0"></f:selectItem>
<f:selectItem itemLabel="Yes" itemValue="1" ></f:selectItem>
<f:attribute value="#{rvmDateComp}" name="rvmDateComp"></f:attribute>
</h:selectOneRadio>
<p:calendar id="rvmDate"
readonly="#{wipMB.rvmMeetingDateReadOnly}"
disabled="#{wipMB.rvmMeetingDateDisabled}"
readonlyInput="true"
navigator="true" mode="popup"
pattern="dd/MM/yyyy"
value="#{wipMB.rvmDate}"
effect="explode"
yearRange="1900:2500"
style="margin-left:5px"
binding="#{rvmDateComp}"
</p:calendar>
<p:message id="rvmDateMsg" for="rvmDate" display="both" ></p:message>
public void validateRVMDate(FacesContext context, UIComponent component, Object value)
throws ValidatorException
{
String invalidDate;
String rvmOption;
Date rvmDate;
String rvmDt = "";
try
{
FacesContext fc = FacesContext.getCurrentInstance();
rvmOption = value.toString();
DateFormat formatter = new SimpleDateFormat("E MMM dd HH:mm:ss Z yyyy");
UIInput rvmCompDt = (UIInput)component.getAttributes().get("rvmDateComp");
rvmDateId = rvmCompDt.getId();
rvmDt = rvmCompDt.getSubmittedValue() == null ? "" : rvmCompDt.getSubmittedValue().toString();
if (rvmOption.equals("1") && rvmDt.isEmpty())
{
FacesMessage msg = new FacesMessage("RVM date is required");
msg.setSeverity(FacesMessage.SEVERITY_ERROR);
fc.addMessage("rvmDateMsg", msg);
throw new ValidatorException(msg);
}
}
catch (Exception ex)
{
String msg = ex.getMessage();
}
}
Upvotes: 1
Views: 3662
Reputation: 1108537
You first need to remove immediate="true"
from the <p:calendar>
, otherwise it's not processed at all when the radio button is processed.
Then, to check if a string is null or empty, just do
String dt = (String) uiCalendar.getSubmittedValue();
if (dt == null || dt.isEmpty()) {
// dt is null or empty. Throw validator exception depending on the
// current radio button value. Note: you should not catch it yourself!
}
Note that this has nothing to do with JSF. It's just basic Java. Your initial attempt as if (dt == "")
is indeed completely invalid. The String
is an object, not a primitive. The ==
compares objects by reference, not by their internal value. Technically, you should have used if (dt.equals(""))
instead, but the isEmpty()
is nicer.
Unrelated to the concrete problem, a much easier way is to just check the radio button value in the required
attribute of the calendar component. First bind the radio button component via binding
to a variable in the view, then reference its UIInput#getValue()
method in the required
attribute.
<h:selectOneRadio id="rvmMeetingOption" binding="#{rvmMeetingOption}"
readonly="#{wipMB.rvmMeetingOptionReadOnly}"
value="#{wipMB.requirementsMeeting}"
disabled="#{wipMB.rvmMeetingOptionDisabled}">
<f:selectItem itemLabel="No" itemValue="0"></f:selectItem>
<f:selectItem itemLabel="Yes" itemValue="1" ></f:selectItem>
</h:selectOneRadio>
<p:calendar id="rvmDate"
readonly="#{wipMB.rvmMeetingDateReadOnly}"
disabled="#{wipMB.rvmMeetingDateDisabled}"
readonlyInput="true"
navigator="true" mode="popup"
pattern="dd/MM/yyyy"
value="#{wipMB.rvmDate}"
effect="explode"
yearRange="1900:2500"
style="margin-left:5px"
required="#{rvmMeetingOption.value == 1}">
</p:calendar>
Upvotes: 3
Reputation: 12495
In JSF each component is a little MVC stack of its own; there is the Model (stored as value), the Controller (the component object) and View (renderer). Validators and controllers are part of the architecture and are needed to move the values between the model and the view.
While JSF Validators play an important role, it is important only INSIDE this little MVC stack. They were not designed to "validate forms", they are made strictly to "validate component value". Lamentably, the name "validator" makes everyone who comes to JSF think, that each time any validating needs to be done, validator is the solution. Strangely, converters are not so abused.
In your case, building a custom validator created a strange situation, where:
The problems above could be solved, but since they all arise from abusing JSF architecture, I think it would be better to rethink the problem. Since your validation concerns flow of application, it is a perfect fit for the action method, where all the complications will dissolve into a single, simple "if" statement with a conditional "addMessage".
Upvotes: 3
Reputation: 2003
use
UIInput uiCalendar = (UIInput) component.getParent().findComponent("rvmDate");
Date test = uiCalendar.getValue();
if(test==null){
throw ValidatorException
}
test will then have the date filled in or will be null when nothing is chosen in teh date field
Upvotes: 0