[SalesForce] Rowspan with apex repeat

I try to create a table with rowspan, but get a wrong table, could somebody help to resolve this?

This is my UPD VF Page:

 <apex:page controller="FinancialProductsController" showHeader="false" sidebar="false" action="{!getData}">
 <head>
     <meta name="viewport" content="width=device-width, initial-scale=1"/>
     <apex:stylesheet value="{!URLFOR($Resource.BootstrapMincss)}"/>
     <apex:includeScript value="{!$Resource.JQueryMinJs}"/>
     <apex:includeScript value="{!$Resource.BootstrapMinJs}"/>              
 </head>
 <apex:form id="Form">
     <apex:messages />              
            <table class="table table-bordered">
                 <tr class="headerRow">
                     <th>Business Division</th>
                     <th>Managed By</th>
                     <th>Product</th>
                     <th>Legal Entity</th>
                     <th>Launch Date</th>
                     <th>Sales Guru</th>
                     <th>PMO version (attachment)</th>
                     <th>Internal Presentation (attachment)</th>
                     <th>External Presentation(attachment)</th>
                 </tr>
                 <apex:repeat id="myRepeatHeader" value="{!divisionList}" var="key">         
                     <apex:variable var="count" value="{!1}"/>            
                     <apex:repeat id="contactDetails" value="{!mapDivision[key]}" var="att">
                         <tr>
                            <apex:outputPanel layout="none" rendered="{!count==1}">
                                <td rowspan="{!(divisioncountMap[key])}" style="vertical-align:middle">
                                    <apex:outputText value="{!att.BD}"/>
                                </td>
                            </apex:outputPanel>
                            <td><apex:outputText value="{!att.MB}"/></td>
                            <td><apex:outputText value="{!att.Name}"/></td>
                            <td><apex:outputText value="{!att.LE}"/></td>
                            <td><apex:outputText value="{!att.LD}"/></td>
                            <td><apex:outputText value="{!att.SG}"/></td>

                            <apex:variable var="count" value="{!count+1}"/>
                         </tr>
                     </apex:repeat>
                 </apex:repeat>                               
             </table>                     
 </apex:form>
</apex:page>

And this is my UPD controller:

public class FinancialProductsController {

//map to capture Division Name and List of Financial Products
public Map<String, List<FinProdWrapper>> mapDivision {get; set;} 
//map to capture Division Name and count of Financial Products which will be used to define rowspan.
public Map<String, Integer> divisionCountMap {get; set;}
//to capture list of Division Names
public List<String> divisionList {get; set;}

public FinancialProductsController(){
    mapDivision = new Map<String, List<FinProdWrapper>>();
    divisionCountMap = new Map<String, Integer>();
    divisionList = new List<String>();
}   

//prepare data to display in Visualforce.
public void getData(){
    List<Financial_Product__c> fd = [Select Business_Devision__c, Launch_Date__c, Name, Legal_Entities__c, Link_to_Confluence__c, Managed_by__c, Responsible_PM__c, Sales_Guru__c from Financial_Product__c];

    //grouped into division and prepare the map
    for(Financial_Product__c fdObj : fd){
        List<FinProdWrapper> fpWrapperList = new List<FinProdWrapper>();
        //verify map already contains same Division Name
        if(mapDivision.containsKey(fdObj.Business_Devision__c)){
            //retrieve the list of existing Financial Products
            fpWrapperList = mapDivision.get(fdObj.Business_Devision__c);
            //put the new Financial Product to the list
            fpWrapperList.add(new FinProdWrapper(fdObj));

            mapDivision.put(fdObj.Business_Devision__c, fpWrapperList);
            divisionCountMap.put(fdObj.Business_Devision__c, fpWrapperList.size());
        }                        
        else{
            //create a new map of Division Name
            fpWrapperList.add(new FinProdWrapper(fdObj));
            mapDivision.put(fdObj.Business_Devision__c, fpWrapperList);
            divisionCountMap.put(fdObj.Business_Devision__c, fpWrapperList.size());                
        }
    }
    //create a list of Division Names which will be helpful to iterate
    divisionList = new List<String>(mapDivision.keySet());
}

public Class FinProdWrapper {

    public FinProdWrapper(Financial_Product__c fn){
        this.Name = fn.Name;
        this.BD = fn.Business_Devision__c;
        this.LD = fn.Launch_Date__c.format();
        this.LE = fn.Legal_Entities__c;
        this.LTC = fn.Link_to_Confluence__c;
        this.MB = fn.Managed_by__c;
        this.RPM = fn.Responsible_PM__c;
        this.SG = fn.Sales_Guru__c;
    }

    public String Name {get; set;}
    public String BD {get; set;}
    public String LD {get; set;}
    public String LE {get; set;}
    public String LTC {get; set;}
    public String MB {get; set;}
    public String RPM {get; set;}
    public String SG {get; set;}        
}        

}

As You recomend I try to create a wrapper class, and I get first column dinamically makes rowspan. But I don't get how to make the second column make rowspan as the first column.

Now I Have:

  A  |  B  |  C  |  D  |
     |  B1 |  C1 |  D1 |
  A1 |  B1 |  C2 |  D2 |
     |  B1 |  C3 |  D3 |

But I need:

  A  |  B  |  C  |  D  |
     |     |  C1 |  D1 |
  A1 |  B1 |  C2 |  D2 |
     |     |  C3 |  D3 |

Best Answer

Examples such as this one HTML rowspan Attribute reduce the number of td elements in the following rows (as rowspan is effectively saying use the content from the previous row).

So you need to modify your code to only output these td elements once in every 3 rows:

                 <td rowspan="3">{!fd.Business_Devision__c}</td>
                 <td rowspan="3">{!fd.Managed_by__c}</td>

That is probably going to take the introduction of an apex:variable that you use to count. (Or you could introduce a wrapper class where you pre-calculate a true/false for the output on the server-side.) Plus an apex:outputPanel of layout="none" to do the conditional rendering of the pair of td elements.

Related Topic