Monday, November 3, 2014

Headervalue not displayed in apex column tag

We have observed a strange behavior in headervalue property in <apex:column>tag. Header value won't display value if it is present within <apex:repeat> tags.

We were having a requirement where we need to display opportunity and its related competitor's record in one row. First Column will display opportunity fields and other columns will display field from different competitors related to opportunity. Number of columns will vary based on number of competitors. In order to display dynamic columns, we used <apex:column>  tags within <apex:repeat> tag. There are few fields which are common to opportunity and competitor object. User should be able to edit these fields for opportunity as well as for competitor in same page.

Below is sample code

public class competitorEntryController {
private String Oppid;
public oppwrapper parentrec{get;set;}
public List<oppwrapper> opplist{get;set;}
public competitorEntryController(Apexpages.standardcontroller controller){
Oppid=(string)controller.getrecord().get('Id');
parentrec=new oppwrapper();
for(Opportunity opp:[select id,name,(select id,name,name__c,Stage__c,NextStep__c from Competitors__r order by name),
Stagename,nextstep from Opportunity where id=:Oppid]){
parentrec.opp=opp;
if(opp.Competitors__r.size()>0){
List<CompetitorWrapper> temp=new List<CompetitorWrapper> ();
for(Competitor__c cm:opp.Competitors__r){
competitorWrapper cw=new competitorWrapper();
cw.comp=cm;
temp.add(cw);
}
parentrec.complist=temp;
}
}
opplist=new List<oppwrapper> ();
system.debug('*******parentrec.complist:'+parentrec.complist);
opplist.add(parentrec);
}
public PageReference Submit(){
//update operation on opportunity and competitor records
Pagereference pag=new PageReference('/'+Oppid);
return pag;
}
public class oppwrapper{
public opportunity opp{get;set;}
public List<CompetitorWrapper> complist{get;set;}
public oppwrapper(){
complist=new List<CompetitorWrapper>();
}
}
public class competitorWrapper{
public Competitor__c comp{get;set;}
}
}
view raw Apex Class hosted with ❤ by GitHub
<apex:page standardController="Opportunity" extensions="competitorEntryController">
<apex:form >
<apex:pageblock title="Competitor section">
<apex:pageblockButtons >
<apex:commandButton value="Save" Action="{!Submit}"/>
</apex:pageblockButtons>
<apex:pageBlocksection title="Using pageblocktable on VF page. problem with Column header value display in repeat tag" columns="1">
<apex:pageblocktable value="{!opplist}" var="op">
<apex:column headervalue="{!Opportunity.name}">
<apex:pageblocksection columns="1">
<apex:inputField value="{!op.opp.stagename}"/>
<apex:inputField value="{!op.opp.nextstep}"/>
</apex:pageblocksection>
</apex:column>
<apex:repeat value="{!op.complist}" var="cp">
<apex:column headervalue="{!cp.comp.name}">
<apex:pageblocksection columns="1">
<apex:inputField value="{!cp.comp.Stage__c}"/>
<apex:inputField value="{!cp.comp.NextStep__c}"/>
</apex:pageblocksection>
</apex:column>
</apex:repeat>
</apex:pageblocktable>
</apex:pageBlocksection>
</apex:pageblock>
</apex:form>
</apex:page>
Output:








In order to resolve this, we used Visualforce Dynamic Components. We created pageblocktable in apex and refereed it VF page.

Below is Code sample
public class competitorEntryController {
private String Oppid;
public oppwrapper parentrec{get;set;}
public List<oppwrapper> opplist{get;set;}
public competitorEntryController(Apexpages.standardcontroller controller){
Oppid=(string)controller.getrecord().get('Id');
parentrec=new oppwrapper();
for(Opportunity opp:[select id,name,(select id,name,name__c,Stage__c,NextStep__c from Competitors__r order by name),Stagename,
nextstep from Opportunity where id=:Oppid]){
parentrec.opp=opp;
if(opp.Competitors__r.size()>0){
List<CompetitorWrapper> temp=new List<CompetitorWrapper> ();
for(Competitor__c cm:opp.Competitors__r){
competitorWrapper cw=new competitorWrapper();
cw.comp=cm;
temp.add(cw);
}
parentrec.complist=temp;
}
}
opplist=new List<oppwrapper> ();
system.debug('*******parentrec.complist:'+parentrec.complist);
opplist.add(parentrec);
}
public PageReference Submit(){
//update operation on opportunity and competitor records
Pagereference pag=new PageReference('/'+Oppid);
return pag;
}
public Component.Apex.PageBlockTable getMyPageBlockTable(){
Component.Apex.PageBlockTable table=new Component.Apex.PageBlockTable(var='op');
table.expressions.value='{!opplist}';
if(opplist.size()>0){
Component.Apex.pageblocksection pgblksec1 = new Component.Apex.pageblocksection ();
pgblksec1.columns=1;
Component.Apex.inputField inputField1 = new Component.Apex.inputField ();
inputField1 .expressions.value = '{!op.opp.stagename}';
pgblksec1.childComponents.add(inputField1);
Component.Apex.inputField inputField2 = new Component.Apex.inputField ();
inputField2.expressions.value = '{!op.opp.nextstep}';
pgblksec1.childComponents.add(inputField2);
Component.Apex.Column column = new Component.Apex.Column(headerValue=opplist[0].opp.name);
column.childComponents.add(pgblksec1);
table.childComponents.add(column);
if(opplist[0].complist.size()>0){
integer count=0;
for(competitorWrapper comp:opplist[0].complist){
Component.Apex.pageblocksection pgblksec2 = new Component.Apex.pageblocksection ();
pgblksec2.columns=1;
Component.Apex.inputField inputField3 = new Component.Apex.inputField ();
inputField3.expressions.value = '{!op.complist['+count+'].comp.Stage__c}';
pgblksec2.childComponents.add(inputField3 );
Component.Apex.inputField inputField4 = new Component.Apex.inputField ();
inputField4.expressions.value = '{!op.complist['+count+'].comp.nextStep__c}';
pgblksec2.childComponents.add(inputField4 );
Component.Apex.Column column1 = new Component.Apex.Column(headerValue='Competitor:'+opplist[0].complist[count].comp.name);
column1.childComponents.add(pgblksec2);
table.childComponents.add(column1);
count++;
}
}
}
return table;
}
public class oppwrapper{
public opportunity opp{get;set;}
public List<CompetitorWrapper> complist{get;set;}
public oppwrapper(){
complist=new List<CompetitorWrapper>();
}
}
public class competitorWrapper{
public Competitor__c comp{get;set;}
}
}
view raw Apex Class hosted with ❤ by GitHub
<apex:page standardController="Opportunity" extensions="competitorEntryController">
<apex:form >
<apex:pageblock title="Competitor section">
<apex:pageblockButtons >
<apex:commandButton value="Save" Action="{!Submit}"/>
</apex:pageblockButtons>
<apex:pageblockSection columns="1" title="Pageblocktable using dynamic visualforce components from Apex">
<apex:dynamicComponent componentValue="{!MyPageBlockTable}" invokeAfterAction="true"/>
</apex:pageblockSection>
</apex:pageblock>
</apex:form>
</apex:page>
Output after using Visualforce Dynamic Components:









Hope this might help you.

For more info on Visualforce Dynamic Components, Check below links:

https://www.salesforce.com/us/developer/docs/pages/Content/pages_dynamic_vf_components_intro.htm
https://developer.salesforce.com/page/Dynamic_Visualforce_Components

Looking forward for everyone's comment and suggestions.