JSF navigation rules for subviews?
Is it possible to create a navigation rule for a <subview> element?
The <subview> element contains a <jsp:include> element which itself includes another JSF page. And only this JSF page shall be exchanged by another JSF page via a navigation rule. My problem is that a navigation rule exchanges the outmost JSF page.
[347 byte] By [
supert24a] at [2007-11-26 13:56:37]

# 1
It would be really cool if there was a way to do this, however there is none that I know of.
The only way I was taught to handle navigation for pages included from another is by using wildcards in your navigation rules.
For example,
<navigation-rule>
<from-view-id>*</from-view-id>
<navigation-case>
<from-action>#{bean.thisAction}</from-action>
<from-outcome>theOutcome</from-outcome>
</navigation-case>
</navigation-rule>
# 2
You can just keep reloading the outmost JSP page, but have a conditional that tests to see which subview to use. This can be facilitated by the rendered attribute on the f:subview tag.
So, for example, you have 3 possible subviews to display depending on what data the user enters on each. They click the submit button, and you test the data that they entered. If the data entered means page A is displayed, you set a boolean in your bean to "activate" page A. You will also set all the other pages (B and C) to false.
Then reload the outermost page.
On the outermost page, you'll have 3 f:subview tags for each of the 3 pages that could be displayed. You'll use the rendered attribute on the f:subview tag to test each pages boolean, to see if the page is activated. The page that was activated during the last submit will get rendered, while the other 2 won't.
Code snippets to help you out... Your JSP:
<%-- Page A --%>
<f:subview id="PageA" rendered="#{BackBean.pageA}">
<jsp:include page="jsp/includes/PageA.jsp" />
</f:subview>
<%-- Page B --%>
<f:subview id="PageB" rendered="#{BackBean.pageB}">
<jsp:include page="jsp/includes/PageB.jsp" />
</f:subview>
<%-- Page C --%>
<f:subview id="PageC" rendered="#{BackBean.pageC}">
<jsp:include page="jsp/includes/PageC.jsp" />
</f:subview>
The BackBean will have something like this:
public String submit() {
//Determine which page to display next
//if page A
isPageA = true;
isPageB = false;
isPageC = false;
//if page B
isPageA = false;
isPageB = true;
isPageC = false;
//if page C
isPageA = false;
isPageB = false;
isPageC = true;
//Return an empty action, to reload outmost page
return "";
}
public boolean isPageA() {
return isPageA;
}
public boolean isPageB() {
return isPageB;
}
public boolean isPageC() {
return isPageC;
}
Hope this helps,
CowKing
# 3
Exactly this is my current approach!
Using booleans to enable/disable <jsp-includes>s.
But it is not nice, so I asked here..
The conceptual lack is that the
jsf-pages have to be already "known", i.e.
they have to be mentioned in the outer JSF file and not only
in the faces-config file.
Another lack is that they are displayed at a fixed "slot",
but can not really be replaced (so the slots have a fixed order
and in my web application, more than one slot can be "enabled").
But thanks anyway..
# 4
Such an approach can cause serious problems when you want to use forms with an request scoped bean in the include pages. Forms which won't be submitted and processed, because the boolean flag is being reset to false in the next lifecycle, etc.
And I'd rather use string comparisions, which is more elegant and consumes less code when using lots of includes. Like:rendered="#{myBean.currentPage == 'A'}"
rendered="#{myBean.currentPage == 'B'}"
rendered="#{myBean.currentPage == 'C'}"
private String currentPage; // + getter
Well, you can just use scriptlets to change the jsp:include page. One requirement is that the bean have to be session scoped. But I guess this is already done as you said you're using boolean checks to turn includes on or off.
Basic example:
JSF<%
mypackage.MyBean myBean = (mypackage.MyBean) session.getAttribute("myBean");
if (myBean == null) { // First-time initialization not done yet.
myBean = new mypackage.MyBean();
}
String currentPage = myBean.getCurrentPage();
%>
<f:view>
...
<jsp:include page="<%= currentPage %>" />
...
</f:view>
MyBeanprivate String currentPage; // + getter
// Eventually set default page and/or do nullchecks.
Where currentPage can be "page1.jsp", "page2.jsp", "main.jsp", "contact.jsp", etc. Take care that you have to put the f:subview tag in the top of the include page itself and not in the main page.
# 5
This is a very nice idea.Perhaps do you know how to replace that last line of the scriptlet code invoking a navigation rule, e.g.String NEXT_to_view_id = JSFFramework.calcNavigationRule( CURRENT_from_view_id, CURRENT_outcome);(However I dont know the actual API)