Monday, December 31, 2012

JSF 2.x Tip of the Day: Dynamic <ui:include/> with <f:viewParam/>

Introduction

I encountered a situation the other day where I need to include a JSF page based on a parameter passed in via a <f:viewParam>. This seems like a very reasonable kind of idea. I expected to be able to make the <ui:include/> use a dynamically set src parameter using EL from the <f:viewParam>. This is where I went wrong (the idea was good...). The <ui:include/> is a tag handler. It is evaluated on Restore View Phase. The value processing does not take place until the Apply Request Values Phase. This presents a problem since the EL binding for my <ui:include/> is based on the <f:viewParam> which is a UIInput object. So we are out of phase. The page will display the results, but all the AJAX will not work.

A Solution

A solution to the problem involves using static <ui:include/> elements wrapped in <ui:fragment/> elements. This allows the tag handler to resolve the page to include, and then the fragment determines (via late binding) whether to display the page based on the <f:viewParam> passed. The page is supported by a @ViewScoped bean to keep the page in scope.

Code

Here is an example of how to do it.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<?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">
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      >
    <h:head>
        <title>Index</title>
        <f:metadata>
            <f:viewParam name="page" value="#{index.page}"/>
        </f:metadata>
    </h:head>
    <h:body>
        <p>
These examples use static binding on the <ui:include/> and use the the <ui:fragment/> <code>rendered</code>
 
            attribute to determine which page to display. Since these elements are evaluated after the component tree is restored,
 
            the AJAX will work.
        </p>
<ui:fragment rendered="#{index.page eq 'page1'}">
            <ui:include src="page1.xhtml"/>
        </ui:fragment>
        <ui:fragment rendered="#{index.page eq 'page2'}">
            <ui:include src="page2.xhtml"/>
        </ui:fragment>
        <h:button id="button1" value="Page 1" outcome="good.xhtml?page=page1"
                  includeViewParams="true"/>
         
 
        <h:button id="button2" value="Page 2" outcome="good.xhtml?page=page2"
                  includeViewParams="true"/>
         
 
        <h:button outcome="index" value="Home"/>
    </h:body>
</html>

Conclusion

I have put the complete NetBeans 7.2.1 project using Mojarra on Bitbucket. The project uses Apache Maven, and was tested using GlassFish 3.1.2. Here is the complete project: dynamic-include

0 comments :

Popular Posts