Thursday, January 4, 2007

Dynamic JSF subviews

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.includePage}" />

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.

The trick

You can also access JSF managed beans using the old JSP EL notation ${managedBeanName}! You only have to keep in mind that this doesn't precreate the managed bean automatically when this line is called for the first time. So somewhere in the code before this line you should already have called the managed bean by JSF EL. The following example will work:

<h:panelGroup rendered="#{myBean.includePage != null}">
    <jsp:include page="${myBean.includePage}" />
</h:panelGroup>

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 with a nasty if-else tree.
        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

15 comments:

Bo said...

Hi!
Great job!!
I was thinking..Do you know a way of do this using NetBeans VWP??

Thanks in advance!

BalusC said...

I don't use the visual pack. Writing the code yourself will make a better developer of you.

Paul said...

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?

BalusC said...

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

Paul said...

That worked!
thanks so much.
Paul

BalusC said...

The article is updated with somewhat better codings.

András said...

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.

BalusC said...

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.

András said...

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

JohnnyMa said...

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

Chuck said...

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!

Krishna said...

how to pass parameter to the included jsp file?

BalusC said...

You can use the backing bean for it.

One Winged Angel said...

Thanks for your tutorial. Nowdays I suppose everybody using JSF 1.2 but I have to use 1.1 version due to project requeriments, so maybe you don't reply on this post anymore. I'm having problems using your solution because i'm using it inside an a4j:repeat. I want to create dynamically richfaces panelBarItems inside a panelBar. To do that i'm using the a4j:repeat. This is my code:


< rich:panelBar styleClass="empty">
  < a4j:repeat value="# studyManager.principalStudyTypes}" var="studyTypeBundle" >
    < rich:panelBarItem label="#{studyTypeBundle.studyType.name}">
      < h:panelGroup rendered="#{studyTypeBundle != null}">
        < jsp:include page="${studyTypeBundle.jspFile}"/>
      < /h:panelGroup>
    < /rich:panelBarItem>
  < /a4j:repeat>
< /rich:panelBar>

(spaces inside tags written deliberately to not be recognized as tags by blogger)

I get a null in "${studyTypeBundle.jspFile}". I've tried using "studyTypeBundle.jspFile != null" in the rendered atribute of the panel group too, but got the same results.

¿Any ideas? Thank you again.

neocygnus said...

work!!! but have a problem
components after of include append j_id_1 at end of id

this is very nasty but the validation over components dont redender the message because the for attribute dont equal with the generated id

Sorry for my English