Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Primefaces multiple dynamic content panels to be displayed

I'm trying to do a kind of simple customizable news view page into my web application, like Google's one but much simpler, with frames. Each frame object simply has his title and an url to be added as its content.

I'm using JSF and primefaces, both on their newest versions. So my backing bean, which is @ViewScoped, has access to the logged user, which is stored in a @SessionScoped bean, and that user has his corresponding frames loaded.

Problem comes when I try to iterate it over the @ViewScoped bean, because the only way I find to do it is with a c:forEach tag. That's the way I do:

<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:p="http://primefaces.org/ui"
xmlns:fn="http://java.sun.com/jsp/jstl/functions">
<h:form>
    <p:panel header="Noticias">
        <h:panelGrid columns="#{fn:length(navegableHomeManager._UserFrames)}"
            width="100%">
            <c:forEach var="frame" items="#{navegableHomeManager._UserFrames}">
                <p:column>
                    <p:panel header="#{frame._Name}" closable="true"
                        style="width:95%;height:500px;" id="#{frame._Name}">
                        <p:ajax event="close"
                            listener="#{navegableHomeManager.actionFrameClosed}" />
                        <ui:include src="#{frame._Path}" />
                    </p:panel>
                </p:column>
            </c:forEach>
        </h:panelGrid>
    </p:panel>
</h:form>

That iteration obviusly does not work with navegableHomeManager bean because it is @ViewScoped. So the bean will be rebuilt in each of the iterations. The solution I've reached uses another @SessionScoped bean between the navegableHomeManager and the loggedBean, so that way the frames are stored there and I can have access to them properly into the iteration. That's working with the code above.

However I don't think it should be compulsory to use a @SessionScoped bean (creating an specific bean for every single case) every time I want to iterate in that way. That's why I have tried using components to avoid the iteration.

<p:dataGrid columns="#{fn:length(navegableHomeManager._UserFrames)}"
            value="#{navegableHomeManager._UserFrames}" var="frame">
    <p:column>
        <p:panel header="#{frame._Name}" closable="true"
                    style="width:95%;height:500px;">
            <p:ajax event="close"
                        listener="#{navegableHomeManager.actionFrameClosed}" />
            <ui:include src="#{frame._Path}" />
        </p:panel>
    </p:column>
</p:dataGrid>

It doesn't work neither when the bean is @ViewScoped or @SessionScoped, because even the frames properties are set, the ui:include tag has already been built with no destination path, so I can't render the destination path dinamically. I think that, as ui:include is being applied at the same time as c:forEach, using a c:forEach tag is really the only way to go through this.

Pool your ideas.

UPDATE

Here I post more xhtml code to help in the understanding of the context. The new's page is integrated into a template. That's the page which is targeted (/system/home/index.xhtml):

<ui:composition xmlns="http://www.w3.org/1999/xhtml"
template="/templates/general_template.xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:c="http://java.sun.com/jsp/jstl/core">

<ui:define name="metadata">
    <f:event type="preRenderView"
        listener="#{navegableHomeManager.initialize}" />
</ui:define>

<ui:define name="general_content">
    <ui:include src="/system/home/home_view.xhtml" />
</ui:define>

And that's the way I also tried to do it, but not making the c:forEach tag to work:

<context-param>
    <param-name>javax.faces.FULL_STATE_SAVING_VIEW_IDS</param-name>
    <param-value>/system/home/index.xhtml</param-value>
</context-param>

And that's the backing bean header:

@ManagedBean
@ViewScoped
@URLMapping(id = "home", pattern = "/home", viewId = "/system/home/index.xhtml")
public class NavegableHomeManager extends SystemNavegable {

/**
 * 
 */
private static final long serialVersionUID = 6239319842919211716L;

@ManagedProperty(value = "#{loggedBean}")
private LoggedBean _LoggedBean;

//More stuff
like image 376
Xtreme Biker Avatar asked Jan 25 '13 08:01

Xtreme Biker


1 Answers

Stick to <c:forEach>. It does the job you're looking for. The <ui:include> runs during view build time, so the iteration tag should also run during view build time.

As to the @ViewScoped bean problem, you've 2 options:

  1. Turn off partial state saving for the particular view:

    <context-param>
        <param-name>javax.faces.FULL_STATE_SAVING_VIEW_IDS</param-name>
        <param-value>/news.xhtml</param-value>
    </context-param>
    
  2. Change it to a @RequestScoped bean and use <f:param> and @ManagedProperty to maintain state across postbacks by request parameters.

There would be a third option if JSF 2.2 is available: just upgrade to JSF 2.2. They've fixed the chicken-egg problem in view scoped beans and partial state saving.

like image 64
BalusC Avatar answered Nov 18 '22 09:11

BalusC