JSF commandbutton ajax: how to capture the success/fail event - ajax

my current code.
<h:form>
<h:panelGroup id="messagePanel" layout="block">
<h:messages errorStyle="color: red" infoStyle="color: green" layout="table"/>
</h:panelGroup>
<h:panelGrid columns="2">
// some form input stuff here..
</h:panelGrid>
<h:commandButton class="register-btn" action="#{accountController.create}" value="#{bundle.Register}">
<f:ajax event="action" execute="#form" render="messagePanel"/>
</h:commandButton>
</h:form>
messagePanel is where the validation errors displays.
I want to know how to capture the success event.
[done] if user input some incorrect values, it does an ajax validation and displays the incorrect values
[problem] if success it should redirect to another page.
**updated
create method
public String create() {
try {
getFacadeUser().create(currentUser);
JsfUtil.addSuccessMessage(ResourceBundle.getBundle("/Bundle").getString("AccountCreated"));
return prepareCreate();
} catch (Exception e) {
JsfUtil.addErrorMessage(e, ResourceBundle.getBundle("/Bundle").getString("PersistenceErrorOccured"));
return null;
}
}
public String prepareCreate() {
current = new Account();
selectedItemIndex = -1;
return "index";
}
i'm using JSF 2.1

This is not correct way to do redirection with AJAX request. You should use ExternalContext.redirect() instead:
FacesContext.getCurrentInstance().getExternalContext().redirect("yourUrl");
In that way you will receive partial response from server to, which will do redirection:
<partial-response>
<redirect url="yourUrl">
</redirect>
</partial-response>
String which you returned in this method is irrelevant, you can even return null.

Related

Why does PrimeFaces 5.3 not call my listener function when I catch the "blur" and "focus" events?

My intention was to show information on filling a text area component. When it gets the focus I show the info, when it loses the focus I clear the info. I do not want to proccess any input value just catch the focus and blur events and call the listener and show/clear the message.
I have read BalusC's comment on conditional rendering so I put my conditional text message to an "always rendered" JSF component.
My "always rendered" f:outPutPanel component is shown in the generated XHTML code but my listener function is never called. As far as I know the method signature of primefaces listener is just void somefunction() not like in jsf ajax listener.
I also read BalusC's comment about including #this for the proccess attribute but in my case it seems not to be reasonable as I do not want to catch any input values.
I am newbie to JSF and primefaces so any help is appreciated.
My relevant view snippet:
<h:form>
<h:panelGroup layout="block" id="info">
<h:outputText rendered="#{ebookController.infoMessage != null}" value="#{ebookController.infoMessage}"/>
</h:panelGroup>
....
<p:inputTextarea id="description" styleClass="form-control vspace" required="true" requiredMessage="Kérlek, add meg az e-könyv rövid leírását" value="#{ebookController.newEbook.description}" rows="20" cols="30" counter="display" maxlength="500" counterTemplate="{0} karakter lehet még" autoResize="false" validatorMessage="Az e-könyv leírása maximum 500 karakterből állhat">
<f:validateLength maximum="500"/>
<p:ajax event="focus" process="#none" update="info" listener="#{ebookController.setTextAreaInfoMessage()}"/>
<p:ajax event="blur" process="#none" update="info" listener="#{ebookController.clearInfoMessage()}"/>
</p:inputTextarea>
<h:outputText id="display" />
</h:form>
My relevant java code:
#Named(value = "ebookController")
#SessionScoped
public class EbookController implements Serializable {
private String infoMessage;
public String getInfoMessage() {
return infoMessage;
}
public void setInfoMessage(String infoMessage) {
this.infoMessage = infoMessage;
}
public void setTextAreaInfoMessage(){
setInfoMessage("Tipp: Az e-könyved bemutatása során a fontos részeket emeld ki, és tagold a szöveget bekezdésekkel. Ha egy bekezdés végére értél, csak egy ENTER-t üss!");
}
public void clearInfoMessage(AjaxBehaviorEvent e){
setInfoMessage("");
}
....
}
Solution 1 : User f:ajax
<f:ajax immediate="true" event="focus" process="#none" render="info"
listener="#{ebookController.setTextAreaInfoMessage()}" />
<f:ajax immediate="true" event="blur" process="#none" render="info"
listener="#{ebookController.clearInfoMessage()}" />
Managed Bean
public void setTextAreaInfoMessage() {
System.out.println("setTextAreaInfoMessage");
setInfoMessage(
"Tipp: Az e-könyved bemutatása során a fontos részeket emeld ki, és tagold a szöveget bekezdésekkel. Ha egy bekezdés végére értél, csak egy ENTER-t üss!");
}
public void clearInfoMessage() {
System.out.println("clearInfoMessage");
setInfoMessage("");
}
Reference Problem with h:form and p:ajax

Redirect on ViewExpiredException in AJAX request in JSF 2 [duplicate]

This question already has answers here:
Authorization redirect on session expiration does not work on submitting a JSF form, page stays the same
(2 answers)
Closed 7 years ago.
When my session is expired in my Java EE 7, JSF web app.
I get a ViewExpiredException in ajax requests.
I would like to redirect to a page where it shows the user that the session is expired.
I tried browsing google and stackoverflow for a solution, but I didden't have any luck to get it to work with how I want it.
UPDATE:
I tried the solution posted # Session timeout and ViewExpiredException handling on JSF/PrimeFaces ajax request
It did work at my login page, when using the login_submit button.
<ui:composition
xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
xmlns:h="http://xmlns.jcp.org/jsf/html"
template="./../templates/login_template.xhtml">
<ui:define name="title">
<h:outputText value="#{bundle.login_title}"/>
</ui:define>
<ui:define name="content">
<h:outputText escape="false" value="#{bundle.login_message}"/>
<h:form>
<h:panelGrid columns="2" cellpadding="5">
<h:outputLabel for="username" value="#{bundle.login_username}"/>
<p:inputText id="username" type="text" value="#{authBean.username}" label="username"/>
<h:outputLabel for="password" value="#{bundle.login_password}"/>
<p:inputText id="password" type="password" value="#{authBean.password}" label="password"/>
<h:outputText value="#{bundle.login_invalid_password}" rendered="#{!authBean.validPassword and authBean.validUsername}"/>
<h:outputText value="#{bundle.login_invalid_username}" rendered="#{!authBean.validUsername}"/>
<p:commandButton value="#{bundle.login_submit}" action="#{authBean.doLogin}"/>
</h:panelGrid>
</h:form>
</ui:define>
</ui:composition>
But it doesn't work with this JSF in a xhtml page that is on a secure page, login page is a public page. For example the following xhtml is on a secure page:
<p:commandButton styleClass="button #{chartBean.isViewButtonActive('MONTH')}" update="dataChart dataTable #form" value="#{bundle.performance_year}" action="#{chartBean.changeModel('MONTH')}" />
This does an AJAX post request, but it gets catched by my #WebFilter. (It also happends with selectOneMenu from Primefaces) This filter checks if an user is logged in if not it redirects them to the login page. But for some reason with the example button I given above it also get catched by the #WebFilter and the ajax requests gets as response redirect specified in the #WebFilter. It doesn't get catched by the ExceptionHandler. The #WebFilter is only applied to secure pages, see below.
#WebFilter(
filterName = "AuthorizationFilter",
urlPatterns = {"/secure/*"},
dispatcherTypes = {DispatcherType.REQUEST, DispatcherType.FORWARD}
)
public class AuthorizationFilter implements Filter {
Does anyone know how to solve this.
I do it like this in the webfilter, and it works fine:
// Check if user logged in, if not redirect to login.xhtml
if (loginBean == null || !((LoginBean) loginBean).isLoggedIn()) {
boolean isAjax = "XMLHttpRequest".equals(req.getHeader("X-Requested-With"));
if (!isAjax) {
res.sendRedirect(req.getContextPath() + "/login.xhtml");
} else {
// Redirecting an ajax request has to be done in the following way:
// http://javaevangelist.blogspot.com/2013/01/jsf-2x-tip-of-day-ajax-redirection-from.html
String redirectURL = res.encodeRedirectURL(req.getContextPath() + "/login.xhtml");
StringBuilder sb = new StringBuilder();
sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?><partial-response><redirect url=\"").append(redirectURL).append("\"></redirect></partial-response>");
res.setCharacterEncoding("UTF-8");
res.setContentType("text/xml");
PrintWriter pw = response.getWriter();
pw.println(sb.toString());
pw.flush();
}
} else {
// Let chain of filters continue;
chain.doFilter(request, response);
}
Inspiration

Submitted form values not updated in model when adding <f:ajax> to <h:commandButton>

I'm learning how to use ajax within jsf, I made a page that does actually nothing, an input text that is filled with a number, submitted to the server, call the setter for that element with the value submitted, and display the getter's value.
Here's the simple bean's code:
#ManagedBean(name="helper",eager=true)
public class HealthPlanHelper {
String random = "1";
public void setRandomize(String s){
random = s;
System.out.println("Calling setter");
}
public String getRandomize(){
return random;
}
}
And the jsf page:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<h:head></h:head>
<h:body>
<h:form>
<h:commandButton action="nothing">
<f:ajax render="num"/>
</h:commandButton>
<h:inputText value="#{helper.randomize}" id="num"/>
</h:form>
</h:body>
</html>
As you see, this is a request scoped bean, whenever I click the button the server shows that it creates an instance of the bean, but the setter method is never called, thus, the getter return always "1" as the value of the string.
When I remove the the setter is called normally.
The <f:ajax> processes by default only the current component (read description of execute attribute). Basically, your code is exactly the same as this:
<h:form>
<h:commandButton action="nothing">
<f:ajax execute="#this" render="num"/>
</h:commandButton>
<h:inputText value="#{helper.randomize}" id="num"/>
</h:form>
In effects, only the <h:commandButton action> is been processed and the <h:inputText value> (and any other input field, if any) is completely ignored.
You need to change the execute attribute to explicitly specify components or sections you'd like to process during the ajax request. Usually, in order to process the entire form, #form is been used:
<h:form>
<h:commandButton action="nothing">
<f:ajax execute="#form" render="num"/>
</h:commandButton>
<h:inputText value="#{helper.randomize}" id="num"/>
</h:form>
See also:
Communication in JSF 2.0 - Ajax (asynchronous) POST form
commandButton/commandLink/ajax action/listener method not invoked or input value not updated (point 8)
Understanding PrimeFaces process/update and JSF f:ajax execute/render attributes

Updating a checkbox from a radio button

I am trying to add ajax behavior to selectoneradio with this code:
xhtml:
<h:selectOneRadio id="metalA" converter="metalConverter" value="#{backingBean.metal.metalCode">
<f:selectItems value="#{backingBean.metalCodeRadio}" />
<f:ajax listener="#{backingBean.updateMenu}" event="click" execute="metalA" render="metalTypeMenuA"/>
</h:selectOneRadio>
<p:outputPanel id="panelA">
<h:selectOneMenu id="metalTypeMenuA" converter="metalConverter" value="#{backingBean.order.metal}" rendered="#{teklifIslemleriBean.selectedITip == 1}">
<f:selectItems value="#{backingBean.metalDetailsMenu}" />
</h:selectOneMenu>
</p:outputPanel>
backing bean:
MetalCode selectedMK = null;
public void updateMenu(AjaxBehaviorEvent event) {
System.out.println("Entered to updateMenu method");
if (metal.getMetalKod()!= null) {
electedMK = aMetal.getMetalCode();
}
if (selectedMK != null) {
// metalTypeMenuA Combobox
List<Metal> metalList = aService.getAccToMetalCode(null, selectedMK);
System.out.println("MetalList:" + metalList.size());
metalTypeMenuA.clear();
for (Metal m : metalList) {
metalTypeMenuA.add(new SelectItem(m, "No:" + m.getMetalNo() + " ,Weight: " + m.getWeight();
}
}
}
However it does not even enter to the updateMenu method. instead of click I tried select, change, etc. I also tried to put a wrapper panel and update it instead of checkbox, still no good. What is wrong with above code? Is updating a checkbox with a change in radiobutton doable? Thanks in advance.
JSF 2.0 Primefaces 2.2.1
EDIT:
I added following
<h:message for="metalA" id="messaged"/>
<f:ajax listener="#{backingBean.updateMenu}" event="click" execute="metalKoduA" execute="metalA" render="messaged orderPG2"/>
orderPG2 is a wrapper around checkbox. But still I can get any error message in h:message or any ajax behavior is happening.
The render attribute of <f:ajax> should not point to a component which is by itself conditionally server-side rendered by rendered attribtue. Let it point to the closest parent which is always rendered instead.
<f:ajax listener="#{backingBean.updateMenu}" render="panelA" />
(note that I removed event="click" and execute="metalA" as those are the defaults already)
If that still doesn't work, then you'd need to read the server logs for any missing faces messages. Big change that you'll see a Validation Error: "Value is not valid" or perhaps a conversion error. To prevent those messages from being missed during ajax rendering, ensure that you're using <h:message> and/or <h:messages> the right way and that you also include them in the render of the <f:ajax>.
<h:selectOneRadio id="metalA" ...>
...
<f:ajax ... render="metalAmessage panelA" />
</h:selectOneRadio>
<h:message id="metalAmessage" for="metalA" />

JSF 2 f:ajax lifecycle problem

The problem is, that if a property is changed during an f:ajax request and a binded panelGroup should be newly created depending on that changed value, the old value is used.
This code will explain the problem.
Here is the backingbean TestBean:
public String getFirst() {
return first;
}
public void setFirst(String first) {
this.first = first;
}
public String getLast() {
return last;
}
public void setLast(String last) {
this.last = last;
}
public String getName(){
return first+" "+last;
}
public void setDynamicPanel(HtmlPanelGroup panel){ }
public HtmlPanelGroup getDynamicPanel(){
Application app = FacesContext.getCurrentInstance().getApplication();
HtmlPanelGroup component = (HtmlPanelGroup)app.createComponent(HtmlPanelGroup.COMPONENT_TYPE);
HtmlOutputLabel label1 = (HtmlOutputLabel)app.createComponent(HtmlOutputLabel.COMPONENT_TYPE);
label1.setValue(" --> "+getFirst()+" "+getLast());
component.getChildren().add(label1);
return component;
}
and now the jsf/facelet code:
<h:form id="form">
<h:panelGrid columns="1">
<h:inputText id="first" value="#{testBean.first}" />
<h:inputText id="last" value="#{testBean.last}" />
<h:commandButton value="Show">
<f:ajax execute="first last" render="name dyn" />
</h:commandButton>
</h:panelGrid>
<h:outputText id="name" value="#{testBean.name}" />
<h:panelGroup id="dyn" binding="#{testBean.dynamicPanel}" />
</h:form>
After the page was initially loaded the outputText and panelGroup shows both "null" as first and last. But after the button is pressed, the outputText is updated well, but the the panelgroup shows again only "null". This is due to the problem, that the "binded method" dynamicPanel is executed before the update of the first and last properties.
how can workaround this behaviour or what is wrong with my code?
If you add the attribute immediate="true" to your input elements, the values will be applied during the "Apply Request Values" phase, and hence be present before your action executes. You may or may not need the immediate attribute set to true on the commandButton as well.

Resources