JSF 2 <f:ajax> with page navigation - ajax

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";

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

Form submit in conditionally rendered component is not processed

I have a custom tagfile with a form:
<h:form>
<h:commandButton value="click">
<f:ajax event="click" listener="#{bean[method]}" />
</h:commandButton>
</h:form>
I'm conditionally rendering it by ajax as below:
<h:panelGroup id="test">
<h:form>
<h:commandButton value="click">
<f:ajax event="click" listener="#{backingTest.updateFlag}" render=":test"/>
</h:commandButton>
</h:form>
<h:panelGroup rendered="#{backingTest.flag}">
<my:customtag bean="#{backingTest}" method="printMessage"/>
</h:panelGroup>
</h:panelGroup>
This is the associated backing bean:
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
#ManagedBean
#RequestScoped
public class BackingTest {
private boolean flag = false;
public void printMessage() {
System.out.println("hello");
}
public void updateFlag() {
flag = true;
}
public boolean getFlag() {
return flag;
}
}
When I click the first command button, then the updateFlag() method is properly invoked and the second command button is properly shown. But when I then click the second command button, it never hits the printMessage() method. In the web browser's JS console and HTTP traffic monitor I can see that the click event is successfully fired and that the XHR POST request is successfully being sent.
If I remove the rendered attribute, then everything works as expected.
How is this caused and how can I solve it? I'm using Mojarra 2.1.25.
Your concrete problem is caused by 2 facts:
When JSF needs to decode a form submit action or a submitted input value, then it also checks if the component is rendered or not (as safeguard against hacked/tampered requests).
Request scoped beans are recreated on every HTTP request (an ajax request counts also as one request!).
In your specific case, the rendered condition has evaluated false while JSF needs to decode the form submit action and therefore the non-rendered input/command components are never processed.
Putting the bean in view scope should fix it. Below example assumes JSF 2.x.
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
#ManagedBean
#ViewScoped
And below example assumes JSF 2.2+ with CDI:
import javax.inject.Named;
import javax.faces.view.ViewScoped;
#Named
#ViewScoped
Or, if the techncial requirement is to keep the bean in request scope, then carry around the condition behind rendered attribute in a <o:inputHidden>. Adjust your snippet to include it in the <h:form>.
<o:inputHidden value="#{backingTest.flag}" />
See also:
commandButton/commandLink/ajax action/listener method not invoked or input value not set/updated - point 6
How to choose the right bean scope?

AJAX onSubmit validation in JSF 2.0

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.

JSF ajax commandbutton from multiple forms within same page reinitiliazes the viewscoped bean

changeThe page has 2 forms. In the first form, the ajax-button initializes an attribute of the viewscoped managed bean. In the second form, the ajax-button uses that attribute to do some stuff. Problem is that the method called by the second form button never gets invoked. Instead, the viewscoped bean is re-initialized and when I hit the same button again, of course the attribute is null resulting in NPE.When I put the 2 buttons within the same form, then everything works as expected.Is this normal: should ajax enabled buttons always reside within the same form?
<h:form id="frmDetail">
<h:commandButton id="btn_changePlant" title="#{msg.ttChangePlant}" immediate="true" image="/resources/img/edit.png">
<f:ajax event="click" render=":fsDetailPlant :headerMsg" listener="{assortiment.detailPlantId}"/>
</h:commandButton>
</h:form>
...some other code ...
<h:form id="frmOffers">
<h:commandButton id="btn_offers" title="#{msg.ttOfferPlant}" immediate="true" value="#{msg.btn_offers}">
<f:ajax event="click" render=":fsDetailPlant :headerMsg" listener="{assortiment.changeOffers}"/>
</h:commandButton>
</h:form>
and the managed bean looks like
#ManagedBean
#ViewScoped
public class Assortiment extends BeanObject implements Serializable {
....
public void detailPlantId(AjaxBehaviorEvent actionEvent) {
clear();
plantdetail = facade.findPlantdetail(plantdetailsIdModel.getRowData());
}
public void changeOffers(AjaxBehaviorEvent actionEvent) {
System.out.println("........ Assortiment.changeOffers(AjaxBehaviorEvent actionEvent)");
if (containerItems.isEmpty()) {
SessieUtils.fillPropertyItems(containerItems, PlantProperty.codeValuesList(ECodeType.logistic, "L02"), facade.getLocale());
}
//
if (offersModel == null) {
offersModel = new ListDataModel<OffersDto>(plantdetail.getOffersList());
}
}
It might just be that the listener attributes need the # prefix,
listener="{assortiment.changeOffers}"
should be
listener="#{assortiment.changeOffers}"

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