5

I am making use of JSTL tags in my JSF application. With certain actions, I need the component tree to be rebuilt as if it was an initial build. My current symptoms are incorrect object to component associations, duplicate ids, and other issues with stale components. This is using a c:foreach (cannot use a repeat tag, see example link) tag which is used in the build phase.

My understanding is that it is possible to force a rebuild, but I haven't been able to find where or how that occurs. I am open to solutions that start on the client or in the server.

For an example of the code I am using refer to this page on dynamic tabs in Richfaces. http://in.relation.to/Bloggers/UsingDynamicallyCreatedRichFacesTabPanelForSearchResults

Note: Using ui:repeat or a4j:repeat is not feasible. See the example page for details.

Other Note: The app beans are session scoped and the data in them needs to be, just not the component tree state.

Update This question is directly to the issue raised in this article and the first comment. I didn't know how to actually do the workaround in the first comment and the accepted answer led me to it.

Adam
  • 3,675
  • 8
  • 45
  • 77

1 Answers1

4

I don't think stale components are the issue. The duplicate IDs especially are a side effect of using the <c:forEach> tag. This is because <c:forEach> will add any child componenets to the component tree multiple times and each time it will attempt to use the same ID (unlike <ui:repeat>). This obviously results in duplicate IDs (you will notice in the example you linked to they did not specify any IDs within the <c:forEach> tags).

I'm not sure what they mean by the 'view build phase'. If you look at the JSF documentation, you will see that there is no such phase. In any case, when you use <ui:repeat>, as long as the AJAX call you use to perform the search re-renders the rich:tabPanel then it should work.

The reason they cited for <ui:repeat> not working was:

You could not use repeat components(neither ui:repeat nor a4j:repeat) for that because they work during page render time and do not create components in JSF tree but just iterate the same instance.

And in their example they used:

...
<a4j:commandButton action="#{capitalsBean.search}" value="Search" reRender="output" id="search"/>
...
<a4j:outputPanel id="output">
    <rich:tabPanel id="tapPanel" width="700" rendered="#{not empty capitalsBean.foundCapitals}">
        <c:forEach items="#{capitalsBean.foundCapitals}" var="cap">
        ...

If you are specifying reRender="output" on the search's a4j:commandButton how does 'page render time' not occur for tapPanel??

In summary, use <ui:repeat>, JSTL and JSF are typically not very good bedfellows.

EDIT: I should have done this first since I don't have experience with rich:tabPanel but <ui:repeat>, it appears, cannot be used with rich:tabPanel (but not for the reasons stated in the example you link to, hence my confusion). Don't use <c:forEach> though, use a component binding to the rich:tabPanel.

Gyan aka Gary Buyn
  • 12,242
  • 2
  • 23
  • 26
  • My issue isn't duplicate ids due to the c:forEach tag repeating a hard coded id as just inside the c:foreach I use an f:subview. The issue is when the page changes sometimes the component tree is stale. I'll look into component binding to see if that is a solution. I'll try to find the correct phrase for "view build phrase". – Adam Jun 20 '11 at 16:24
  • I believe what I meant by "view build phase" was the "new view" or "initial view" paths of the restore view phase which then bypass to the render response phase? – Adam Jun 20 '11 at 16:31
  • To be honest I don't know the inner workings of the JSF lifecycle to that degree. You shouldn't need to though. An AJAX call invokes the JSF lifecycle the same way that any regular JSF postback would. The only difference is that you can pick and choose which components are processed by the different phases using the `process` and `reRender` attributes. I can't see why you would get a 'stale' component tree. The only things that could be 'stale' on the client side are those that are not included in the `reRender` attribute. – Gyan aka Gary Buyn Jun 20 '11 at 23:05
  • I don't see that I have satisfactorily answered your question yet... Thanks for accepting it all the same. Try the binding and get back to me. – Gyan aka Gary Buyn Jun 20 '11 at 23:06
  • 1
    The binding got me on the right path to a solution like this: `tabPanel.getParent().getChildren().clear();` This clears the tab panel from the component tree and it will be rebuilt. – Adam Jun 21 '11 at 15:26