Using JSF Validator - jsf

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.
XHTML Page
<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>
Custom Validator
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();
}
}

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:
validator and view have a cyclic dependency on each other,
there is a need to use hacks (such as "immediate") and low-level APIs,
hard-coding view logic in an unlikely place,
requires much more knowledge and is flaky. For example the logic of acquiring value from calendar might be different depending on whether radio button is before or after calendar in document order.
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".

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>

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

Related

JSF PrimeFaces rendering components

Let's say I have a simple method that, like this:
public String test()
{
return "hello";
}
Now let's say I have the following PrimeFace component:
<p:fieldset styleClass="containers" rendered="#{controller.test()}">
<h2>Testing</h2>
<p:outputLabel for="test" value="Test" />
<p:inputText id="test" />
</p:fieldset>
The method above returns "hello". I would like to dynamically show and hide that fieldSet by comparing the returned value of that method to a field of one of my beans. For instance, on the rendered parameter, I would like to do something like: controller.test() != "some variable" which would return true or false. Am I allow to do that? If not, what is the way of doing it?
Basically the goal is to dynamically show and hide some container by comparing the returned value of a method with a bean property.
Look Like you misunderstood rendered
The rendered Attribute
A component tag uses a Boolean EL expression, along with the rendered
attribute, to determine whether or not the component will be rendered.
If you will check above definition you will know what exactly is the use of this attribute.
More you can see below
The rendered attribute which uses Boolean EL expression indicates
whether a component is currently visible or not. The property is
useful when you want to hide components for specific users or based on
condition. The default value of rendered attribute is true.
<h:outputText value=”mapping” rendered=”Boolean EL expression” />
For example, the commandLink component in the following section of a page is not rendered if the cart contains no items:
<h:commandLink id="check"
...
rendered="#{cart.numberOfItems > 0}">
<h:outputText
value="#{bundle.CartCheck}"/>
</h:commandLink>
With your concrete problem you can do like this
Make a String variable call value
Now create get/set methods for above variable
Now in your test method you can add
public void test(){
value="hello";
}
Bur remember you have call test() method of page load
Now in your Xhtml or Jsf or Jsp page
rendered="#{controller.value != 'hello'}"
Or better way create a Boolean variable and do all the magic of hide and show the component

selectOneMenu sets field to null after being changed

I try to do something that is very similar to this richfaces example. I have a form that describes custom ID validation in case that you have not selected one of the predefined ones, else the form will be disabled. So disabled expression for the form members would go to the next method:
public boolean isPredefinedValidator() {
return !currentProjectRegField.getIdValidation().getIdType().equals(IdValidatorType.NONE);
}
that is invoked like this:
disabled="#{accountHome.isPredefinedValidator()}"
and here is the selector for the predefined validator:
<h:selectOneMenu value="#{accountHome.currentProjectRegField.idValidation.idType}"
rendered="#{!(empty accountHome.currentProjectRegField or empty accountHome.currentProjectRegField.idValidation)}">
<a4j:support event="onchange" reRender="customIdValidator"/>
<s:convertEnum />
<s:enumItem enumValue="NONE" label="#{messages['IdValidatorType_enum.NONE']}"/>
<s:enumItem enumValue="USA_ID" label="#{messages['IdValidatorType_enum.USA_ID']}"/>
<s:enumItem enumValue="MEXICO_ID" label="#{messages['IdValidatorType_enum.MEXICO_ID']}"/>
</h:selectOneMenu>
The issue is, when the method isPredefinedValidator() is invoked on a4j rerender (on disabled EL), I receive NPE.
Caused by: java.lang.NullPointerException
at com.whatever.something.action.AccountHome.isPredefinedValidator(AccountHome.java)
And when I try to debug - turns out that the value that has been set from the selectOneMenu is null.
Does it mean that reRender and setting value to the variable happens async, and there is a race condition? And what is the correct solution for this case?
Some black-magic configuration in the rich:modalPanel that contains the h:selectOneMenu resolved this issue. It goes like this <rich:modalPanel ... domElementAttachment="form">

Reset value to null in primefaces autocomplete event

I have an autocomplete event that fires correctly once a value is selected. I want another event to fire once I erase the value in the textbox and reset the value to null. I was thinking of using the onChange attribute but I was having issues so I reverted back to my original code.
<p:autoComplete id="deviceAuto" dropdown="true" scrollHeight="250"
value="#{summaryReportController.device.nickname}"
forceSelection="true"
completeMethod="#{summaryReportController.deviceComplete}">
<p:ajax event="itemSelect"
listener="#{summaryReportController.handleDeviceSelect}"
update="printThis" />
</p:autoComplete>
public void handleDeviceSelect(SelectEvent event) {
String deviceSelect = event.getComponent().getId();
if (deviceSelect.equalsIgnoreCase("deviceAuto")) {
Device selectedDevice = deviceMgr.getDevicebyNickname(device.getNickname());
setDevice(selectedDevice);
}
updateInterface();
}
When you modify the text content of the AutoComplete textfield, the search method (aka. completeMethod) will be called on the backing bean. You can reset the value to null there if you get an empty string.
Backing Bean
// insert getter and setter for the device property ...
/** Search for devices by name */
public List<String> deviceComplete(String search) {
if (StringUtils.isBlank(search)) {
setDevice(null); // textfield was cleared, reset device value!
return Collections.emptyList();
} else {
// search for devices ...
return deviceNames;
}
}
Note that I used Apache Commons StringUtils.isBlank(String) to check if the string was null or did only contain whitespace characters.
JSF View
In your XHTML file you probably want to listen to any Ajax event to update your view -- or you figure out the event you need (blur, change, whatever) yourself:
<p:autoComplete ...>
<p:ajax event="itemSelect" listener="..." update="..." />
<p:ajax process="#this" update="..." />
</p:autocomplete>
I hope this helps.
An alternative could be something like a "clear" or "reset" button next to the search textfield to make it clear to the user that the value will be cleared.
The default autoComplete minQueryLength attribute equals 1 and your search string will be updated when you deleting it until it has lenght of 1 character.
E.g.:
You entering 'foo' - and this string is provided to search method (updating after entering first character - minQueryLength = 1)
But when you delete search string - it is also updated until it will have length of 1.
Solution:
set attribute minQueryLength="0"
Or:
if you need bigger value add to your autoCompleteMethod(String search) condition:
if (search.length()<={your minQueryLength attribute} ) field = null;
Old question, but I think it worths another view.
The problem with minQueryLenth = 0 or minQueryLenth = 1 is that it can return hundreds of options (and for sure the user won't read all of them to choose one). My solution was as follows.
First of all I need the input to be sent to the server as soon as the user select one of its values (in my use case the user is not allowed to go to next step in a wizard if this value is null or empty). So I put an ajax function triggered in the event of a selected value.
xhtml:
<p:autoComplete
id="someId"
value="#{myViewScopedBean.selectedValue}"
...
...
minQueryLenth="5"
onblur="autoCompleteLostFocus('someId', 'someCommand()')">
<p:ajax
event="itemSelect"
listener="#{myViewScopedBean.newValueSelected}"
process="#this"
update="commandButtonGoToNextStep" />
</p:autoComplete>
<p:remoteCommand
name="someCommand"
actionListener="#{myViewScopedBean.setValueNull}"
update="commandButtonGoToNextStep" />
<p:commandButton
id="commandButtonGoToNextStep"
...
...
disabled="#{myViewScopedBean.selectedValue == null}" />
If the user clean the text, I need to send that value to "myViewScopedBean" and update the component that allows the user to go to the next step. I solved that putting a javascript function that is called when the autocomplete lose focus.
javascript:
function autoCompleteLostFocus(autocompleteId, comand) {
if ($("[id='" + autocompleteId + "_input']").val().trim() == "") {
eval(comando);
}
}
in myViewScopedBean:
public void setValueNull() {
selectedValue = null;
}
I hope it helps. A lot of work, but the behaviour is exactly what I wanted. The reason for the javascript function is that it just send information to the servlet if the value is equals to "", otherwise it does nothing.
From a completely different angle...
Why do you have summaryReportController.device.nickname as a value in autoComplete?
I'd suggest you to use device as a value and specify
var
itemLabel
itemValue
converter
in your autocomplete, while your completeMethod will return list of devices filtered by nickname. Converter is implementation of javax.faces.convert.Converter.
See the POJO case in PF Showcase.

Rich Calendar Validator

I'm new to JSF and I'm sure I'm doing something stupid, but I've been trying different things for days and cant make any progress. I'm trying to do validation when a user types in a date instead of using the rich calendar but for some reason I cant seem to get the validator to fire. The page code is as follows:
<a4j:outputPanel id="responseReleaseDate" rendered="#{appealSearchManager.isVendor}">
<p><h:outputText value="#{messages.ResponseReleaseDate}"/></p>
<rich:calendar id="responseReleaseDateBegin" datePattern="MM/dd/yyyy"
enableManualInput="true"
buttonIcon="/images/calendar_icon.jpg" buttonClass="calendar"
validator="#{appealSearchManager.validateResponseReleaseDateBegin}"
value="#{appealSearchManager.responseReleaseDateBegin}">
</rich:calendar>
<rich:calendar id="responseReleaseDateEnd" datePattern="MM/dd/yyyy"
enableManualInput="true"
buttonIcon="/images/calendar_icon.jpg" buttonClass="calendar"
validator="#{appealSearchManager.validateResponseReleaseDateBegin}"
value="#{appealSearchManager.responseReleaseDateEnd}">
</rich:calendar>
</a4j:outputPanel>
The bean code I'm trying to invoke is as follows:
public void validateResponseReleaseDateBegin(FacesContext facesContext, UIComponent uiComponent, Object value) throws ValidatorException {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("MM/dd/yyyy");
if (value != null && !value.equals("")) {
try {
simpleDateFormat.parse(value.toString());
} catch (ParseException e) {
throw new ValidatorException(new FacesMessage(
FacesMessage.SEVERITY_ERROR,
MessageFormat.format((RootUtils.getCommonBundle().getString(BundleConstants.INVALID_ITEM)), "Response Release Date"),
MessageFormat.format(RootUtils.getCommonBundle().getString(BundleConstants.INVALID_DATE_FORMAT), "Date", "MM/DD/YYYY")));
}
}
}
The wierd thing is that I can reach the validateResponseReleaseDateBegin(...) method using the code below (I know, it doesnt make sense for a text field, it was just for testing purposes). But I never hit the method when I enter input for the rich calendar.
<div class="div30">
<p><h:outputText value="#{messages.ProgramInvoiceId}"/></p>
<h:inputText id="programInvoiceId"
validator="#{appealSearchManager.validateResponseReleaseDateBegin}"
value="#{appealSearchManager.programInvoiceId}"/>
</div>
Any ideas why this validator works in one place and not another?
Thanks!
This makes no sense. The <rich:calendar> will already implicitly convert the String submitted value to Date before setting it as model value. If you enter a date in invalid format, the <rich:calendar> will already throw a ConverterException for that. Its message should already be visible in any <h:messages> or <h:message> component associated with the component.
As conversion runs before validation, your validator is never fired when conversion fails. Even when your validator was fired, the Object value argument in the validator is already of the type java.util.Date. So if your validator was fired, it would always have thrown an exception because Date#toString() does definitely not match MM/dd/yyyy.
I'm not sure why you need this validator. Perhaps you just wanted to supply a custom conversion error message? In that case, you should be using its converterMessage attribute instead.
<rich:calendar ... converterMessage="Invalid date" />
Or, if you really need to "validate" the date format by yourself, implement a custom Converter instead and register it by converter attribute or <f:converter> tag instead.

richfaces text and text area on rerender unable to use keyboard up and down arrow keys to move the cursor

I am using RichFaces 3.3.2 and JSF 1.2.
Scenario:
In my application when the user enters some text in a text field or a text area we have to enable the apply button. For this we are using rerender 'onkeyup' event.
Validation error mesage should be shown when user enters invalid date
JSF Page code:
<h:inputText id="input" required="true" requiredMessage="Value cann't be null"
value="#{client.Value}" validatorMessage="Value should be between 0 and 999999999999.99" valueChangeListener="#{myHandler.onChange}" maxlength="30">
<f:validateDoubleRange minimum="0" maximum="999999999999.99"/>
<a4j:support event="onkeyup" eventsQueue="A4JQueue" reRender="outputPanel_btn_save"></a4j:support>
Apply button code:
<a4j:outputPanel id="outputPanel_btn_save">
<a4j:commandButton value="#{msg.btn_Apply}" id="applyButton" reRender="outputPanel_btn_save" eventsQueue="A4JQueue" disabled="#{myHandler.isApplyButtonDisabled}" styleClass="button" action="#{myHandler.update}">
</a4j:commandButton>
</a4j:outputPanel>
Backing bean code for myHandler.onChange()
MyHandler {
public void onChange(ValueChangeEvent event) {
Iterator<FacesMessage> facesMessages = getFacesContext().getMessages();
boolean isMessagePresent=false;
while(facesMessages.hasNext()){
FacesMessage message = facesMessages.next();
isMessagePresent=true;
break;
}
if (event != null
&& event.getNewValue() != event.getOldValue()&& !isMessagePresent) {
this.isApplyButtonDisabled = Boolean.FALSE;
}
if(isMessagePresent){
this.isApplyButtonDisabled = Boolean.TRUE;
}
}
}
Problem:
When the user enters some text onkeyup event we are rerendering the apply button. Due to rerender keyboard arrow keys are not working as the field is loosing it's focus onKeyup event.
I tried using JS to enable the apply button, when user enters some text. But then JSF validations are not being executed and no validation message are being displayed.
Question:
Can you suggest a way to enable the apply button with out loosing focus on the text field / text area and also JSF validations should be executed / displayed?
Try using focuc attribute on a4j:support. It allows to set focus on a component after Ajax request.

Resources