3 Replies Latest reply on Feb 20, 2009 4:08 PM by Val Sw

    Nested DataTable within a UI:Repeat

    Fernando Gonzalez Newbie

      Im having trouble with the following scenario:
      A CustomerSegment can have many subsegments ,and a subsegment can have many filters. What I basically did, was create a ui:repeat that displays all of the subsegments of a given customer segment, and for each subsegment i display a dataTable with all the filters.
      The code is as follows:


      customersegment.xhtml (this is where the create and edit operations on a customer segment happen)


                <ui:repeat value="#{msubsegments}" var="ss">          
                          <rich:panel>
                               <f:facet name="header">Subsegment</f:facet>
                               <h:dataTable value="#{ss.filters}" var="f">                              
                                    <h:column>
                                         <h:outputText value="#{f.variable.name}"/>
                                    </h:column>
                                    <h:column>
                                         <h:outputText value="#{f.value}"/>
                                    </h:column>
                                    <h:column>
                                         <h:commandLink action="#{customerSegmentManager.editFilter(ss,f)}" value="Edit" />
                                    </h:column>
                                    <h:column>
                                         <h:commandLink action="#{customerSegmentManager.deleteFilter(ss,f)}" value="Delete" />
                                    </h:column>
                               </h:dataTable>          
                               <h:commandLink action="#{customerSegmentManager.addFilter}" value="Add Filter" immediate="true"/>
                          </rich:panel>
                          <br/>
                     </ui:repeat>          



      addFilter.xhtml (when you want to add or edit a filter for a given subsegment, you get taken to this page)




                <h:form>
                     Variable: <h:selectOneMenu  value="#{filter.variable}">
                               <s:selectItems value="#{variables}" var="v" label="#{v.name}" />
                               <s:convertEntity/>
                           </h:selectOneMenu> 
                     Association: <h:selectOneMenu value="#{filter.association}">
                               
                              </h:selectOneMenu>
                     Filter: <h:inputText value="#{filter.value}"/>
                     Value: <h:commandButton value="Save" action="#{customerSegmentManager.saveFilter}" />
                </h:form>
      



      and finally this is the customerSegmentManager, which manages all of the CRUD operations of a customerSegment:


      @Name("customerSegmentManager")
      @Scope(ScopeType.CONVERSATION)
      public class CustomerSegmentManager {
           
           @In(create=true) @Out
           CustomerSegment customerSegment;
           
           @DataModel
           List<CustomerSegment> segments;
           
      
           @DataModel
           List<Subsegment> msubsegments;
           
           
           @DataModelSelection("msubsegments")
           @Out(required=false)
           Subsegment subs;
           
           
           @In(create=true) @Out
           Filter filter;
           
           @In
           EntityManager entityManager;
      
           @End
           public String save()
           {
                if(segments!=null)
                {
                     segments.add(customerSegment);
                }
                entityManager.persist(customerSegment);
                return "/customersegments.xhtml";
           }
           
                
           public String addFilter()
           {     filter = new Filter();
                return "/addFilter.xhtml";
           }
      
           
           public String editFilter(Subsegment s,Filter f)
           {
                subs=s;
                filter = s.getFilters().get(s.getFilters().indexOf(f));
                return "/addFilter.xhtml";
           }
           
           
           
           public String deleteFilter(Subsegment s,Filter f)
           {
                s.getFilters().remove(f);          
                return "";
           }
           
           
           public String saveFilter()
           {
                if(subs.getFilters()==null)
                {
                     subs.setFilters( new ArrayList<Filter>() );
                }
                if(subs.getFilters().contains(filter))
                {
                     return "/customersegment.xhtml";
                }
                else
                {
                     filter.setSubsegment(subs);
                     subs.getFilters().add(filter);
                }          
                return "/customersegment.xhtml";
           }
      
           public String addSubsegment()
           {
                if(customerSegment.getSubsegments()==null)
                {
                     ArrayList<Subsegment> list = new ArrayList<Subsegment>();
                     customerSegment.setSubsegments(list);
                }
                Subsegment s = new Subsegment();          
                customerSegment.getSubsegments().add(s);
                s.setSegment(customerSegment);
                msubsegments = customerSegment.getSubsegments();
                return "";
           }
           
           @Begin(join=true)
           public String createSegment()
           {
                return "/customersegment.xhtml";
           }
           
           
           @Factory("msubsegments")
           public void getSubsegments()
           {
                msubsegments = ( customerSegment.getSubsegments()==null ) ?  new ArrayList<Subsegment>() : customerSegment.getSubsegments();
           }
           
           @Factory("segments")
           public void getSegments()
           {
                segments =  (List<CustomerSegment>) entityManager.createQuery("Select s from CustomerSegment s").getResultList();
           }     
           
      }



      the add filter operation works as expected, the subs variable gets correctly filled with the selected subsegment, takes you to the addFilter page, and when you click save it correctly gets saved to the selected subsegment.


      However, when I try to do the edit or delete operations for a filter, the ss variable is ALWAYS the last subsegment of the list. I don't really know why. I can't expose a datamodel for the nested dataTable(the filters one) since it depends on each subsegment.  So i tried passing the paramaters edit(subsegment,filter), but subsegment always returns with the last subsegment of customersegment, without the parameters, the same thing happens, the commandLink sets subs to the last subsegment (I knew without parameters it wouldn't work, as your not clicking the ui:repeat, but the nested h:dataTable), however, i really need a way to know not only which filter was selected, but to which subsegment it belongs.


      Please give me any ideas or solutions (changing the whole workflow, though not ideal, is acceptable)

        • 1. Re: Nested DataTable within a UI:Repeat
          Val Sw Expert
          Have you tried with s:link.

          I am using ui:reapeat, where user can add as well as particular row (I use hashcode), not sure if it will help, but this is brief sample

          <ui:repeat>
          ...

          <s:link action="#{xxxxHome.removeReagentLink}" 
                    value="Remove"
               <f:param name="hashcode" value="#{info.hashCode()}"/>                                                 
          </s:link>
          </ui:repeat>

          xxxxHome.java
          public String removeReagentLink(){          
               javax.faces.context.FacesContext facesContext = (new org.jboss.seam.faces.FacesContext()).getContext();
               javax.servlet.http.HttpServletRequest hsr=(javax.servlet.http.HttpServletRequest)facesContext.getCurrentInstance().getExternalContext().getRequest();
               String reagentHashcode=hsr.getParameter("hashcode");
               
               try {
                    Reagent[] reagentNew=null;          
                    reagentNew=new Reagent[reagent.length-1];
                    
                    int j=0;
                    for(int i=0;i<reagentNew.length;i++){
                         log.info("reagent["+j+"]"+reagent[j].hashCode());
                            if(reagent[j].hashCode()!=Integer.parseInt(reagentHashcode)){
                                 log.info("xxxxHome.removeReagentLink() 1.-->i="+i+"-->j="+j);
                                   reagentNew[i]=reagent[j];
                                   j++;                      
                            }else{
                                 log.info("xxxxHome.removeReagentLink() 2.-->i="+i+"-->j="+j);
                                 i--;
                                 j++;                      
                            }
                    }
                    this.reagent=reagentNew;
               } catch (Exception e) {
                    return "removeReagentLinkError";
               }
               return "";
          }
          • 2. Re: Nested DataTable within a UI:Repeat
            Fernando Gonzalez Newbie

            That worked great thanks!!!. However, it does feel a bit clunky having to use f:params and invoking the facescontext from the server side, when seam is supposed to make all of this easier.


            Would it be too hard to have child components have full access to the parent's component variable?


            As an example for the code above, have ss be visible inside the dataTable, not just at the datatable declaration? (as i tried to use it). This would greatly simplify my problem (and I'm guessing nested dataTables are used commonly in the developer community)

            • 3. Re: Nested DataTable within a UI:Repeat
              Val Sw Expert
              Yes, there can be other better ways, but I faced lot of issues... finally stuck to it as it is working :)

              Here are my details (sorry, just pasted as is, didn't cleaned up), you can check it, not sure if it will help as per your scenario, but don't forget to rate if it helps :)

              1) Your first question
              Below is the code where I am using nested datatable, and getting the details of each entity.

              My entity hierarchy is :
              Project (have list of Experiments) >Experiment(have list of Reagents)>Reagent(have list of treatments)>Treatment.
              Note: I am using rich:dataTable not tried with h:dataTable.

              NESTED "rich:dataTable" XHTML
              ----------------------------
              <ui:define name="body">
                  <h:messages globalOnly="true" styleClass="message" errorClass="errors" infoClass="info" id="globalMessages"/>
                  <rich:panel>
                        ....
                  </rich:panel>
                   
                  <rich:panel header="Details for project #{projectHome.instance.projectName} ">
                  <div class="association" id="quantExperimentChildren">
                     
                      <h:outputText value="No details associated with this project #{projectHome.instance.projectName} for #{identity.username} user.
                                 rendered="#{empty projectHome.quantExperiment}"/>
                     
                      <rich:dataTable value="#{projectHome.quantExperiment}"
                                     var="quantExperiment"
                                rendered="#{not empty projectHome.quantExperiment}"
                              rowClasses="rvgRowOne,rvgRowTwo"
                                      id="quantExperimentTable">      
                          <h:column>
                              <f:facet name="header">Experiment Name</f:facet>
                              <h:outputText value="#{quantExperiment.experimentName}"/>               
                          </h:column>         
                          ...           
                          <h:column>
                              <f:facet name="header">Reagents/ Treatments</f:facet>
                                   <rich:simpleTogglePanel label="View related Reagent and Treatments" switchType="client" opened="false">
                                  <rich:dataTable value="#{quantExperiment.reagent}"
                                              var="reagent"
                                          rendered="#{not empty projectHome.reagent}"                      
                                            rowClasses="rvgRowOne,rvgRowTwo"
                                          id="reagentTable">  
                                       <h:column>
                                            <f:facet name="header">PName</f:facet>
                                            <h:outputText value="#{reagent.pname}"/>
                                        </h:column>
                                        ....                         
                                        <h:column>
                                             <f:facet name="header">Related Treatments</f:facet>
                                            <rich:dataTable value="#{reagent.treatment}"
                                                    var="treatment"
                                                  rowClasses="rvgRowOne,rvgRowTwo"
                                                id="treatmentTable"
                                                rendered="#{not empty reagent.treatment}">
                                                       <h:column>
                                                            <f:facet name="header">Treatment Name</f:facet>
                                                            <h:outputText value="#{treatment.treatmentCompoundName}"/>
                                                        </h:column>
                                                        .....
                                             </rich:dataTable>
                                        </h:column> 
                                                 
                                   </rich:dataTable>
                                   </rich:simpleTogglePanel>
                                   
                              </h:column>       
                         
                          <h:column>
                              <f:facet name="header">Action</f:facet>             
                              <s:link view="/QuantExperimentEdit.xhtml"
                                  id="editExp"
                                    value="Edit Experiment"
                                    action="#{quantExperimentHome.editProject}">                          
                                        <f:param name="quantExperimentHjid"
                                              value="#{quantExperiment.hjid}"/>
                                      <f:param name="quantExperimentFrom" value="Project"/>
                                  </s:link>
                          </h:column>
                      </rich:dataTable>
                     
                  </div>
                  <rich:spacer height="10px"/>
                  <div class="actionButtons">
                        ...                
                  </div>       
                  </rich:panel>
              </ui:define>
              </ui:composition>

              2) I am using nested ui:repeat and getting the values
              xxxxEdit.xhtml
              --------------
              <ui:define name="body">
                  <h:messages globalOnly="true" styleClass="message" errorClass="errors" infoClass="info" id="globalMessages"/>     
                   
                  <h:form id="project" styleClass="edit">
                       <div style="clear:both">
                             <span class="required">*</span>
                               required fields
                      </div>
                      <rich:panel>
                       ...  
                      </rich:panel>
                     
                      <rich:panel>
                        ...       
                      </rich:panel>
                     
                      <rich:dataTable></rich:dataTable>
                      <rich:panel id="reagentPanel">
                        <f:facet name="header">#{reagentHome.managed ? 'Edit' : 'Add/ Edit'} Reagent</f:facet>
                   
                      <table border="1" class="dr-table rich-table" id="color">
                          <thead class="dr-table-thead">
                              <tr class="dr-table-header rich-table-header">
                                  <th class="dr-table-headercell rich-table-headercell" style="width:80px height:20px"><h:outputText value="PName" /></th>
                                  <th class="dr-table-headercell rich-table-headercell" style="width:80px height:20px"><h:outputText value="PType" /></th>
                                  <th class="dr-table-headercell rich-table-headercell" style="width:80px height:20px"><h:outputText value="Color" /></th>
                                  <th class="dr-table-headercell rich-table-headercell" style="width:80px height:20px">
                                       <h:outputText >Affinity Compound</h:outputText>
                                  </th>
                                  <th class="dr-table-headercell rich-table-headercell" style="width:80px height:20px"><h:outputText value="Note" /></th>
                                   <th class="dr-table-headercell rich-table-headercell" style="width:80px height:20px">
                                       <h:outputText value="Treatment details" />
                                  </th>                   
                                  <th class="dr-table-headercell rich-table-headercell" style="width:80px height:20px"><h:outputText value="Action" /></th>
                              </tr>
                          </thead>
                         
                          <ui:repeat value="#{projectHome.reagent}" var="info" >
                         
                          <tbody onmouseover="this.style.backgroundColor='#F8F8F8'"
                                    onmouseout="this.style.backgroundColor='#{a4jSkin.tableBackgroundColor}'">
                                    
                                         <td class="dr-subtable-cell rich-subtable-cell" style="width:80px">
                                                     <s:decorate id="pameField" template="layout/edit.xhtml">                                       
                                                          <h:inputText id="pname1" required="true" value="#{info.pname}"/>
                                                     </s:decorate>
                                                     
                                            </td>
                                      ....
                                     
                                      <td class="dr-subtable-cell rich-subtable-cell" style="width:80px" align="center">
                                                <table id="trtTable" style="width:557px" border="0" class="message">
                                                <tr style="width:557px" align="justify" valign="top">
                                                      <th>Agent Name</th>
                                                      <th>Concentration</th>
                                                      <th>Conc Unit</th>
                                                      <th>Duration</th>
                                                      <th>Time Unit</th>
                                                      <th>Action</th>
                                                 </tr>
                                                <ui:repeat value="#{info.treatment}" var="itreat">
                                                     <tr>
                                                           <td>
                                                                <h:inputText  value="#{itreat.treatmentCompoundName}"/>
                                                           </td>                                             
                                                          ...
                                                           <td class="dr-subtable-cell rich-subtable-cell">                                            
                                                               <s:link action="#{projectHome.removeTreatmentLink}" 
                                                                         value="Remove"
                                                                         onclick="if (!confirm('Are you sure you want to remove this treatment?')) return false;">
                                                                    <f:param name="re_hashcode" value="#{info.hashCode()}"/>
                                                                    <f:param name="tr_hashcode" value="#{itreat.hashCode()}"/>                                                 
                                                             </s:link>
                                                        </td>          
                                                     </tr>
                                                </ui:repeat>  
                                                </table>                               
                                                   <h:commandLink action="#{projectHome.addTreatmentLink}" 
                                                               value="Add treatments"  >
                                                          <f:param name="re_hashcode" value="#{info.hashCode()}"/> 
                                                          <f:param name="re_pname" value="#{info.pname}"/>                                                                                                 
                                                  </h:commandLink>                             
                                         </td>                       
                                      <td class="dr-subtable-cell rich-subtable-cell" style="width:80px" align="center">                                 
                                                <s:link action="#{projectHome.removeReagentLink}" 
                                                          value="Remove"
                                                onclick="if (!confirm('Are you sure you want to remove this reagent?')) return false;">
                                                <f:param name="hashcode" value="#{info.hashCode()}"/>                                                 
                                              </s:link>             
                                      </td>
                          </tbody>
                          </ui:repeat>
                         
                      </table>          
                        </rich:panel>

                        <rich:spacer height="15px"/> 
                        <div class="actionButtons" align="center">     
                            <h:commandLink id="add"
                                 action="#{projectHome.addReagent}"
                                 value="Add More Reagents">          
                            </h:commandLink>
                        </div>
                             
                      <div class="actionButtons">      
                            
                             <table>
                                       <tr>
                                            <td>
                                                 <h:commandLink id="save" title="Creates new project"
                                                action="#{projectHome.persist}"
                                                    disabled="#{!projectHome.wired}"
                                                    rendered="#{!projectHome.managed}"                     
                                                  style="color:black"
                                                       styleClass="button2">
                                                      <span>Save Project</span>
                                                     <rich:componentControl for="panel" attachTo="save" operation="show" event="onclick"/>
                                                 </h:commandLink>
                                            </td>
                                       ..
                                       </tr>
                                  </table>
                            <rich:spacer width="15px"/>
                            ....
                      </div>
                  </h:form>
              </ui:define>
              </ui:composition>