18

I am trying to toggle a page that shows a <rich:dataTable>. Before I just included the <ui:include> template and it would just show the table the whole time.

<ui:include src="../log/viewDlg.xhtml"/>

Now I want to be able to toggle it on/off on the web-page. Showing on the page with maybe a button or link. How can I achieve it?


Update 1: I am unable to get it to show up for some odd reason, Here is what I wrote so far based on feed back

View:

<a4j:commandLink value="View"
    action="#{bean.showview}" render="viewPanel"/>

<h:panelGroup id="viewPanel">
    <h:panelGroup id="tableRenderPanel" rendered="#{bean.showPolicyView}">    
        <ui:include src="../log/viewDlg.xhtml"/>
    </h:panelGroup>                         
</h:panelGroup>

Backing bean:

private boolean showPolicyView = false;

public void showView() {
    showPolicyView = !showPolicyView;
}

public boolean isShowPolicyView(){
    return showPolicyView;
}
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
Gilbert V
  • 1,050
  • 5
  • 16
  • 43

2 Answers2

21

Wrap your <ui:include> inside two <h:panelGroup> elements. There's a catch here, you can't rerender a conditional component. Why's this? because when the element's rendered attribute resolves to false, it will not be considered while rendering the view so it can't be the target of an operation (in this case, related to renderization).

Jumping to the code, you'll have this:

<h:panelGroup id="wrapperPanel">
    <h:panelGroup id="tableRenderPanel" rendered="#{yourBean.renderTable}">
        <ui:include src="../log/viewDlg.xhtml"/>
    </h:panelGroup>
</h:panelGroup>

yourBean#renderTable is a Boolean property that determines if the component will be rendered. When it evaluates to false, the component is not included in the component tree.


Toggling the view

To toggle the view, simply create a bean method that either refreshes the page

<h:commandLink action="#{yourBean.toggleTableView}"/>

or the particular panel through AJAX. To do this in JSF 1.2, rely on extensions like RichFaces to introduce AJAX, if you can. For example, should you choose RichFaces, you can use <a4j:commandLink/> and its handy render (or reRender in older versions) attribute to achieve what you could do normally with an <f:ajax/> in JSF 2

<a4j:commandLink action="#{yourBean.toggleTableView}" reRender="wrapperPannel"/>

Or, another alternative is

<a4j:commandLink action="#{yourBean.toggleTableView}">
    <a4j:support event="oncomplete" reRender="wrapperPannel"/>
</a4j:commandLink>

Please note that the reRender attribute may vary depending on the structure of your page, but it should always reference the id of the wrapping panel in the end. Also, reRender was renamed to simply render in late RichFaces versions.

So, assuming you have a renderTable property (getter + setter) in yourBean, the toggleTableView must change it, in order to dinamically define if the component is to be rendered or not (renderTable = false).


Introducing RichFaces

Check this link for help in setting up RichFaces in your project.

Fritz
  • 9,987
  • 4
  • 30
  • 49
  • I have a small problem I am using jsf 1.2 and I am getting this issue. Tag Library supports namespace: http://java.sun.com/jsf/core, but no tag was defined for name: ajax should i just use the commanlink with the ajax or something similar? – Gilbert V Sep 09 '13 at 19:29
  • 1
    @GilbertV Oh, I see, silly me. `f:ajax` was introduced later. If you can, use a JSF extension like RichFaces or PrimeFaces in a version compatible with JSF 1.2. Those add a nice AJAX boost to previous JSF versions. I'll update my answer to make it 1.2 friendly. – Fritz Sep 09 '13 at 19:38
  • Alrighty ty i wouldn't know how to make the extension for RichFaces or PrimeFaces so it would be nice to see it. – Gilbert V Sep 09 '13 at 19:41
  • @GilbertV Done, I also added a link to the configuration guide for RichFaces. In any case, don't hesitate to ask if you need further help. – Fritz Sep 09 '13 at 19:52
  • Thank you i will check that out, for some reason it still won't refresh the page when I click on the link, I gotta be doing something wrong so i updated the question to show the code i wrote based on your suggestions. – Gilbert V Sep 09 '13 at 20:09
  • 1
    @GilbertV There's something weird there, `h:commandLink` doesn't have the `render` atribute. If you check the answer again, there's a really small difference: It's an `a4j:commandLink` instead of a `h:commandLink`. `a4j` belongs to RichFaces. – Fritz Sep 09 '13 at 20:26
  • thank you for your assistance, I made the changes but still the panel refuses to show, do you have any further recommendation or advice? – Gilbert V Sep 10 '13 at 14:52
  • 1
    @GilbertV Do you get any error regarding an id not being found when clicking the link? – Fritz Sep 10 '13 at 14:54
  • No there is no error and I have it running fine on debug. It loads up fine and runs the method. If there is an error eclipse isn't showing it to me. – Gilbert V Sep 10 '13 at 14:59
  • 1
    @GilbertV I've added a new option using an old `a4j:support` element from earlier versions of RichFaces. If you have it, try it. Also, `wrapperPanel` can be changed from an `h:panelGroup` to an `a4j:outputPanel`. – Fritz Sep 10 '13 at 15:24
  • When i tried it i got a error stating " Attribute 'event' is required". What does that mean ? – Gilbert V Sep 10 '13 at 16:00
  • 1
    @GilbertV A support instruction is associated to a particular event. In this case, try `event="oncomplete"`. – Fritz Sep 10 '13 at 16:07
  • Tried it with but for some reason it still won't show up. Did i wrote it wrong ? – Gilbert V Sep 10 '13 at 16:16
  • 1
    @GilbertV No, if `policyPanel` is the id previously known as `viewPanel` in your example. I must be leaving some loose end around, so I'm sorry for all the misses... tough it seems fine to me. I'll give it another try, I guess. – Fritz Sep 10 '13 at 16:31
  • Thank you, and yes policyPanel is the ID previously known as viewPanel. I just wanted it to be more easy to spot here. – Gilbert V Sep 10 '13 at 17:14
  • 1
    @GilbertV Is your bean RequestScoped? if so, since your default value is false, setting it to true won't help in the end, as a new bean is created to handle the request. Everything works, except the results don't last enough to use them. – Fritz Sep 10 '13 at 17:22
  • how would I make it last long enough to user ? is there a trick i need to preform or is some java script needed? – Gilbert V Sep 10 '13 at 17:30
  • @GilbertV For the future: If you were to use JSF2, you could make that bean ViewScoped, which is kept alive as long as lons as the current form. For now, this particular issue [has alerady been answered](http://stackoverflow.com/questions/5897262/jsf-1-2-how-to-keep-managed-bean-with-request-scope) – Fritz Sep 10 '13 at 18:03
  • I just looked at the getter to show and your right once the page has been reloaded the method returns to false. would adding the method to another bean and retrive the getter with that bean help or would it just reset the bean as well ? Should i use the ? – Gilbert V Sep 10 '13 at 18:05
  • 1
    @GilbertV Indeed, it would be reset, as the other bean would be a RequestScoped one as well. Those beans only survive in the scope of a request, and once the answer has been rendered, they're discarded. That's why ViewScoped was introduced in JSF2, to fill the gap between RequestScoped and SessionScoped, where the latter survives as long as the user's JSESSION is active (that means, reserved memory for a bean that's kept alive as long as the user uses your application, plus the session expiration time). Check the link I posted in my previous comment. – Fritz Sep 10 '13 at 18:10
  • Okay must be doing something wrong it seems, I am getting the following error " Must be literal" what does it mean by literal? – Gilbert V Sep 10 '13 at 18:59
  • I am still getting that error here is the error i am exactly getting" Must be literal" is there something i have to do with my java code ? – Gilbert V Sep 10 '13 at 19:23
  • @GilbertV I see now, `beanName` must be a literal, meaning that you have to define the name of the bean directly, like this: `beanName="loginBean"` and also, don't forget to make your LoginBean serializable. – Fritz Sep 10 '13 at 19:37
  • @GilbertV [This might come in handy](http://chat.stackoverflow.com/rooms/3320/discussion-between-sword101-and-balusc) – Fritz Sep 10 '13 at 19:39
  • The room is frozen I can't add any new messages do you want to create a new chat room or something? – Gilbert V Sep 10 '13 at 19:55
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/37131/discussion-between-gilbert-v-and-gamb) – Gilbert V Sep 10 '13 at 20:12
5

I like the use of ui:include better than inserting h:panelBoxes like here:

<ui:fragment rendered="#{myBean.yourCondition()}">
    <ui:include src="viewA.xhtml"/>
</ui:fragment>
<ui:fragment rendered="#{not myBean.yourCondition()}">
    <ui:include src="viewB.xhtml"/>
</ui:fragment>

Advantage: Tag handlers do not represent components and never become a part of the component tree once the view has been built. It won't interefere with your CSS - the h:panelBox, in contrary, inserts a div or span.


... Another approach would be c:choose, which works but can cause render phases issues.

<c:choose>
    <c:when test="#{myBean.yourCondition()}">
        <ui:include src="viewA.xhtml"/>
    </c:when>
    <c:otherwise>
        <ui:include src="viewB.xhtml"/>
    </c:otherwise>
</c:choose>

Caution: When fiddling with tag handlers (like any c:xxx), be sure to know the difference between UI Components and Tag Handlers. Namely that UI Components and Tag Handlers are renderend in different phases. That implies that you cannot create a variable in a composite component and use it in a nested tag handler. c:choose and ui:include are both tag handlers, so normally it's not a problem. Read the link, it's a very short example and very insightful.

Hannes Schneidermayer
  • 4,729
  • 2
  • 28
  • 32