Skip executing <ui:include> when parent UI component is not rendered
Asked Answered
C

2

8

I have the following construct at several places in my webapp in order to conditionally render page fragments depending on some actions:

<h:panelGroup rendered="#{managedBean.serviceSelected == 'insurance'}">
    <ui:include src="/pages/edocket/include/service1.xhtml" />
</h:panelGroup>

I have observed, that the <ui:include> is still executed even when the rendered attribute evaluates false. This unnecessarily creates all backing beans associated with the service1.xhtml file which is been included.

How can I skip executing the <ui:include> when the parent UI component is not rendered, so that all those backing beans are not unnecessarily created?

Corin answered 16/8, 2012 at 14:40 Comment(0)
C
9

Unfortunately, this is by design. The <ui:include> runs as being a taghandler during the view build time, while the rendered attribute is evaluated during the view render time. This can be better understood by carefully reading this answer and substituting "JSTL" with "<ui:include>": JSTL in JSF2 Facelets... makes sense?

There are several ways to solve this, depending on the concrete functional requirement:

  1. Use a view build time tag like <c:if> instead of <h:panelGroup>. This however puts implications into the #{managedBean}. It can't be view scoped and should do its job based on HTTP request parameters. Exactly those HTTP request parameters should also be retained in subsequent request (by e.g. <f:param>, includeViewParams, etc) so that it doesn't break when the view is restored.

  2. Replace <ui:include> by a custom UIComponent which invokes FaceletContext#includeFacelet() during the UIComponent#encodechildren() method. So far no such component exist in any of the existing libraries. But I can tell that I've already such one in mind as a future addition for OmniFaces and it works as intuitively expected here at my test environment (with Mojarra). Here's a kickoff example:

    @FacesComponent(Include.COMPONENT_TYPE)
    public class Include extends UIComponentBase {
    
        public static final String COMPONENT_TYPE = "com.example.Include";
        public static final String COMPONENT_FAMILY = "com.example.Output";
    
        private enum PropertyKeys {
            src;
        }
    
        @Override
        public String getFamily() {
            return COMPONENT_FAMILY;
        }
    
        @Override
        public boolean getRendersChildren() {
            return true;
        }
    
        @Override
        public void encodeChildren(FacesContext context) throws IOException {
            getChildren().clear();
            FaceletContext faceletContext = ((FaceletContext) context.getAttributes().get(FaceletContext.FACELET_CONTEXT_KEY));
            faceletContext.includeFacelet(this, getSrc());
            super.encodeChildren(context);
        }
    
        public String getSrc() {
            return (String) getStateHelper().eval(PropertyKeys.src);
        }
    
        public void setSrc(String src) {
            getStateHelper().put(PropertyKeys.src, src);
        }
    
    }
    
Cynosure answered 16/8, 2012 at 16:47 Comment(5)
Hi, Thanks for reply BaluSC . But Iam not able to understand the answer. Where we need to declare this component and how to use it.Corin
Hi Balusc , after adding the component the skipping of include is happening perfectly. But when it is required to be included , that time fails . I will paste the exception FYI .Corin
Has this been included in omnifaces yet, BalusC?Auxochrome
@Thang: No, this construct didn't work in MyFaces (and beyond some extent also not in Mojarra). See also this related question: #13680692Cynosure
@BalusC: So does this mean that if we want dynamic include, we have to make the bean SessionScoped, BalusC?Auxochrome
A
7

Use conditional expression as ui:include src:

<h:panelGroup>
    <ui:include 
        src="#{managedBean.serviceSelected == 'insurance' ?
            '/pages/edocket/include/service1.xhtml'
            :
            '/pages/empty.xhtml'}"
    />
</h:panelGroup>
Ables answered 21/2, 2013 at 22:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.