10 Replies Latest reply on Oct 21, 2008 8:32 AM by Martin Höller

    Dynamic panelbar

    a o Newbie

      Hi,

      I want to create a dynamic panelbar. Is there an other way than writing java code directly?

      I am making a query from database to get countries and their definitions, and I want to add a panelBarItem for each country to panelBar. However, panelBar is not dynamic enough unfortunately.

      For example, this one works but, if I want to put many things in a panelBarItem; it is very difficult:

      for(Country e : country){
       HtmlPanelBarItem item = new HtmlPanelBarItem();
       item.setLabel(e.getName());
      
       HtmlOutputText htmlOutputText = new HtmlOutputText();
       htmlOutputText.setValue(m.getDefinition());
       item.getChildren().add(htmlOutputText);
      
       children.add(item);
       }
      


      I tried this one also, but it didnt work:

      <rich:panelBar>
       <t:dataTable value="#{countryBean.countries}" var="row">
       <t:column>
       <rich:panelBarItem label="#{row.name}">
       <t:outputText value="#{row.definition}"></t:outputText>
       </rich:panelBarItem>
       </t:column>
       </t:dataTable>
      </rich:panelBar>
      
      


      Second method is better of course, but it didnt work; exception is thrown.

      How can I solve this problem without writing Java code?

      Thanks...

        • 1. Re: Dynamic panelbar
          Ranveer Singh Newbie

          have you seen richfaces demo source code. just check how they are creating their navigation. It is same what you want..

          • 2. Re: Dynamic panelbar
            David Greenberg Newbie

            What part of the demo source code are you referring to? The only examples I see use static menu items. Could you please say specifically where to find an example of dynamic generation of either menuItems or panelBarItems?

            Thanks,
            David

            • 3. Re: Dynamic panelbar
              David Greenberg Newbie

              While I never found the demo code with a dynamic panelBar, I did come up with the following two options, neither of which work correctly. Has anyone been able to solve this?

              Note that this is only relevant when using Facelets. These examples also assume that "#{myList}" is dynamic and changes whenever "outPanel" is re-rendered.

              Option 1:

              <a4j:outputPanel id="outPanel">
               <rich:panelBar>
               <ui:repeat value="#{myList}" var="myVar">
               <rich:panelBarItem label="#{myVar}">
               <h:outputText value="Hello world" />
               <h:outputText value="Hello #{myVar}" />
               </rich:panelBarItem>
               </ui:repeat>
               </rich:panelBar>
              </a4j:outputPanel>
              


              This will generate the divs appropriately, displaying all the labels for the items, but it is not possible to expand any item. This is because the PanelBarRendererBase is looking for UIPanelBarItem components as the children of the UIPanelBar, and it does not look recursively. Re-rendering "outPanel" does refresh the list. Unfortunately, unless the users have Firebug and are willing to manually turn off the "display: none" each time they want to expand an item, this will not work.

              Option 2:
              <a4j:outputPanel id="outPanel">
               <rich:panelBar>
               <c:forEach items="#{myList}" var="myVar">
               <rich:panelBarItem label="#{myVar}">
               <h:outputText value="Hello world" />
               <h:outputText value="Hello #{myVar}" />
               </rich:panelBarItem>
               </c:forEach>
               </rich:panelBar>
              </a4j:outputPanel>
              


              This will display "Hello world" in a panel with no label. The data can be re-rendered with different options, but "#{myVar}" never gets displayed. This is because the JSTL-style functions in Facelets run at facelet compile-time, not render-time, so only the value(s) that were in "#{myList}" at that point will be rendered.

              While this is certainly a shortcoming of Facelets, it is also a bug in RichFaces. PanelBarRendererBase should look recursively for UIPanelBarItems, for precisely this reason. Otherwise, there is no way to dynamically change the panels displayed. Is there a workaround for this or a fix in 3.2.2?

              Thanks,
              David

              • 4. Re: Dynamic panelbar
                shadowcreeper Apprentice

                I have found that you are much better off using var="ignoredVar" varStatus="varStatus", then a c:set name="varIndex" value="varStatus.index" and using ${myVar[varIndex]} wherever you want the myVar.

                I think this is due to the fact that c:forEach is not fully compatible with AJAXy stuff. However, the index from the varStatus is always correct even when AJAX reRendering changes the size of the items list.

                • 5. Re: Dynamic panelbar
                  David Greenberg Newbie

                  Unfortunately that didn't seem to work. Am I doing something wrong?

                  This is the test code I used:

                  <h:outputText value="List: '#{fn:length(myList)}'" />
                  <c:forEach items="myList" var="ignored" varStatus="varStatus">
                   <c:set var="varIndex" value="varStatus.index" />
                   <h:outputText value="Index: '${varStatus.index}'" />
                   <h:outputText value="Index: '${varIndex}'" />
                   <h:outputText value="var: '${ignored}'" />
                  </c:forEach>
                  


                  The output is the following (after a few ajax submits):

                  List: '4'
                  Index: ''
                  Index: ''
                  var: ''


                  Did I miss anything?

                  Thanks,
                  David

                  • 6. Re: Dynamic panelbar
                    shadowcreeper Apprentice

                    I had seen this before, but I haven't run across it in my own pages for a while. I'm not sure what I did to fix it as I don't see that I'm doing anything particularly different in my code at the moment.

                    I'm not using panelBar, but I am using rich:tabPanel, rich:dataTable and h:inputText all referencing different indexes from one of couple of nested c:forEach components.

                    One more thing: I had this working with RF3.2.0 fine, but 3.2.1 wouldn't work, although I've tried a couple of NIGHTLY builds for 3.2.2 and they have worked fine (and I just switched over to NIGHTLY 20080817).

                    Oh yeah, I am also using Facelets 1.1.14 which definitely does some things differently with the c:forEach stuff...

                    • 7. Re: Dynamic panelbar
                      David Greenberg Newbie

                      That must be it. I am using RF 3.2.1.GA with Facelets 1.1.14. I'll have to try again once 3.2.2 is more stable.

                      Thanks for your help.

                      • 8. Re: Dynamic panelbar
                        shadowcreeper Apprentice

                        one more thing to try... i think when i saw it i was using h:panelGroup, which i have since gotten rid of...

                        so maybe if you try not using h:outputText, try something like this:

                        <h:outputText value="List: '#{fn:length(myList)}'" />
                        <c:forEach items="myList" var="ignored" varStatus="varStatus">
                         <c:set var="varIndex" value="varStatus.index" />
                         Index: '${varStatus.index}'<br/>
                         Index: '${varIndex}'<br/>
                         var: '${ignored}'<br/>
                        </c:forEach>
                        

                        and see if that works for you, or try some other type of rich: or a4j: components. or maybe surrounding it in rich:panel or a4j:outputPanel

                        also, in case this helps, mine looks something like the following pseudo-code:
                        <rich:tabPanel>
                         <c:forEach>
                         <c:set firstIndex/>
                         <rich:tab id="tab${firstIndex}">
                         <ui:include/>
                         </rich:tab>
                         </c:forEach>
                        </rich:tabPanel>
                        
                        <a4j:form>
                         <a4j:region>
                         <a4j:jsFunction the one mentioned below oncomplete="refresher();">
                         <a4j:actionparam name="param" assignTo="#{bean.value}"/>
                         more a4j:actionparam components...
                         </a4j:jsFunction>
                         <a4j:jsFunction "refresher" reRender="table-${bean.savedFirstIndexValue}-${bean.savedSecondIndexValue}"/>
                         </a4j:region>
                        </a4j:form>
                        


                        the ui:include file:
                        <c:forEach>
                         <c:set secondIndex/>
                         <h:outputText using secondIndex/>
                         <rich:panel>
                         <f:facet header using secondIndex>
                         <rich:dataTable id="table-${fistIndex}-${secondIndex}>
                         <rich:columns value using secondIndex>
                         <h:inputText onchange running jsFunction with both indexes as function parameters/>
                         </rich:columns>
                         </rich:dataTable>
                         </rich:panel>
                        </c:forEach>
                        


                        notice my rich:tabPanel is not in a form or region... not sure if that makes a difference... i simply did not want it to submit all the values, as there may be hundreds of inputText components (taking forever to submit) and changing one value causes all following values to be recalculated (so they are instead submitted via jsFunction onchange)...

                        hope this helps
                        -Shadow

                        • 9. Re: Dynamic panelbar
                          shadowcreeper Apprentice

                          Also, as you meantioned above, if rich:tabPanel would look recursively for rich:tab objects there would be no need for c:forEach in my code either...

                          Although rich:columns is nice and a rich:tabs would be nice, I believe it would be better to recursively search for useful objects, or at the very least, search recursively inside ui:reapeat and/or a4j:repeat objects for the known expected items (column, tab, panelBarItem, etc...).

                          Is there a reason why this is not done?

                          • 10. Re: Dynamic panelbar
                            Martin Höller Newbie

                            Hi!

                            I just had the same problem and stumbled across this thread. Is this really the only solution to the problem?

                            There is also a JIRA for this problem: https://jira.jboss.org/jira/browse/RF-2772
                            Unfortunately the issue was rejected with a comment saying to use <c:forEach> as described in the forums... :-(
                            I thought using JSTL with facelets is discouraged?

                            Any thoughts?
                            - martin