Blog entry posted for: Rahul - Comity Intern (Summer’2011)
..
One of the limitations of the Salesforce.com platform is that it does not allow developers to inject their own logic into an Approval Process, especially when using standard VisualForce tags. With standard related lists (not custom components) columns cannot be customized to display custom information.
One common way of working around this limitation is to replicate the relatedList as a custom component where you duplicate the look and feel utilizing the pageBlockTable VF tag, thereby having the ability to add any custom logic. This approach is more rewarding but far more time consuming and not always necessary.
Another quicker mechanism to bypass this limitation is to use a combination of CSS and HTML tags and attributes on a page in addition to APEX code that replicates the needed standard functionality.
As an example, let us take a look at a use case that requires us to perform a check and display an error message on a VF page upon clicking the Approve/Reject Link from the ProcessSteps relatedList i.e. the Approval History.
One way to approach this, as highlighted in this post is to use CSS to hide the actionColumn on the standard relatedList, then provide commandButtons or commandLinks above or below the relatedList allowing the user to run custom pre-defined APEX logic.
In the event that the business does not require a heavily customized solution, modifying a standard related list can be the faster and more reasonable approach. However, its functionality is also limited, in the sense that using this method only allows the hiding of pre-existing columns that would otherwise be shown in the relatedList implementation. The addition of new columns is not possible and in this case one must revert to the complete custom solution.
For hiding the Action column:
Insert the following code on the Custom VF Page in the correct place as specified by the tags:
<style>
/* === Hides Action Column for Approval History === */
[class$='actionColumn']
{display:none}
/* === END === */
</style>
NOTE: This will cause all columns of the name actionColumn to be hidden on the page, so only use this implementation if you are sure that nothing else has the same name or else it will disappear as well.
A better way would be to find the columnID because this is guaranteed to be unique at least within the page, but this is not always possible, as it was in this case.
So you could use this method to hide a column from a custom element in a similar manner.
To add commandButtons that do the same thing:
Insert the following code in the correct place on the Custom VF Page, either above or below the code that either looks like or contains the following: <apex:relatedList list=“ProcessSteps”></apex:relatedList>
<!– Buttons that mimic the functionality of the Action Column in the Approval History Related List –>
<apex:form>
<apex:pageBlock id=“appRej”>
<apex:pageBlockButtons location=“top” id=“appHistButtons”>
<apex:actionRegion >
<apex:commandLink value=“Approve/Reject” id=“appRejectBtn” styleClass=“btn” style=”padding:2px 5px 3px 5px; text-decoration:none;” action=“{!ApprRej}” />
</apex:actionRegion>
<apex:actionRegion >
<apex:commandLink value=“Reassign” id=“ReassignBtn” styleClass=“btn” style=”padding:2px 5px 3px 5px; text-decoration:none;” action=“{!Reassign}” />
</apex:actionRegion>
</apex:pageBlockButtons>
</apex:pageBlock>
</apex:form>
<!– END –>
In your controller extension, create the functions that these buttons are associated to as shown below (assuming that all variables needed, functions referenced etc. have been already predefined and setup elsewhere):
// Function called when Approve/Reject Button is clicked
public PageReference ApprRej()
{
// runs the check
approvePossible();
// if the check fails then it changes the flag to display error message and re-renders the current Page
if(canApprove == false)
{
canApprove2 = false;
PageReference pageRef = ApexPages.currentPage();
pageRef.setRedirect(true);
return null;
}
// if check is successful then it runs a SOQL query to get the Approval ID and uses that to redirect to the relevant Approve/Reject page
else
{
List<ProcessInstanceWorkItem> workItemList = [Select p.ProcessInstance.Status, p.ProcessInstance.TargetObjectId,p.ProcessInstanceId,p.OriginalActorId,p.Id,p.ActorId From ProcessInstanceWorkitem p where p.ProcessInstance.TargetObjectId = :opp.Id];
String strAppId = workItemList[0].Id;
String partialURL = ‘/p/process/ProcessInstanceWorkitemWizardStageManager?id=’ + strAppId;
canApprove2 = true;
PageReference pageRef = new PageReference(partialURL);
pageRef.setRedirect(true);
return pageRef;
}
}
// Function called when Reassign Button is clicked
public PageReference Reassign()
{
// runs a SOQL query to get the Approval ID and uses that to redirect to the relevant Reassign page
List<ProcessInstanceWorkItem> workItemList = [Select p.ProcessInstance.Status, p.ProcessInstance.TargetObjectId,p.ProcessInstanceId,p.OriginalActorId,p.Id,p.ActorId
From ProcessInstanceWorkitem p where p.ProcessInstance.TargetObjectId = :opp.Id];
String strAppId = workItemList[0].Id;
String partialURL = ‘/’ + strAppId + ‘/e?et=REASSIGN&retURL=apex/GMAView?id=’ + gma.Id + ‘&sfdc.override=1′;
PageReference pageRef = new PageReference(partialURL);
return pageRef;
}
In this case, it is presumed that the page has an element that is rendered based on some flag canApprove2
<apex: outputPanel style=”color:red;font-size:150%” rendered=“{!NOT(canApprove2)}”>
<br/>Sample error message is displayed here<br/>
</apex:outputPanel>
NOTE: A better way of constructing the partial URLs is to avoid any hard-coding and instead use the setParameter and getParameter methods.
In case you do need to hard-code for any reason, as I have done in the above example, then you would need to click on the actionColumn commandLink that takes you to the standard page, and then copy and cleanup the URL by identifying and segregating the record ID, and also removing anywildcard or dummy Unicode/UTF characters.
For example, a URL that looks like this:
https://cs4.salesforce.com/04iP01234564ks0IAA/e?et=REASSIGN&retURL=apex%2FGMAView%3Fid%3D006P6543213MiuTIAS&sfdc.override=1
It has characters such as %2F which should be replaced by / or %3F which should be changed to the = sign etc accordingly, as is necessary. This applies to ANY and ALL salesforce.com URLs.
Also, partialURLs should always be used preferably over fullURLs to facilitate migration of code between orgs.
The end result is that something that originally looked like this:

Can now be seen showing up as this:

Observe that the left-hand most column missing, and also notice how the 2 new buttons have appeared at the bottom.
Continue Reading