How to dynamically show/hide components under p:tab via ajax?

2.4k views Asked by At

Forgive me I am not even sure my question is correctly stated. I am trying to unravel relationship between p:tab and h:panelGroup. I have very shallow understanding of JSF. I have following code.

<p:tabView id="view">
    <p:tab id="A">
        ...
        <p:ajax event="change" update="C,D" listener="#{bean.captureValue}"/>
    </p:tab>
    <p:tab id="B" titleStyleClass="x">
        <h:panelGroup id="C">
            <h:panelGroup rendered="#{bean.checkValue eq 'Yes'}"/>
                <f:facet name="title"><table>...</table></f:facet>
                <div>....</div>
            </h:panelGroup>
        </h:panelGroup>
        <h:panelGroup id="D">
            <h:panelGroup rendered="#{bean.checkValue eq 'No'}"/>
                <f:facet name="title"><table>.....</table></f:facet>
                <div>....</div>
            </h:panelGroup>
        </h:panelGroup>
    </p:tab>
</p:tabView>

So within component id="A", a user selects a value from drop down menu, bean captures it and dynamically show or hide component id="C" or "D" based on the value.

First time try, I didn't have any h:panelGroup tags. I used rendered attribute directly from p:tab component however I realized that unless I refresh the entire page, the bean.checkValue wouldn't know latest value captured. By reading many articles in this forum, I realized I have to wrap it with h:panelGroup which in turn worked by showing either h:panelGroup "C" or "D" based on the value selected from p:tab tag with id="A".

However the contents of f:facet tag is not visible anymore. It has html table tag which contains h:outputText with static value and p:graphicImage. I am not sure why and hope someone can solve this mystery.

Update:

Thanks to Arthur. I was able to fix the issue with his help. I paste here code that performs expected output.

<p:tabView id="view">
    <p:tab id="A">
        ...
        <p:ajax event="change" update="view" listener="#{bean.captureValue}"/>
    </p:tab>
    <p:tab id="B" titleStyleClass="x">             
          <f:facet name="title">
              <ui:fragment rendered="#{bean.checkValue eq 'Yes'}"/>
                 <table>...</table>
              </ui:fragment>
          </f:facet>
          <ui:fragment rendered="#{bean.checkValue eq 'Yes'}"/>
              <div>...</div>
          </ui:fragment>


           <f:facet name="title">
              <ui:fragment rendered="#{bean.checkValue eq 'No'}"/>
                 <table>...</table>
              </ui:fragment>
          </f:facet>
          <ui:fragment rendered="#{bean.checkValue eq 'No'}"/>
              <div>...</div>
          </ui:fragment>            
    </p:tab>
</p:tabView>
1

There are 1 answers

8
Artur Skrzydło On BEST ANSWER

Facets are representing a named section within a container component. Container for your facets are in both cases <h:panelGroup> and this component doesn't define any facet which you could use. As you don't provide in your sample code any name for the facet (which is mandatory) I only assume that maybe you would like to use a title facet for a tab, as <p:tab> component define facet named "title". Then it should look like

<p:tab id="B">
        <f:facet name="title" >
            <h:outputText value="Test1" rendered="#{bean.checkValue}"/>
            <h:outputText value="Test2" rendered="#{!bean.checkValue}"/>
        </f:facet>
</p:tab>

, so you implement rendering logic inside facet value (you decide which title would be displayed. This logic could be also moved to backing bean. Keep in mind that in primefaces sometimes components doesn't handle very well and you could try then use them as an attribute instead of facets as stands in this post

It is also possible that you misunderstand meaning of facets. The best way to explain them are the facets defined i component. Authors of this component wanted to provide for users possibility to define header and footer of datatable. Then you, as a jsf user can compose header for instance, from other different components. You could also check this post where facets are also explained.

One more thing to add is that using <h:panelGroup rendered="#{bean.checkValue}"/> for render logic is considred as bad pattern as it is going to produce a <span> element in your code. Instead you should use <ui:fragment rendered="#{bean.checkValue}"/> which is intended for rendering logic and it won't produce any additional html code