Switch between subviews in one main page
The goal is to be able to switch between multiple JSP include pages in one main page. There are several ways to achieve this. The easiest way would be the following:
<jsp:include page="#{myBean.currentInclude}" />
But this only works in JSF 1.2 + JSP 2.1, the environment where Unified Expression Language is made available. In older versioned environments the above snippet is not valid.
A most seen solution is to hardcode multiple f:subview and jsp:include tags and use the rendered attribute of the f:subview to render the jsp:include or not.
<f:subview id="includePage1" rendered="#{myBean.currentInclude == 'includePage1'}"> <jsp:include page="includePage1.jsp" /> </f:subview> <f:subview id="includePage2" rendered="#{myBean.currentInclude == 'includePage2'}"> <jsp:include page="includePage2.jsp" /> </f:subview> <f:subview id="includePage3" rendered="#{myBean.currentInclude == 'includePage3'}"> <jsp:include page="includePage3.jsp" /> </f:subview>
Where the getCurrentInclude() method of the backing bean MyBean.java returns the property which page have to be included. One big disadvantage is that you have to hardcode every new include page into the main JSP page.
Another most seen approach is to use multiple h:panelGroup tags and use includes with the f:subview already coded in the include files itself. But this still doesn't remove the disadvantage.
<h:panelGroup rendered="#{myBean.currentInclude == 'includePage1'}"> <jsp:include page="includePage1.jsp" /> </h:panelGroup> <h:panelGroup rendered="#{myBean.currentInclude == 'includePage2'}"> <jsp:include page="includePage2.jsp" /> </h:panelGroup> <h:panelGroup rendered="#{myBean.currentInclude == 'includePage3'}"> <jsp:include page="includePage3.jsp" /> </h:panelGroup>
The trick
You can access request scoped JSF beans using ${requestScope.managedBeanName} and session scoped JSF beans using ${sessionScope.managedBeanName}. You have only to keep in mind that the request scoped managed beans aren't created yet during evaluation of the old JSP EL and that session scoped managed beans aren't created yet during evaluation of the old JSP EL in the first pageview of a fresh new session.
The relevant XML code of the faces-config file, in this example we'll use a session scoped bean:
<managed-bean> <managed-bean-name>myBean</managed-bean-name> <managed-bean-class>mypackage.MyBean</managed-bean-class> <managed-bean-scope>session</managed-bean-scope> </managed-bean>
The relevant code of the main JSP file. Please note the scriptlet on the top, this will precreate the managed bean during the first view in the session, otherwise ${requestScope.managedBeanName} will always return null on every view or ${sessionScope.managedBeanName} will always return null in the first view.
// Check if the bean is already created or not. if (session.getAttribute("myBean") == null) { // First-time initialization of bean not done yet, so do it manually. session.setAttribute("myBean", new mypackage.MyBean()); } // For request scoped beans of course use request.get/setAttribute() instead. <f:view> <html> <head> </head> <body> <h:panelGroup rendered="#{myBean.includePage != null}"> <jsp:include page="${sessionScope.myBean.includePage}" /> </h:panelGroup> </body> </html> </f:view>
Take care: do not use f:subview instead of h:panelGroup. Every include page should have its own f:subview with an unique ID.
The relevant java code of the backing bean MyBean.java should look like:
public String getIncludePage() { if (...) { // Do your thing, this is just a basic example. return "include1.jsp"; } else if (...) { return "include2.jsp"; } else if (...) { return "include3.jsp"; } else { return "default.jsp"; } }
Copyright - There is no copyright on the code. You can copy, change and distribute it freely. Just mentioning this site should be fair.
(C) January 2007, BalusC

13 comments:
Hi!
Great job!!
I was thinking..Do you know a way of do this using NetBeans VWP??
Thanks in advance!
I don't use the visual pack. Writing the code yourself will make a better developer of you.
When I try this I get an error saying:
The value of attribute "page" associated with an element type "jsp:include" must not include the '<' character.
I also had to put the scriptlet within jsp:scriptlet tags instead of the tags you had so it would be well formed xml.
Any ideas?
That is indeed a problem if you declared your page as XML.
Anyway, this article is somewhat outdated. You can also use JSP EL and access a session attribute or even a request attribute. I.e.
jsp:include page="${sessionScope.currentInclude}"
Whereby a JSF backing bean can set it using FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put("currentInclude", "foo.jsp");
That worked!
thanks so much.
Paul
The article is updated with somewhat better codings.
Hi BalusC!
Great job! Partially worked for me. Partially means in JSF 1.2, JSP 2.1, if I use like <jsp:include page="#{myBean.currentInclude}">, I get following error:
"The attributes for a standard action or an uninterpreted tag cannot be deferred expressions."
Any ideas what to do if you have @EJB annotations / EJBs injected by container? If you merely instantiate like new myPackage.MyBean(), EJBs are not injected, at least not on GlassFish v2 b58g, NetBeans 6.0.
About that error message: make sure that you defined the web.xml to be at least version 2.5.
About EJB: I am not fully familiar with EJB 3.0 yet and so also not in a JSF context.
Thanx for the fast answer!
Unfortunately my web.xml looks like:
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
Hi BalusC,
Thank for this great article! I tried to include my page with the following code,
< jsp:include page="#{myBean.currentInclude}" />
< t:outputText value="#{myBean.currentInclude}" />
but I only see my output string and not the include page. Any idea what I did wrong? thanks!
Johnny
Outstanding articles. Thank you for sharing your knowledge.
I am new to the java enterprise development community and am curious why you use jsp as opposed to facelets?
Thanks again!
how to pass parameter to the included jsp file?
You can use the backing bean for it.
Post a Comment