AJAX onSubmit validation in JSF 2.0 - ajax

I've started learning JSF2.0, and have come across a problem. Any advice on how to proceed would be welcome.
I have renamed form elements and classes for simplicity sake.
I have a form, for example:
<h:form id="frmSearch">
<h:inputText id="dataPoint1" value="#{bean.dataPoint1}"/>
<div id="dataPoint1Error" class="msgError">Value not found in database.</div>
<h:inputText id="dataPoint2" value="#{bean.dataPoint2}"/>
<div id="dataPoint2Error" class="msgError">Value not found in database.</div>
<h:commandButton action="#{bean.validate}" type="submit" value="Search"/>
</h:form>
The CSS class "msgError" keeps the element hidden by default.
I would like to basically have a method in the "bean" class that validates the input by checking against the database, then if the value isn't found, unhide the error message, or if it is found, then execute another method which performs the actual functionality.
In my head, it would work sort of like this in the Java (forgive any syntax errors, just typing as I think):
#ManagedBean
public class Bean {
private String dataPoint1 = "";
private String dataPoint2 = "";
public boolean validate() {
if(dao.fieldExists(this.dataPoint1) && dao.fieldExists(this.dataPoint2)) { //check the database
performFunctionality();
return true;
}
else {
return false; //and show error div on screen
}
}
public void performFunctionality() {
//do whatever
}
//getters and setters
}
Any advice would be very welcome!
Thanks!

You're not utilizing JSF builtin validation facilities. Make use of it.
Here's how it can look like:
<h:form id="frmSearch">
<h:inputText id="dataPoint1" value="#{bean.dataPoint1}" validator="#{bean.validateDataPoint}" />
<h:message for="dataPoint1" />
<h:inputText id="dataPoint2" value="#{bean.dataPoint2}" validator="#{bean.validateDataPoint}" />
<h:message for="dataPoint2" />
<h:commandButton action="#{bean.performFunctionality}" value="Search">
<f:ajax execute="#form" render="#form" />
</h:commandButton>
</h:form>
with
public void validateDataPoint(FacesContext context, UIComponent component, Object convertedValue) {
if (!dao.fieldExists((String) convertedValue)) {
throw new ValidatorException(new FacesMessage("Value not found in database."));
}
}
That performFunctionality() must be executed by the command button's action method.
When validation fails (i.e. ValidatorException is been thrown), then the message will be displayed in the <h:message> associated with the input component and the action method won't be invoked. The validator attribute can alternatively also point to a fullworthy class which implements javax.faces.validator.Validator. The <f:ajax> is been added to make it an ajax submit.
See also:
How to perform validation in JSF, how to create a custom validator in JSF
Wherever you've learnt JSF, make sure that you've also read the chapters about conversion and validation. Don't think too much the PHP/ASP/JSP/jQuery way. JSF is a full fledged component based MVC framework.

Related

Trying to call ajax listener method via onevent="#{checkIfUsernameAvailable}"

I have a jsf page and an input field. When the event of this input field being blurred, I would like the method checkIfUsernameAvailable() of my ManagedBean to be called. Then the image should be rendered. The problem is that that method is either never called or just not found, no matter what I do. So could someone tell me how I should do it ?
My code here doesn't work, obviously because I never call the method checkIfUsernameAvailable in my jsf. I'm sure the answer is simple but I tried so much and I just don't find it. So I removed my tried calls to this method in the code so it's without errors.
on the f: ajax i put
JSF:
<h:inputText id="username" required="true" value="#{subscribeUser.user.username}">
<f:ajax event="blur" render="usernameCheck"}"></f:ajax>
</h:inputText>
<h:panelGroup id="usernameCheck" >
<h:graphicImage value="resources/images/success_indicator.png" rendered="#{subscribeUser.isIndicatorVisible.usernameSuccess}">
</h:graphicImage>
<h:outputText id="usernameError" value="#{subscribeUser.isIndicatorVisible.usernameSuccess}"/>
</h:panelGroup>
So you see subscribeUser.isIndicatorVisible.usernameSuccess should always be false. I would like that when the input field is blurred that I'd call checkIfUserAvailable() so then it would be true and my image would then be rendered.
ManagedBean:
public class SubscribeUser {
private User user;
private Map<String, Boolean> isIndicatorVisible;
#EJB
Userpersistence up;
public SubscribeUser() {
this.user = new User();
this.isIndicatorVisible = new HashMap<>();
this.isIndicatorVisible.put("usernameSuccess", false);
//...
}
public void checkIfUsernameAvailable() {
this.isIndicatorVisible.replace("usernameSuccess", true);
}
//getters & setters
}
You need the listener attribute.
<f:ajax event="blur" listener="#{subscribeUser.checkIfUsernameAvailable()}" render="usernameCheck"}" />
See also:
Java EE 7 tutorial - Sending an ajax request
By the way, validation is usually done by a normal validator, not an action method. But I gather that you still need to learn about that part.
See also:
JSF 2.0 validation in actionListener or action method

get model value on f:ajax or a4j:ajax listener method

This is my first post on SO.
I am using JSF2 with Richfaces4 and I have the following problem:
Depending the value of a drop down menu I want some input fields in a panel to be disabled and not required otherwise those fields should be enabled and required.
I have the following in my xhtml
<h:selectOneMenu value="#{backingBean.field}" id="ResponseType">
<f:selectItems value="#{backingBean.responseTypes}" />
<f:ajax event="change" execute="#this" render="myPanel" listener="#{backingBean.responseTypeValueChange}" immediate="true"></f:ajax>
</h:selectOneMenu>
<rich:panel id="myPanel">
<h:inputText id="input1" label="label1" value="#{backingBean.input1}" required="#{not backingBean.flagDisabled}" disabled="#{backingBean.flagDisabled}" />
<h:inputText id="input2" label="label2" value="#{backingBean.input2}" required="#{not backingBean.flagDisabled}" disabled="#{backingBean.flagDisabled}" />
<h:inputText id="input3" label="label3" value="#{backingBean.input3}" required="#{not backingBean.flagDisabled}" disabled="#{backingBean.flagDisabled}" />
<h:inputText id="input4" label="label4" value="#{backingBean.input4}" required="#{not backingBean.flagDisabled}" disabled="#{backingBean.flagDisabled}" />
</rich:panel>
My backing bean is a Spring bean and the code is:
public class BackingBean {
private boolean flagDisabled;
private String field;
// getters and setters
public List<SelectItem> getResponseTypes() {
...
// returns values [1: Positive], [2: Negative]
}
public void responseTypeValueChange(AjaxBehaviorEvent event) {
flagDisabled = "2".equals(field);
}
}
My problem is that when the responseTypeValueChange method is invoked the field variable holds the value from the previous request. So I always get the exact opposite behavior.
I have also tried with a4j:ajax but I get the same results.
Then i changed the method to get the submittedValue from the event argument like this:
public void responseTypeValueChange(AjaxBehaviorEvent event) {
if (event.getSource() instanceof HtmlSelectOneMenu) {
HtmlSelectOneMenu source = (HtmlSelectOneMenu) event.getSource();
flagDisabled = "2".equals(source.getSubmittedValue());
}
}
The above works but how I can update the flagDisabled value and THEN invoke the method?
I feel that my solution is not the best. It is actually a hack.
Thank you.
After so much time and while investigating another matter concerning the JSF validation I figured out how to properly invoke the method without using something like:
if (event.getSource() instanceof HtmlSelectOneMenu) {
HtmlSelectOneMenu source = (HtmlSelectOneMenu) event.getSource();
flagDisabled = "2".equals(source.getSubmittedValue());
}
In the <h:selectOneMenu> I added the attribute execute="#this" in order to include only this element in the ajax request.
Strange thing is that I had it in my example here but not in the actual code.
Sorry for the misleading post guys.
BTW: This has nothing to do with the scope of the managed bean. The bean is session scoped but I created even a custom View scope for Spring and even used the JSF #ViewScope without any results.

JSF 2 <f:ajax> with page navigation

My requirement is to trigger and ajax request upon the button click and show validation errors with out page refresh. Also if there is no error, navigate to second view. Below is the code im trying. Im using jsf 2.1.7 with Jboss 7.1.1 final.
<h:form>
<h:inputText value="#{helloBean.name}"></h:inputText>
<h:commandButton value="Welcome Me" action="#{helloBean.goToWelcome}">
<f:ajax event="click" listener="#{helloBean.goToWelcome}"></f:ajax>
</h:commandButton>
</h:form>
HelloBean.java
#ManagedBean
#SessionScoped
public class HelloBean implements Serializable {
public String goToWelcome(){
System.out.println("in goToWelcome");
return "welcome";
}
}
I have a welcome.xhtml in the same folder as above xhtml and i can see the goToWelcome() method also being fired but the navigation does not happen. i assume its because as per the spec listener attribute should have a method with void return type and the returned string from goToWelcome() is ignored. So is there any way to achieve my requirement. Any kind of help would be highly appreciated. Thanks.
Basically, you need to return a navigation case outcome from an action method to do navigation. Note that AJAX listener is incapable to do navigation, at least directly. If you don't want to perform navigation, you could just return null from your action method. Also, navigation won't happen if there are conversion/validation errors, as well as your action method won't be called. For this reason you need to assign a bunch of <h:message>, or a global <h:messages> to display the error messages.
To combine it, the following suffices to achieve your functionality.
The view:
<h:form>
<h:messages id="messages">
<h:inputText value="#{helloBean.name}" />
<h:commandButton value="Do AJAX validation and navigate if necessary" action="#{helloBean.goToWelcome}">
<f:ajax execute="#form" render="messages" />
</h:commandButton>
</h:form>
The bean:
#ManagedBean
#ViewScoped
public class HelloBean implements Serializable {
public String goToWelcome(){
//do business job
if(/* some condition met */) {
return null;
} else {
return "nextpage";
}
}
}
Related reading on your topic
JSF f:ajax listener vs commandButton action;
How to use both Navigation Rule and f:ajax;
Communication in JSF 2.0, section "Ajax validation".
You probably need to redirect the page (assuming you don't have validation errors, it should work)
return "nextpage.jsf?faces-redirect=true";

JSF 2.0; Validator tag "disabled" depends on value from page

In my jsf application i want to validate a field which should only be validated, when one option in a SelectOneRadio is checked.
I found out, that <f:validator> has an attribute, called "disabled".
Can i use this, to check the value from another field?
I tried, but i haven't access to the value from my bean.
<h:selectOneRadio value="#{myBean.checkedSelectOneRadioValue}">
<f:selectItems value="#{myBean.valuesForSelectOneRadio}" />
</h:selectOneRadio>
<f:validator validatorId="myValidator" disabled="#{myBean.checkedSelectOneRadioValue == 'TEST'}" />
Is there any way to reach that without writing own validatorhandler?
Thanks!
The <f:validator> is a tag handler, not an UI component. All its attributes are per definition evaluated during view build time, not during view render time. The view build time is that moment when the XHTML file is been parsed into a JSF component tree as available by context.getViewRoot(). The very same view is usually reused across postbacks to the same view by returning null/void in (ajax) actions.
So you can't let a tag handler attribute depend on a render time attribute which can change during a postback request. One of the ways is to perform that check inside the custom validator itself.
E.g.
<h:inputText>
<f:validator validatorId="myValidator" />
<f:attribute name="radio" value="#{myBean.checkedSelectOneRadioValue}" />
</h:inputText>
with
#Override
public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
if (!"TEST".equals(component.getAttributes().get("radio"))) {
return;
}
// Perform actual validation here.
}
You can alternatively also use OmniFaces <o:validator> instead. It extends the standard <f:validator> with request based evaluation of EL in attributes.
<h:inputText>
<o:validator validatorId="myValidator" disabled="#{bean.checkedSelectOneRadioValue == 'TEST'}" />
</h:inputText>
See also the showcase example and the source code from which an extract of relevance is posted below:
#Override
public void apply(FaceletContext context, UIComponent parent) throws IOException {
if (!ComponentHandler.isNew(parent)) {
return;
}
final javax.faces.validator.Validator validator = createValidator(context);
final RenderTimeAttributes attributes = collectRenderTimeAttributes(context, validator);
final ValueExpression disabled = getValueExpression(context, "disabled", Boolean.class);
((EditableValueHolder) parent).addValidator(new javax.faces.validator.Validator() {
#Override
public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
if (disabled == null || Boolean.FALSE.equals(disabled.getValue(context.getELContext()))) {
attributes.invokeSetters(context.getELContext(), validator);
validator.validate(context, component, value);
}
}
});
}
With JSF 2.0 you can use f:ajax for a partial submit. Add this tag to your h:selectOneRadio:
<h:selectOneRadio value="#{myBean.checkedSelectOneRadioValue}">
<f:ajax render="idOfInputText"/>
<f:selectItems value="#{myBean.valuesForSelectOneRadio}" />
</h:selectOneRadio>
...
<h:inputText id="idOfInputText">
<f:validator validatorId="myValidator"
disabled="#{myBean.checkedSelectOneRadioValue eq 'TEST'}" />
</h:inputText>
Replace the renderattribute content with the real id of your input field with the validator. This assumes that the selectOneRadio and the inputText are inside the same NamingContainer.
To avoid extended discussions in comments, i will provide my suggestions as an answer to discuss it further...
At first it should be
disabled="#{myBean.checkedSelectOneRadioValue == 'TEST'}
or
disabled="#{myBean.checkedSelectOneRadioValue eq 'TEST'}
Additional, at least in ICEFaces (and MyFaces should have this function, too), you may use:
<h:selectOneRadio value="#{myBean.checkedSelectOneRadioValue}" partialSubmit="true">
<f:selectItems value="#{myBean.valuesForSelectOneRadio}" />
</h:selectOneRadio>
This should force an ajax request after changing the value of selectoneradio and the validator-disabled check should be able to get it from the bean.
If that does not work, there may be autoSubmit or similar in MyFaces...

JSF - Pass a parameter on ajax call - What's wrong on this code?

I need to pass a parameter to a bean when i do an ajax call.
My bean is this :
#ManagedBean
#RequestScoped
public class Selector {
#ManagedProperty(value="#{param.page}")
private String page;
#PostConstruct
public void init() {
if(page==null || page.trim().isEmpty()) {
this.page="homepage";
}
System.out.println(this.page);
}
public String getPage() { return page; }
public void setPage(String page) { this.page=page; }
}
And, when i do the ajax call, i need (due to the fact that i want to render a different context) the page parameter. So i've done this :
// in this moment selector.page = articles
<h:inputHidden value="#{selector.page}" id="page" />
<h:commandLink>
<f:setPropertyActionListener target="#{articlesSelector.order}" value="1" />
<f:ajax event="click" render=":articlesContent"/>
<h:graphicImage value="img/arrow_up.png" alt="Arrow Up"/>
</h:commandLink>
But, on the Apply request phase, the page still "homepage". It should get the page-parameter from the request, apply it to the Component tree and render the "articles" context. Why doesnt happens?
Cheers
Because the value of <h:inputHidden> is only set during update model values phase. This is indeed an unintuitive behaviour which existed for long in JSF. I've ever reported an issue about this, but this was closed as "by design".
There are several ways to fix this, among others the view scope. In your particular case, you can use <f:param> instead of <h:inputHidden>:
<h:commandLink>
<f:param name="page" value="#{selector.page}" />
<f:setPropertyActionListener target="#{articlesSelector.order}" value="1" />
<f:ajax event="click" render=":articlesContent"/>
<h:graphicImage value="img/arrow_up.png" alt="Arrow Up"/>
</h:commandLink>
It will then be available as request parameter #{param.page} and in your request scoped bean thus be set as #ManagedProperty.

Resources