11 Replies Latest reply on Nov 24, 2009 12:14 AM by Dean Hiller

    ui:repeat and c:forEach not working inside dataTable

    Ken Clark Newbie

      I am trying to get a solution working for dynamically viewable and moveable columns in a dataTable.  I have tried c:forEach and ui:repeat for the columns, but neither works correctly.  I have two values in a List.  In the case of forEach, it only iterates once, and passes in a blank value to the action method, and in the case of ui:repeat, it does not iterate.


      It seems to me that this should work, but so far no luck.


      Any ideas?


      Here is the facelet code:



      <ice:dataTable id="issuesList" value='#{issueNodes}' rows="10" var='issueNode' border="1"
                cellpadding="2" cellspacing="0" sortColumn="#{issuesSortColumnName}"
                   sortAscending="#{issuesSortAscending}">
         <h:column .../>
         <ui:repeat value="#{issueColumnIds}" var="columnId">
         <!--c:forEach var="columnId" items="#{issueColumnIds}"-->
           <h:column>
             <f:facet name="header">
               <h:outputText value="#{issueAction.getHeader(columnId)}"/>
             </f:facet>
             <ice:outputText value="#{issueAction.getColumnValue(issueNode,columnId)}"/>
           </h:column>
         <!--/c:forEach-->
         </ui:repeat>
      



      and here is a snippet of the Action bean:



      @Stateful
      @Name("issueAction")
      public class IssueAction extends BaseNodeAction implements IssueActionLocal
      {
          @Out(required=false)
          private List<String> issueColumnIds = null;
          
          // ...
      
          @Begin(join=true)
          public String list(NodeQueryKey parentKey)
          {
              // Set up the dynamic columns
              issueColumnIds = new ArrayList<String>();
              issueColumnIds.add("id");
              issueColumnIds.add("priority");
              
              // ...
          }
      
          public String getHeader (String columnId)
          {
              // To be implemented
              return columnId;
          }
          
          public Object getColumnValue(IssueNode issueNode, String columnId)
          {
              if ("id".equals(columnId))
              {
                  return issueNode.getNodeId();
              }
              if ("priority".equals(columnId))
              {
                  return issueNode.getPriority();
              }
      
              return "[Unknown Column]";
          }
      
          // ...
      }
      



      Thanks,
      ken

        • 1. Re: ui:repeat and c:forEach not working inside dataTable
          Ken Clark Newbie

          Note: I simplified this just as a test to eliminate any possible issues calling the action bean methods (see below).


          The problem still persists as described above.  forEach returns 1 columnId that is blank, and ui:repeat does not iterate any columns.


          
          <ice:dataTable id="issuesList" value='#{issueNodes}' rows="10" var='issueNode' border="1"
          
                    cellpadding="2" cellspacing="0" sortColumn="#{issuesSortColumnName}"
          
                       sortAscending="#{issuesSortAscending}">
          
             <h:column .../>
          
             <ui:repeat value="#{issueColumnIds}" var="columnId">
          
             <!--c:forEach var="columnId" items="#{issueColumnIds}"-->
          
               <h:column>
          
                 <f:facet name="header">
          
                   <h:outputText value="#{columnId}"/>
          
                 </f:facet>
          
                 <ice:outputText value="#{columnId)}"/>
          
               </h:column>
          
             <!--/c:forEach-->
          
             </ui:repeat>
          
          



          Thanks,
          ken

          • 2. Re: ui:repeat and c:forEach not working inside dataTable
            Daniel Hinojosa Master

            Oh, I was thinking about your issue....what happens if you test it out using <h:dataTable> instead of ice's implementation.  It could be that this is an ice implementation problem.

            • 3. Re: ui:repeat and c:forEach not working inside dataTable
              System Administrator Expert

              you can also try <rich:dataTable>.


              what do you mean exactly by:


              dynamically viewable and moveable columns in a dataTable?


              are you asking about changing the physical order of the columns by dragging/releasing?


              and hiding/showing columns via clicking, etc.?

              • 4. Re: ui:repeat and c:forEach not working inside dataTable
                Samuel Mendenhall Apprentice

                It does work with rich:dataTable so you'll want to try with that, see the work I did @ http://wiki.jboss.org/auth/wiki/DynamicCrud  specifically:



                <ui:composition  xmlns="http://www.w3.org/1999/xhtml"
                                 xmlns:ui="http://java.sun.com/jsf/facelets"
                                 xmlns:h="http://java.sun.com/jsf/html"
                                 xmlns:f="http://java.sun.com/jsf/core"
                                 xmlns:s="http://jboss.com/products/seam/taglib"
                                 xmlns:rich="http://richfaces.org/rich"
                                 xmlns:a="http://richfaces.org/a4j"
                                 xmlns:e="http://org.el.func/SeamFunc"
                                 xmlns:c="http://java.sun.com/jstl/core">
                    
                    <c:if test="${empty entityIdName}">
                                <c:set var="entityIdName" value="#{controlKey}Id" />
                        </c:if>
                        
                        <c:if test="${empty entityQuery}">
                                <c:set var="entityQuery" value="#{e:evalEl(e:concat(controlKey, 'List'))}" />
                        </c:if>
                        
                        <c:if test="${empty entityIdField}">
                                <c:set var="entityIdField" value="id" />
                        </c:if>
                        
                        <c:if test="${empty entityView}">
                                <c:set var="entityView" value="/#{controlKey}.xhtml" />
                        </c:if>
                        
                        <c:if test="${empty excludedFields}">
                                <c:set var="excludedFields" value="version" />
                        </c:if>
                        
                        <c:if test="${empty tableId}">
                                <c:set var="tableId" value="#{controlKey}Table" />
                        </c:if>
                        
                        <c:if test="${empty linkedFields}">
                                <c:set var="linkedFields" value="id" />
                        </c:if>
                        
                    
                    <rich:dataTable id="#{tableId}" 
                                    var="entity"
                                    value="#{entityQuery.resultList}" 
                                    rendered="#{not empty entityQuery.resultList}"
                                    onRowMouseOver="this.style.backgroundColor='#F1F1F1'"
                                    onRowMouseOut="this.style.backgroundColor='#{a4jSkin.tableBackgroundColor}'">
                        
                                <c:forEach items="#{entityQuery[controlKey].getClass().getDeclaredFields()}" var="field">
                                
                                        <e:setPropertyBindings valueBinding="#{field.name}" endsWith="ListLabel"/>
                                        <e:setPropertyBindings valueBinding="#{field.name}" endsWith="EnumLabel"/>
                                        <e:setPropertyBindings valueBinding="#{field.name}" endsWith="DatePattern"/>
                                
                                    <rich:column rendered="#{!e:csvContains(excludedFields, field.name)}">
                                        <f:facet name="header">#{e:capitalize(field.name)}</f:facet>
                                        
                                        <e:setValueBinding var="vb" valueBinding="#{entityQuery[controlKey][field.name]}"/>
                                        
                                        <e:isDate id="vb">
                                                        <h:outputText value="#{entity[field.name]}">
                                                                <s:convertDateTime pattern="#{e:evalEl(e:concat(field.name, 'DatePattern'))}"/>
                                                    </h:outputText>
                                                </e:isDate>
                                                
                                                <e:isText id="vb">
                                                    <s:fragment rendered="#{e:csvContains(linkedFields, field.name)}">
                                                            <s:link view="#{entityView}" value="#{entity[field.name]}">
                                                                        <f:param name="#{entityIdName}" value="#{entity[entityIdField]}"/>
                                                            </s:link>
                                                        </s:fragment>
                                                        <s:fragment rendered="#{!e:csvContains(linkedFields, field.name)}">
                                                            #{entity[field.name]}
                                                        </s:fragment>
                                                </e:isText>
                                                
                                                <e:isList id="vb">
                                                        #{entity[field.name]}
                                                </e:isList>
                                                
                                                <e:isEnum id="vb">
                                                    <e:setValueBinding var="enumLabel" valueBinding="#{e:evalEl(e:concat(field.name, 'EnumLabel'))}"/>
                                                    #{enumLabel == '' ? entity[field.name] : entity[field.name][enumLabel]}
                                                </e:isEnum>
                                    
                                                <e:isBoolean id="vb">
                                                #{entity[field.name]}
                                                </e:isBoolean>
                                    </rich:column>
                                </c:forEach>
                                
                    </rich:dataTable>
                    
                </ui:composition>
                


                • 5. Re: ui:repeat and c:forEach not working inside dataTable
                  Ken Clark Newbie

                  I did try h:dataTable and found no difference.  I have a feeling the subject of my original post is inaccurate.  I think I have a problem with outjection or scope.


                  I tried a couple other things.  First I changed the outjection scope on issueColumnIds:


                  
                      @Out(required=false, scope=ScopeType.SESSION)
                  
                      private List<String> issueColumnIds = null;
                  
                  



                  This also made no difference.  I also tried PAGE scope.


                  The other thing I tried was changing the reference in the facelet code to something I knew existed nowhere:


                  
                  <c:forEach var="columnId" items="#{issueColumnIdsJUNKJUNK}">
                  
                  



                  This also had no difference.  In other words it seems as if the forEach and repeat tags do not appear to work, but in reality just cannot resolve the reference to the outjected issueColumnIds field.


                  Does anyone know how this can happen?


                  Thanks,
                  ken

                  • 6. Re: ui:repeat and c:forEach not working inside dataTable
                    Daniel Hinojosa Master

                    May we see the code where issueColumnIds is and how its affected?


                    • 7. Re: ui:repeat and c:forEach not working inside dataTable
                      Ken Clark Newbie

                      There is no other code which touches the issueColumnIds attribute other than what I put in my original post.  Ultimately there will be a great deal more, but since I am stuck at the simplest spot, I just stopped here until I resolve this problem.


                      I made some additional usages of the c:forEach and ui:repeat tags in the same xhtml page outside and inside the dataTable and found some very interesting things:


                      - forEach, no matter where I put it, always iterates one time and returns an empty string.  I think it just does not work with outjected values in Seam for some reason


                      - by contrast, ui:repeat works correctly ALMOST ALWAYS.  The one place it does not work is as I have it, with a child h:column.  In this case, there are no child h:columns that are ever built.  I can't explain this.


                      - if I just make simple uses of ui:iterate, as below, it seems to work as expected.



                      <ui:repeat value="#{issueColumnIds}" var="columnId">
                        <h:outputText value="#{columnId}"/>
                      </ui:repeat>
                      



                      Does any of that trigger any thoughts?


                      Thanks,
                      ken


                      • 8. Re: ui:repeat and c:forEach not working inside dataTable
                        Samuel Mendenhall Apprentice

                        This stuff is really tricky and does require quite a bit of trial and error, keep at it.  c:forEach should work, for a bit more on dynamic columns see: http://wiki.jboss.org/wiki/DynamicColumns  which comes from the Richfaces perspective.


                        Best thing to do is copy code that works as your basis the modify it to suit your needs.


                        -Samuel

                        • 9. Re: ui:repeat and c:forEach not working inside dataTable
                          judy guglielmin Novice

                          The data table only expects column elements as children.  The c:foreach is called before the components dump their values into the model and ui:repeat is called before the render response phase. 
                          To use the ice components effectively, you should be using the ice:column component to iterate over the list (another option would be to use an html table element and children in combination with two ui:repeats. 


                          Option 1:-


                          //Columns


                          <ice:dataTable id="issuesList" value="#issueNodes}" rows = "10" var="issueNode" border="1"
                                  cellpadding="2" cellspacing="0" sortColumn="#{issuesSortColumnName}"
                                  sortAscending="#{issuesSortAscending}">
                                 <ice:columns value="#{issueColumnIds}" var="columndId">
                                    <f:facet name="header">
                                       <h:outputText value="#{issueAction.getHeader(columnId)}"/>
                                    </f:facet>
                                    <ice:outputText value="#{issueAction.getColumnValue(issueNode,columnId)}"/>
                                 </ice:columns>
                           </ice:dataTable>
                          
                          
                          Option 2 Html Table:-
                          <table>
                               <!-- header -->
                               <ui:param value='#{issueNodes[0]}' name='issueNode' />
                                    <tr>
                                         <ui:repeat value="#{issueColumnIds}" var="columnId"
                          > >
                                              <th><h:outputText
                          value="#{issueAction.getHeader(columnId)}"/></th>
                                      </ui:repeat>
                                     </tr>
                            <!-- body -->
                               <ui:repeat value='#{issueNodes}' var='issueNode'>
                                     <tr>
                                     <ui:repeat value="#{issueColumnIds}" var="columnId" >
                                               <td>
                                          <ice:outputText
                          value="#{issueAction.getColumnValue(issueNode,columnId)}"/>
                                     <td>
                                     </ui:repeat>
                                     </tr>
                               </ui:repeat>
                          </table>
                          
                          



                          For more timely help with ICEfaces, you may want to post to the ICEfaces forum.  Also, sometimes when I search this forum for ICEfaces issues, I don't always see them all and users don't always tag them properly.

                          • 10. Re: ui:repeat and c:forEach not working inside dataTable
                            Dean Hiller Expert

                            Anyone know how to get the sortBy to work with using the forEach?  I have a pageable rich:dataTable (ie. using ExtendedDataModel so it does not load too many records in memory).  It all works except for the sortBy which seems to only want to sort by things on the entity returned :(.




                                      <rich:dataTable width="600" id="listTable" rows="#{queryManager.resultsPerPage}"
                                           reRender="datascroller"
                                           value="#{queryManager.dataModel}"
                                           rendered="#{queryManager.dataModel ne null}"
                                           var="tpvTrans">
                                           <f:facet name="header">
                                                <h:outputText value="Call Records" />
                                           </f:facet>
                                           
                                           <c:forEach var="col" items="#{queryManager.columns}">
                                                <rich:column sortBy="#{tpvTrans.getValue(col)}">
                                                     <f:facet name="header"> 
                                                          <s:div>
                                                          #{col.label}
                                                          </s:div>                                        
                                                     </f:facet>
                                                        #{tpvTrans.getValue(col)}
                                                </rich:column>     
                                           </c:forEach>
                                           
                                           <f:facet name="footer">
                                                <rich:datascroller id="datascroller" />
                                           </f:facet>
                                      </rich:dataTable>          
                            



                            • 11. Re: ui:repeat and c:forEach not working inside dataTable
                              Dean Hiller Expert

                              ah, never mind, I think I have this now with EL in the java code...


                              ValueExpression valueExpression = (ValueExpression) expression;
                              ELContext elContext = FacesContext.getCurrentInstance().getELContext();
                              Object value = valueExpression.getValue(elContext);
                              



                              and then the value is the string and I can manipulate that in themodel to add to the Hibernate Criteria object.