PreRenderView incrementally called on every postback - jsf-2

I have an issue with the order and number of executions of an f:event type="preRenderView".
During my search here I found as usual answers from BalusC in this and this post related to my problem - still it leaves two questions for me:
When I put one f:event type="preRenderView" in the template file (for managing common tasks like checks about the user state which applies for all my views) and another f:event type="preRenderView" in each view (for handling view specific initializations), I wonder why the listener method from the view is called before the one from the template.
When I put the whole <f:metadata><f:event [..] /></f:metadata> after ui:define as suggested, it gets called twice after redirecting to that page from the login page, but when I put it one level higher after ui:composition it only gets called once.
Update: Example
The following example demonstrates the behaviour above:
This is the template file template_test.xhtml, containing a listener for preRenderViewevent calling a common method in a handler for all views:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xml:lang="de" lang="de" xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head>
<link rel="stylesheet" type="text/css" href="../resources/css/style.css" />
</h:head>
<h:body>
<f:event type="preRenderView" listener="#{testHandler.initCommon()}" />
<div id="content">
<ui:insert name="content" />
</div>
</h:body>
</html>
This is the view file test.xhtml, containing also a listener for preRenderViewevent calling a view specific method in a handler and a command button redirecting via a handler method:
<?xml version="1.0" encoding="UTF-8"?>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
template="template_test.xhtml">
<ui:define name="content">
<f:metadata>
<f:event type="preRenderView"
listener="#{testHandler.initIndividual()}"></f:event>
</f:metadata>
<h:form>
<h:commandButton value="Redirect" action="#{testHandler.redirect()}" />
</h:form>
</ui:define>
</ui:composition>
This is the handler class TestHandler.java containing the 3 methods:
package test;
import java.io.Serializable;
import javax.enterprise.context.SessionScoped;
import javax.inject.Named;
#Named
#SessionScoped
public class TestHandler implements Serializable {
private static final long serialVersionUID = -2785693292020668741L;
public void initCommon() {
System.out.println("Common init called.");
}
public void initIndividual() {
System.out.println("Init for individual page called.");
}
public String redirect() {
return "test/test.xhtml?faces-redirect=true";
}
}
Now, this is what I see in my tomcat log when requesting the test page:
Init for individual page called.
Common init called.
Init for individual page called.
This shows no. 1, that the event handler from the view is called before the one from the template and no. 2, that the event handler from the view is called twice.
It also shows a 3rd point (that's why I included a button with a redirect to the same page) showing what happens if the page gets requested by redirect - the individual page gets called even more times:
Init for individual page called.
Common init called.
Init for individual page called.
Init for individual page called.
Both no. 2 and 3 can be prevented by either putting the whole metadata section above the ui:define or by adding a dummy parameter to the view's metadata section which is not included in the URL:
<f:metadata>
<f:viewParam name="dummyToDenySecondRedirect" />
<f:event type="preRenderView"
listener="#{testHandler.initIndividual()}"></f:event>
</f:metadata>
Can someone tell me the reason for those cases?

I can reproduce it. This is caused by the presence of /WEB-INF/beans.xml and implicitly thus CDI. It even occurs when you switch back to standard JSF annotations while keeping the beans.xml file. This is already reported as both issue 1771 and issue 2162. However, due to absence of a concrete WAR file reproducing the issue and low votes, the Mojarra developers didn't bother to look closer at it.
I have reported it once again as issue 2719. The problem can be reproduced with a smaller example:
<!DOCTYPE html>
<html lang="en"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
>
<f:metadata>
<f:event type="preRenderView" listener="#{bean.preRenderView}" />
</f:metadata>
<h:head>
<title>preRenderView fail</title>
</h:head>
<h:body>
<p>On initial request, you'll see the listener being invoked twice instead of only once.</p>
<p>On every postback by the below button, you'll see the listener being invoked once more.</p>
<h:form>
<h:commandButton value="submit" />
</h:form>
<p>Note however that this increments every time you issue the postback.</p>
<p>If you remove <code>/WEB-INF/beans.xml</code> and redeploy, then the issue will disappear.</p>
</h:body>
</html>
and
package com.example;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
#ManagedBean
#RequestScoped
public class Bean {
public void preRenderView() {
System.out.println("preRenderView called");
}
}

A missing resource may also cause the listener to be called twice. I'm using MyFaces 2.2 here:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<f:metadata>
<f:event type="preRenderView" listener="#{testController.update()}" />
</f:metadata>
<h:head>
<script type="text/javascript" src="#{resource['/js/missing.js']}" />
<title>Test</title>
</h:head>
<h:body>
<p>TestController.update() is called twice.</p>
</h:body>
</html>
Obviously, you shouldn't include any missing or obsolete resources in the first place. But let's say you have (by mistake) and your listener gets called twice on and on, you have no chance to find the actual cause of that problem. JSF shouldn't do this.

Related

Using additional components as a parameter to `<ui:include>` [duplicate]

I have 2 basic templates - one with a side menu, and one without - that both ui:include a common page which contains ui:insert tags (templates are largish, so basic example below).
Using Mojarra everything worked ok, but now I have migrated to MyFaces the ui:insert tags are ignored and the content of the related ui:define does not get rendered (i.e. 'Here are my results' is not displayed).
Should I be specifying included-page.xhtml as a template somehow? I tried
<ui:composition template="included-page.xhtml" />
instead of
<ui:include src="included-page.xhtml" />
but lost the CSS.
Hoping someone can suggest a solution :)
Many thanks,
Neil
my-page.xhtml
<ui:composition xmlns:ui="http://java.sun.com/jsf/facelets"
template="/templates/default-template.xhtml">
<ui:param name="title" value="My Title" />
<ui:define name="results">
Here are my results
</ui:define>
</ui:composition>
default-template.xhtml
<!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"></meta>
<title>#{title}</title>
</h:head>
<h:body>
<ui:include src="included-page.xhtml" />
</h:body>
</html>
included-page.xhtml
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets">
<ui:insert name="results">
</ui:insert>
</ui:composition>
The <ui:include> should have been an <ui:decorate>.
<ui:decorate template="included-page.xhtml" />
But if the included-page.xhtml is by itself not reused elsewhere, I wonder why it isn't just been inlined in the master template instead.
See also:
Difference between ui:composition and ui:decorate in Facelets
What is the real conceptual difference between ui:decorate and ui:include?

JSF Bookmarkable URL to update ui:decorate value

Need help here. I'm trying to make my current project bookmarkable. My current design can basically be summed up in this code snippet:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
xmlns:f="http://xmlns.jcp.org/jsf/core">
<f:metadata>
<f:viewParam name="contentUrl" value="#{navigationBean.contentUrl}"/>
</f:metadata>
<h:body>
<ui:composition template="/views/template/template.xhtml">
<ui:define name="leftpane">
<ui:include src="/views/admin/menu_administrator.xhtml"/>
</ui:define>
<ui:define name="rightpane">
<p:growl showDetail="true" sticky="false" />
<ui:decorate template="/views/admin/content/#{navigationBean.contentUrl}.xhtml"/>
</ui:define>
</ui:composition>
</h:body>
</html>
So I have this template to make the site 30/70 look having the "leftpane" contain the menu and the "rightpane" to display the output content. What I want is to be able to change the output in the "rightpane" depending on the URL sent:
www.mysite.com/projectitle/views/admin/Administrator.xhtml?faces-redirect=true&contentUrl=cont_admin_rapptmnttype
Whatever will be constructed in this url: /views/admin/content/#{navigationBean.contentUrl}.xhtml on the "rightpane" also has a corresponding backing bean to generate the needed output
I'm using Primefaces3.5, MyFaces2.0, WAS8.5
Hope someone could help me out on this. Thanks.
UPDATE:
I am using a p:menuitem to set the contentUrl like
<p:menuitem value="Appointment Type" id="cont_admin_rapptmnttype"
ajax="false" outcome="#{navigationBean.currentMode}" >
<f:param name="contentUrl" value="cont_admin_rapptmnttype"/>
</p:menuitem>
But when I click on the menuitem I get a Stackoverflow exception which, as it turns, is caused by:
<ui:decorate template="/views/admin/content/#{navigationBean.contentUrl}.xhtml"/>
Which is the one I'm trying to update.
Here is the recurring exception in the stacktrace:
at org.apache.myfaces.view.facelets.tag.ui.DecorateHandler.apply(DecorateHandler.java:137)
at javax.faces.view.facelets.CompositeFaceletHandler.apply(CompositeFaceletHandler.java:51)
at javax.faces.view.facelets.DelegatingMetaTagHandler.applyNextHandler(DelegatingMetaTagHandler.java:59)
at org.apache.myfaces.view.facelets.tag.jsf.ComponentTagHandlerDelegate.apply(ComponentTagHandlerDelegate.java:324)
at javax.faces.view.facelets.DelegatingMetaTagHandler.apply(DelegatingMetaTagHandler.java:54)
at javax.faces.view.facelets.CompositeFaceletHandler.apply(CompositeFaceletHandler.java:51)
at javax.faces.view.facelets.DelegatingMetaTagHandler.applyNextHandler(DelegatingMetaTagHandler.java:59)
at org.apache.myfaces.view.facelets.tag.jsf.ComponentTagHandlerDelegate.apply(ComponentTagHandlerDelegate.java:324)
at javax.faces.view.facelets.DelegatingMetaTagHandler.apply(DelegatingMetaTagHandler.java:54)
at javax.faces.view.facelets.CompositeFaceletHandler.apply(CompositeFaceletHandler.java:51)
at org.apache.myfaces.view.facelets.tag.ui.CompositionHandler.apply(CompositionHandler.java:150)
at org.apache.myfaces.view.facelets.compiler.NamespaceHandler.apply(NamespaceHandler.java:57)
at org.apache.myfaces.view.facelets.compiler.EncodingHandler.apply(EncodingHandler.java:45)
at org.apache.myfaces.view.facelets.impl.DefaultFacelet.include(DefaultFacelet.java:322)
at org.apache.myfaces.view.facelets.impl.DefaultFacelet.include(DefaultFacelet.java:369)
at org.apache.myfaces.view.facelets.impl.DefaultFacelet.include(DefaultFacelet.java:347)
at org.apache.myfaces.view.facelets.impl.DefaultFaceletContext.includeFacelet(DefaultFaceletContext.java:215)

How to keep JSF flash scope parameters on page reload?

I use flash scope to pass a setting object between #viewscoped contollers. But if I make a page reload on one of them, then the flash map is empty and the setting object is not initialized. Is it possible to keep flash scope on page reload?
My source code to store/retrieve settings:
FistPage.xhtml
...
<p:commandButton value="next"
action="#{firstPageController.transferConfig}"
process="#this" />
...
FirstPageController.java
#ManagedBean(name = "firstPageController")
#ViewScoped
public class FirstPageController {
...
public String transferConfig() {
FacesContext.getCurrentInstance().getExternalContext().getFlash().put("searchConfig", searchConfig);
return "/secondPage.xhtml?faces-redirect=true";
}
...
}
SecondPage.xhtml
...
<h:outputLabel value="value">
<f:event type="preRenderComponent" listener="#{secondPageController.onPageLoad()}"/>
</h:outputLabel>
...
SecondPageController.java
#ManagedBean(name = "secondPageController")
#ViewScoped
public class SecondPageController {
...
public void onPageLoad()
{
flash = FacesContext.getCurrentInstance().getExternalContext().getFlash();
searchConfig = ((SearchFilterConfig) flash.get("searchConfig"));
flash.putNow("searchConfig", searchConfig);
flash.keep("searchConfig");
}
...
}
I use Mojarra 2.1.29
Thanks
I just did some tests in my playground project and realized it's actually possible to keep the state of the flash parameters even if you GET the page again, using {flash.keep}. That's how the JSF docs explain it:
The implementation must ensure the proper behaviour of the flash is preserved even in the case of a <navigation-case> that contains a <redirect />. The implementation must ensure the proper behavior of the flash is preserved even in the case of adjacent GET requests on the same session. This allows Faces applications to fully utilize the Post/Redirect/Get design pattern.
Here you've got a nice basic test case:
page1.xhtml
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:c="http://java.sun.com/jsp/jstl/core">
<h:head />
<h:body>
<h:form>
<h:button id="nextButton" value="Next (button)" outcome="page2.xhtml" />
<c:set target="#{flash}" property="foo" value="bar" />
</h:form>
</h:body>
</html>
page2.xhtml
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html">
<head />
<body>foo = #{flash.keep.foo}
</body>
</html>
Just open the first page and click on the button which will redirect you to the second one. Then refresh the second page as many times as you want and you'll find the parameter persisting.
Tested in Mojarra 2.2.6

Action nested inside ui:repeat recreates viewscoped bean instead of navigating away

I have a h:form with two p:commandButtons. One button is nested inside of ui:repeat inside a component. The button outside of the ui:include seems to navigate properly to the target destination returned by the action method. However the identical button nested inside of ui:include and ui:repeat appears to reinitialize the view scoped bean instead of navigating to the action destination. Does anyone have an explanation and a solution or workaround?
The code is roughly this. mybean is view scoped.
<h:form id="myform">
<p:commandButton value="DoIt" action="#{mybean.doit()}" ajax="true"/> <!-- this works! -->
<ui:include src="/sections/util/mycomp.xhtml">
<ui:param name="backingbean" value="#{mybean}"/>
</ui:include>
</h:form>
Here is the component.
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
...
xmlns:p="http://primefaces.org/ui">
<ui:repeat value="#{backingbean.mylit}" var="item" varStatus="status">
<p:commandButton value="DoIt" action="#{backinbean.doit()}" ajax="true"/> <!-- this doesn't -->
</ui:repeat>
</ui:composition>
Strangely if I reposition the nested p:commandButton inside the ui:component but outside of the ui:repeat, then it works.
Any ideas?
Hi I copied your codes and tried to reproduce the problem but it seems that mine is working OK. By the way, if you want to use that button for navigation probably you should set ajax to false. Below are my codes:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui">
<h:head></h:head>
<h:body>
<h:form id="myform">
<p:commandButton value="DoIt" action="#{backingBean.goToAnotherPage()}" ajax="true"/> <!-- this works! -->
<ui:include src="firstpage.xhtml">
<ui:param name="bb" value="#{backingBean}"/>
</ui:include>
</h:form>
</h:body>
</html>
And here the second page firstpage.xhtml:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui">
<ui:repeat value="#{bb.myList}" var="item" varStatus="status">
<p:commandButton value="DoItInRepeat" action="#{bb.goToAnotherPage()}" ajax="true"/> <!-- this doesn't -->
</ui:repeat>
<ui:debug hotkey="x" />
</ui:composition>
And finally the backing bean:
#ManagedBean
#ViewScoped
public class BackingBean {
private List<String> myList = new ArrayList<String>();
#PostConstruct
public void init(){
myList.add("1");
myList.add("2");
myList.add("3");
}
public String goToAnotherPage(){
return "destpage.xhtml";
}
//Getters and Setters
}

Richfaces is not defined javascript error

When I try to call Richfaces.showModalPanel('id') I am getting Richfaces is not defined javascript error and nothing happening.
In my sample application I have two pages, one is master view and another page is child view. Child view invokes popupPanel in master view using above call. I am not sure what is wrong. Any pointers would be appreciated.
Here are the pages I have:
First page:
<!DOCTYPE html>
<html lang="en"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:rich="http://richfaces.org/rich"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:richext="http://java.sun.com/jsf/composite/richext">
<h:head>
<title>Page Title</title>
</h:head>
<h:body>
<ui:include id="nextPageInclude" src="secondpage.xhtml"/>
<rich:popupPanel id="logoutDialogId"
width="300"
height="50"
autosized="true"
resizeable="false"
moveable="true"
modal="true"
style="border:5px solid #5e81ac; background-color:#dce3ed;">
<h:outputText value="Inside logout window"/>
</rich:popupPanel>
</h:body>
</html>
Second page:
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:a4j="http://richfaces.org/a4j"
xmlns:rich="http://richfaces.org/rich">
<h:head/>
<a4j:outputPanel id='headerLinks' layout="block">
<ul id="sddm">
<li>
</li>
<li>
</li>
<li>
<a4j:commandLink id="logoutLinkId"
value="Logout"
onclick="Richfaces.showPopupPanel('logoutDialogId')"
styleClass="linkLogout"/></li>
</ul>
<div style="clear:both"></div>
</a4j:outputPanel>
</ui:composition>
EDIT: Attached loaded JS screenshot
Thank you,
The issue with the above code is that since RichFaces 4.0 we can't make the old calls to open a popupPanel, the way you have written it is obsolete, try this if you may instead:-
<a4j:commandLink id="logoutLinkId"
value="Logout"
onclick="#{rich:component('logoutDialogId')}.show();"
styleClass="linkLogout"/>
And similarly to hide the popupPanel use
<a4j:commandLink id="Close_Modal"
value="Close Logout"
onclick="#{rich:component('logoutDialogId')}.hide();"
styleClass="linkLogout"/>
Remove the <h:head> from the include composition. It doesn't belong there and would possibly corrupt the generated HTML head. The <h:head> should be declared only once throughout the view and preferably only in the master template.
Another possible cause is that you've a Filter which happens to match the URL pattern of resource requests as well which in turn is not doing its job entirely right. Check HTML source which <script> elements are all generated and press F12 in Firebug/Chrome/IE9 and explore the Net (or Network) tab to see what browser has all retrieved as to JS resources.
Update: the object name is RichFaces with the uppercase F, not Richfaces. Fix it as well.

Resources