jsfprimefacestabviewuiinclude

JSF dynamically include src in "ui:include src="#{bean.pagePath}"


I tried to include multiple source page path using ui:include tag in different tabs. The problem is when i gave the source page path as static one means that page will be shown but if give the source page path from backing bean mean it won't include the page.

Here is my code

template.xhtml:

    <p:layoutUnit position="center" id="layoutCenter">
                <h:form id="tempFormId">
                    <p:tabView value="#{multiTabBean.tabsList}" var="useCase"
                        activeIndex="#{multiTabBean.activeTabIndex}">
                        <p:tab title="#{useCase.title}" closable="true">
                            <f:subview>
                                <h:panelGroup id="mainTempPanelGroupId" layout="block">
                                    <ui:include src="#{useCase.path}" />
                                </h:panelGroup>

                            </f:subview>
                        </p:tab>
                    </p:tabView>
                </h:form>
            </p:layoutUnit>

bean:

public String menuAction() {                    
    menuBtnRendered = true;
    FacesContext facesContext = FacesContext.getCurrentInstance();
    ExternalContext externalContext = facesContext.getExternalContext();
    selectedModuleViewId = externalContext.getRequestParameterMap().get(
            "moduleViewId");

    tabsList.add(new Tab(getTabId(selectedModuleViewId),
                selectedModuleViewId, getModulePath(selectedModuleViewId)));        

    return null;
}

I'm using @ViewScoped.


Solution

  • <ui:include> runs during view build time (when XHTML is turned into JSF component tree). <p:tabView> runs during view render time (when JSF component tree needs to produce HTML).

    So, <p:tabView var> isn't available when <ui:include> runs. This problem is detailed in this answer: JSTL in JSF2 Facelets... makes sense? (<ui:include> is a taghandler and has hence same lifecycle as JSTL tags).

    You can solve this to a certain degree by using <c:forEach> to produce <p:tab>s instead of <p:tabView value>.

    <p:tabView activeIndex="#{multiTabBean.activeTabIndex}">
        <c:forEach items="#{multiTabBean.tabsList}" var="useCase" varStatus="loop">
            <p:tab title="#{useCase.title}" closable="true">
                <f:subview id="tab_#{loop.index}">
                    <h:panelGroup id="mainTempPanelGroupId" layout="block">
                        <ui:include src="#{useCase.path}" />
                    </h:panelGroup>
                </f:subview>
            </p:tab>
        </c:forEach>
    </p:tabView>
    

    It's by the way interesting to see that you somehow used <f:subview> in your initial attempt which is completely useless over there (already taken into account by <p:tabView var>), but it's actually helpful in here (it creates a new NamingContainer around the tab content).