9 Replies Latest reply on Sep 11, 2009 7:13 AM by jean.baldessar

    Dynamic include problem

    jean.baldessar

      Hi! I posted this in the seam forum too...
      I want to do something like that:

      <a4j:outputPanel id="componentToReRender" >
       <ui:repeat value="#{backingBean.myIncludes}" var="includePath" >
       <ui:include src="#{includePath}" />
       </ui:repeat>
      </a4j:outputPanel>
      <a4j:commandButton
       value="add some include"
       action="#{backingBean.addSomeInclude" /* add some value in backingBean.myIncludes list */
       reRender="componentToReRender"/>
      <a4j:commandButton
       value="remove some include"
       action="#{backingBean.removeSomeInclude" /* remove some value in backingBean.myIncludes list */
       reRender="componentToReRender"/>


      But I cant because the include tag dont work with the var value of a ui:repeat. You can say "use c:forEach", but according with some articles I read (like this), I cant do that to, because I want do remove and add values in my backingBean list.

      the same happens if I use a4j:repeat and a4j:include...

      What can I do?

        • 1. Re: Dynamic include problem
          nbelaevski

          Hi,

          This should work ok with c:forEach. Have you tried that?

          • 2. Re: Dynamic include problem
            jean.baldessar

            Yes I already tryed and c:forEach have a problem:

            according with http://drewdev.blogspot.com/2008/03/build-time-vs-render-time.html: "a JSF component tree should never be altered between having its state saved and when its state is restored."

            If I use c:forEach for add and remove components, I get a lot of bugs like duplicated ids. More information about the c: forEach bugs can be found in the cited article.

            • 3. Re: Dynamic include problem
              jean.baldessar

              any alternative solution?

              • 4. Re: Dynamic include problem
                nbelaevski

                 

                "jean.baldessar" wrote:
                according with http://drewdev.blogspot.com/2008/03/build-time-vs-render-time.html: "a JSF component tree should never be altered between having its state saved and when its state is restored."

                Well, it's not. Facelets tags are evaluated on render response phase, here is the simplest experiment to prove this:
                <h:form>
                 <c:forEach items="#{forum5Bean.data}">
                 <h:outputText value="aaaa" />
                 </c:forEach>
                
                 <h:commandLink value="Link" />
                 </h:form>

                public Object getData() {
                 Thread.dumpStack();
                
                 if (list.isEmpty()) {
                 list.add(new SelectItem(1, "1", "odin"));
                 list.add(new SelectItem(2, "2", "dva"));
                 list.add(new SelectItem(3, "3", "tri"));
                
                 }
                 return list;
                 }


                Console output: http://pastie.org/612754 - note there's no trace from RestoreViewPhase class - doesn't this mean that getData() is not evaluated again on restore view phase? For more info check com.sun.faces.application.StateManagerImpl class.

                I guess the article may be actual for JSF 1.1 or JSP, but for JSF 1.2/Facelets it seems to be wrong.

                • 5. Re: Dynamic include problem
                  nbelaevski

                   

                  "jean.baldessar" wrote:
                  any alternative solution?

                  a4j:include/ui:include both build components tree. They don't work in the context of the iteration that a4j:repeat/ui:repeat defines.

                  • 6. Re: Dynamic include problem
                    jean.baldessar

                    nbelaevski, I am not sure if the article is correct, but the fact is that c:forEach bug's my application. If I remove a component of the tree, and add other component later, JSF restores the state of the old component in my new component (at least that is what it seems to happen) and I get a duplicated id exception.

                    • 7. Re: Dynamic include problem
                      jean.baldessar

                      My application has a code like that:

                      <rich:tabPanel id="userRotinaTab" switchType="client">
                       <c:forEach items="#{gestao.openedScreens}" var="screen">
                       <rich:tab id="#{rotina.codigo}>
                       <ui:include src="#{rotina.path}" />
                       </rich:tab>
                       </c:forEach>
                      </rich:tabPanel>


                      the bug happens in this situation:

                      * add a object in openedScreens list
                      * remove this object
                      * add other object in openedScreens list
                      * add the first object again in my list


                      in this point I get a duplicated id, because JSF restores the value of the first element that I add in the list in the second element...

                      it's realy complicated to explain.

                      To resolve this, I was thinking in forget ui:repeat, a4j:repeat and c:forEach and read a xhtml from my backingBean and add the resulting component in my userRotinaTab, but I dont know how to do this.

                      this is madness O_o"


                      suggestions?

                      • 8. Re: Dynamic include problem
                        nbelaevski

                        a4j:include cannot be created programmatically, but you can use its (or Facelets) code as a reference on how you can create components tree from .xhtml file.

                        Another solution is creation of maximum possible number of components and hide some using "rendered".

                        • 9. Re: Dynamic include problem
                          jean.baldessar

                          "Another solution is creation of maximum possible number of components and hide some using "rendered"."

                          the problem is that my application has a lot of screens and if I simple configure rendered=false the component tree still being constructed and my backingBeans get instantied before I realy use it.

                          the first alternative seems to be hard to do, but I'll try it...