Search code examples
jsfmanaged-beanjsf-2.3

How share some f:event of f:metadata between selected XHTML with managed bean interface as parameter


Noting that from JSF view metadata demystified:

Since this tag is about current view metadata it doesn't participate in XHTML templates (the page author must ensure that the element does not appear on a template or included page; it can be in a template client) and it is direct child of <f:view>.

I have multiple <f:viewParam> and <f:event> that repeat in many XHTML pages, which are in turn clients of a template.xhtml. Each f:event depends on a given managed bean, where the managed bean is different for each XHTML page (but respects a common interface, i.e., the same operations for the listeners exist for every relevant managed bean):

<f:view>
    <f:metadata>

        <!-- I want to share this across many XHTML parametrised by the bean -->
        <f:viewParam name="id" value="#{particularBean.id}"/>
        <f:event type="preRenderView" listener="#{particularBean.opCommon1}"/>
        <f:event type="preRenderView" listener="#{particularBean.opCommon2}"/>
        <!-- END SHARED PORTION -->

        <f:event type="preRenderView" listener="#{particularBean.onlyForMe}"/>

    </f:metadata>
</f:view>

<ui:composition template="/template.xhtml">

Q: How can I encapsulate the shared <f:viewParam> and <f:event> portion so that it can be "included" and treated as a common policy fragment, with particular managed beans (meeting the common interface) passed in for each XHTML page ?


Solution

  • I found the answer in one of my own older projects (as I posted I recalled vaguely I had investigated this already at some stage years ago). This works:

    In /include/shared.xhtml:

    <ui:composition 
     xmlns="http://www.w3.org/1999/xhtml"
     xmlns:f="http://xmlns.jcp.org/jsf/core"
     xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
     >
        <f:viewParam name="id" value="#{particularBean.id}"/>
        <f:event type="preRenderView" listener="#{compatibleBean.opCommon1}"/>
        <f:event type="preRenderView" listener="#{compatibleBean.opCommon2}"/>
    </ui:composition>
    

    And in any client:

    <f:view>
     <f:metadata>
    
      <ui:include src="/included/shared.xhtml">
        <ui:param name="compatibleBean" value="#{particularBean}"/>
      </ui:include>
    
      <f:event type="preRenderView" listener="#{particularBean.onlyForMe}"/>
    
     </f:metadata>
    </f:view>