This was an assignment given by one of my friend on Nov 12th, 2011. I thought it was an easy task, just making a visual force page with pagination it, but to my surprise, it was not -:(
So, here is the objective, putting it in exact words of my dear friend:
“You have accounts and a number of opportunities at different stages are associated to them. You have to design an inline Visualforce page on account detail page that shows a dropdown containing various opportunity stages. When user selects any of the listed stage, the PageBlockTable should show the all the Opportunities with the selected stage.”
This was the basic requirement, now comes the tough part:
1. It should also use the pagination with first, last, previous, next and page size options.
2. It should also use sorting and the entire functionality should be ajaxified.
I started designing the page and finished the basic functionality in 2 hours. Then came the pagination part for which I knew I cannot use standard list controllers, so I decided to use a custom class, SObjectPaginator from the package Apex-lang(
http://code.google.com/p/apex-lang/). All thanks to Richard Vanhook for developing Apex-lang and making our lives easier.
It’s very easy to use to SObjectPaginator, you just need to implement the interface and the method handlePageChange(List newPage) and call the SObjectPaginator.setRecords(List) to set the records in pagination.
Solution:
Here is the screenshot of what came out after 8 hours of hard work.
|
Inline visualforce page on account detail page |
The Visualforce Page:
<apex:page standardController="Account" extensions="OpportunityOnAccountDetailExtension">
<apex:form >
<apex:pageBlock mode="edit" >
<apex:pageBlockSection columns="1">
<apex:outputText >
<B>Select an Opportunity stage to view opportunities related to this account:</B>
</apex:outputText>
<apex:actionRegion >
<apex:selectList size="1" multiselect="false" value="{!selectedStage}" >
<apex:selectOptions value="{!Items}" />
<apex:actionSupport event="onchange"
action="{!handleAccountSelected}"
rerender="pbs1"
status="status"/ >
</apex:selectList>
</apex:actionRegion>
</apex:PageBlockSection>
<apex:pageBlockSection columns="1" id="pbs1">
<apex:actionstatus id="status" startText="testing...">
<apex:facet name="stop">
Opportunity Stage Selected: <apex:outputText value="{!selectedStage}" />
<apex:pageBlockTable value="{!accounts}" var="opp" id="pb1">
<apex:column value="{!opp.obj.name}" />
<apex:column value="{!opp.obj.StageName}" />
<apex:column value="{!opp.obj.Amount}" />
<apex:column value="{!opp.obj.CloseDate}" />
<apex:facet name="footer">
<apex:outputPanel layout="block">
<!-- PAGE X OF X IN X RESULTS -->
Page {!IF(paginator.pageCount=0, 0, paginator.pageNumberDisplayFriendly)} of {!paginator.pageCount} in {!paginator.recordCount} results
<!-- FIRST -->
<apex:outputText value="First"
rendered="{!NOT(paginator.hasPrevious)}" />
<apex:commandLink value="First"
rendered="{!paginator.hasPrevious}"
action="{!paginator.first}" />
<!-- PREVIOUS -->
<apex:outputText value="Previous"
rendered="{!NOT(paginator.hasPrevious)}" />
<apex:commandLink value="Previous"
rendered="{!paginator.hasPrevious}"
action="{!paginator.previous}" />
<!-- PAGE SHORTCUTS -->
<apex:repeat value="{!paginator.previousSkipPageNumbers}" var="skipPageNumber">
<apex:outputPanel >
<apex:commandLink value="{!skipPageNumber+1}" action="{!skipToPage}">
<apex:param name="pageNumber" id="pageNumber" value="{!skipPageNumber}" assignto="{!pageNumber}" />
</apex:commandLink>
</apex:outputPanel>
</apex:repeat>
<apex:outputText style="text-decoration:none; font-weight:bold; background-color: #FFFF00"
value="{!paginator.pageNumber+1}"/>
<apex:repeat value="{!paginator.nextSkipPageNumbers}" var="skipPageNumber">
<apex:outputPanel >
<apex:commandLink value="{!skipPageNumber+1}" action="{!skipToPage}">
<apex:param name="pageNumber" id="pageNumber" value="{!skipPageNumber}" assignto="{!pageNumber}" />
</apex:commandLink>
</apex:outputPanel>
</apex:repeat>
<!-- NEXT -->
<apex:outputText value="Next"
rendered="{!NOT(paginator.hasNext)}" />
<apex:commandLink value="Next"
rendered="{!paginator.hasNext}"
action="{!paginator.next}" />
<!-- LAST -->
<apex:outputText value="Last"
rendered="{!NOT(paginator.hasNext)}" />
<apex:commandLink value="Last"
rendered="{!paginator.hasNext}"
action="{!paginator.last}" />
<!-- Page Size Options -->
Page Size:
<apex:actionRegion >
<apex:selectList value="{!paginator.pageSize}"
size="1">
<apex:selectOptions value="{!paginator.pageSizeOptions}" />
<apex:actionSupport event="onchange"
rerender="pbs1"
status="status" />
</apex:selectList>
</apex:actionRegion>
</apex:outputPanel>
</apex:facet>
</apex:pageBlockTable>
</apex:facet>
</apex:actionstatus>
</apex:PageBlockSection>
</apex:pageBlock>
</apex:form>
</apex:page>
The Controller Code:
global class OpportunityOnAccountDetailExtension implements SObjectPaginatorListener {
String selectedStage;
Account acc;
global List accounts {get;set;}
global SObjectPaginator paginator {get;set;}
global Integer pageNumber {get;set;}
private String sortDirection = 'ASC';
private String sortExp = 'name';
List oppList = new List();
public OpportunityOnAccountDetailExtension(ApexPages.StandardController controller) {
this.acc = (Account)controller.getRecord();
oppList = null;
this.accounts = new List();
this.paginator = new SObjectPaginator(
2, //pageSize
new List{2,5,10, 25, 50, 100, 200}, //pageSizeIntegerOptions
this //listener
);
//this.paginator.setRecords(getoppList());
}
public String getselectedStage() {
return selectedStage;
}
public void setselectedStage(String selectedStage) {
system.debug('%%%%%%%%%%%% ' + this.selectedStage);
this.selectedStage = selectedStage;
system.debug('%%%%%%%%%%%% ' + this.selectedStage);
}
public List getItems() {
List options = new List();
options.add(new SelectOption('','--SELECT Opportunity Stage--'));
Schema.DescribeFieldResult field = Opportunity.StageName.getDescribe();
for (Schema.PicklistEntry f : field.getPicklistValues())
options.add(new SelectOption(f.getLabel(),f.getLabel()));
return options;
}
/*
public List getoppList(){
system.debug('$$$$$$$$$$$$$$$$$$ ' + selectedStage);
if(selectedStage==null){
oppList = null;
}else{
oppList = [select name, stageName, Amount, CloseDate from Opportunity where AccountId =: acc.id and StageName =: String.escapeSingleQuotes(selectedStage)];
}
return oppList;
}
*/
public PageReference handleAccountSelected(){
system.debug('$$$$$$$$$$ in handleAccountSelected()');
string sortFullExp = sortExpression + ' ' + sortDirection;
string query = 'select name, stageName, Amount, CloseDate from Opportunity where AccountId =';
query = query + ' ' + acc.id + ' ' + ' ';
query = query + 'and StageName =' + ' ' + String.escapeSingleQuotes(selectedStage) + ' '+ ' order by ' + sortFullExp;
system.debug('################## ' + query);
this.paginator.setRecords([select name, stageName, Amount, CloseDate from Opportunity where AccountId =: acc.id and StageName =: String.escapeSingleQuotes(selectedStage)]);
return null;
}
public PageReference test(){
return null;
}
global void handlePageChange(List newPage){
this.accounts.clear();
if(newPage != null && newPage.size() > 0){
for(Integer i = 0; i < newPage.size(); i++){
this.accounts.add(
new OppWrapper(
(Opportunity)newPage.get(i)
, i + this.paginator.pageStartPosition + 1
)
);
}
}
}
global PageReference skipToPage(){
this.paginator.skipToPage(pageNumber);
return null;
}
public String sortExpression
{
get
{
return sortExp;
}
set
{
//if the column is clicked on then switch between Ascending and Descending modes
if (value == sortExp)
sortDirection = (sortDirection == 'ASC')? 'DESC' : 'ASC';
else
sortDirection = 'ASC';
sortExp = value;
}
}
public String getSortDirection()
{
//if not column is selected
if (sortExpression == null || sortExpression == '')
return 'ASC';
else
return sortDirection;
}
public void setSortDirection(String value)
{
sortDirection = value;
}
public class OppWrapper{
public Opportunity obj{get;set;}
public Integer serialNumber{get;set;}
public Boolean selected{get;set;}
public OppWrapper(Opportunity obj, Integer serialNumber){
this.obj = obj;
this.serialNumber = serialNumber;
system.debug('@@@@@@@@@@@@@@@@ ' + obj.Name);
}
}
}