Custom redirection on Lead Convert operation in salesforce.com

Standard

When you convert a Lead, you will be taken to newly created Account’s detail screen. Thats the standard salesforce.com behaviour.

But what if, you want to show newly created Contact’s detail screen (instead of Account screen), upon Lead conversion? Unfortunately, there is no such setting available in salesforce (yet).

Many people might have achieved it, by some or the other workaround. And here is my trick.

  • Create following Apex Controller class, to use it along with the VF page.
    public class LeadConvertLandingController{
    
        Id newId = null;
        public LeadConvertLandingController(){
            newId = ApexPages.CurrentPage().getParameters().get('newid');
        }
    
        public PageReference redirect(){
            Lead convertedLead = [select ConvertedContactId from Lead where id=:newId];
            PageReference pRef = new PageReference('/' + convertedLead.ConvertedContactId);
            pRef.setRedirect(true);
            return pRef;
        }
    }
    
  • Create a VF page with following markup.
    <apex:page controller="LeadConvertLandingController" action="{!redirect}">
        please wait....
    </apex:page>
    
  • Create a Custom Button for Lead object, as follows:
    • Label = “Convert”.
    • Display type = “Detail Page Button”.
    • Behavior = “Display in existing window without sidebar or header”.
    • Content source = “URL”.
    • And copy below URL in the big text area.
      /lead/leadconvert.jsp?retURL=/{!Lead.Id}&id={!Lead.Id}&saveURL=/apex/LeadConvertLanding
      
  • Now edit the Lead layout and remove the standard Convert button and add the custom Convert button.
  • Thats it!

Hope thats helpful!

Note: This solution works only when, lead conversion is done with new Account/Contact during lead conversion process. It may not work, if existing Account/Contact is chosen, during lead conversion process/screens.

Advertisements

Display Standard Mini Page Layout in Visualforce

Standard

Did you ever run into a situation, when you were asked to display a standard mini page layout in Visualforce, on hover of a link?

Assuming that you haven’t faced the situation, and are not sure how to go about it? Am writing this blog post, to let you know, following options available, to meet the requirement.

  1. Search and download a relevant javascript from internet, and use it in your VF page.
  2. Write your own html/javascript.
  3. Don’t reinvent the wheel. Instead, use salesforce’s standard mini page layout display mechanism.

Per my experience, options 1 & 2 are very time consuming and may not guarantee native look and feel.

However, option 3 is my favorite, as it saves lot of time and effort and is very much native. You just don’t need to write any complicated javascript/html. Instead, you will call some of the salesforce’s javascript functions. Now, that’s smart thinking.

Standard Mini Page Layout in Visualforce

Here is the Visuaforce markup, enjoy!!

<apex:page standardController="Account" recordSetVar="accounts">
<apex:pageBlock >
<apex:pageBlockTable value="{!accounts}" var="acc">
<apex:column headerValue="{!$ObjectType.Account.Fields.Name.Label}">
<a href="/{!acc.id}"
id="lookup{!acc.id}opp4"
onblur="LookupHoverDetail.getHover('lookup{!acc.id}opp4').hide();"
onfocus="LookupHoverDetail.getHover('lookup{!acc.id}opp4', '/{!acc.id}/m?retURL=/{!acc.id}&isAjaxRequest=1').show();"
onmouseout="LookupHoverDetail.getHover('lookup{!acc.id}opp4').hide();"
onmouseover="LookupHoverDetail.getHover('lookup{!acc.id}opp4', '/{!acc.id}/m?retURL=/{!acc.id}&isAjaxRequest=1').show();">
{!acc.Name}
</a>
</apex:column>
<apex:column headerValue="{!$ObjectType.Account.Fields.Type.Label}" value="{!acc.Type}" />
</apex:pageBlockTable>
</apex:pageBlock>
</apex:page>

I tried to keep it simple. However, you can create a re-usable custom component for this and use it where ever you need it.

Hope that’s helpful

Sorting, Pagination in Visualforce using DataTables JQuery plug-in.

Standard

datatables in vf

What is this DataTables.net?
DataTables is a plug-in for the jQuery Javascript library. It is a highly flexible tool, based upon the foundations of progressive enhancement, which will add advanced interaction controls to any HTML table.

My Attempt
I did little bit of dotnet programming in my early days. I remember using ado.net controls for binding data to a list on an aspx page with just drag and drop. It was exciting to be able to pass SQL statements to controls directly in design time.

I always wondered if Salesforce would introduce similar VF components. For good or bad, that didn’t happen. However, Salesforce did a better thing by introducing VF components. Encouraging developers to create their our own VF components and reuse them just like you do in dotnet or java world.

Here is my attempt to create a VF component, which can take SOQL query, List of fields and Headers in design time.

I tried keep the code simple, you may tweak it as needed.

Here is the code…enjoy..!

VF Page

<apex:page docType="html-4.01-strict">
    <c:quickTableComp cContainerId="testtable"
        columnFields="Id, Name, AccountNumber"
        columnTitles="Record ID, Account Name, Account Number"
        soql="select Id, Name, AccountNumber from Account"    
    />
</apex:page>

VF Component

<apex:component controller="quickTableHandler">
    <apex:attribute name="cContainerId" type="String" required="true"  description="Id of the container which will hold & display the table" assignTo="{!cContainerId}"  />
    <apex:attribute name="soql" assignTo="{!soql}" type="String" description="SOQL query to execute and populate records." />
    <apex:attribute name="columnFields" assignTo="{!columnFields}" type="String" description="Comma-separated list of fields to display." />
    <apex:attribute name="columnTitles" assignTo="{!columnTitles}" type="String" description="Comma-separated list of column titles." />

    <link rel="stylesheet" type="text/css" href="http://cdn.datatables.net/1.10.0/css/jquery.dataTables.css"/>
    <script type="text/javascript" src="http://code.jquery.com/jquery-1.10.2.min.js"></script>
    <script type="text/javascript" src="http://cdn.datatables.net/1.10.0/js/jquery.dataTables.js"></script>
    
    <script type="text/javascript">
            $(document).ready( function() {
                $('#{!cContainerId}').dataTable();
            } );
    </script>        

    <div class="full_width">
                
        <table cellpadding="0" cellspacing="0" border="0" class="display" id="{!cContainerId}" style="width:980px">
            <thead>
                <apex:outputPanel layout="none">
                    <tr>
                        <apex:repeat value="{!columnTitlesList}" var="t">
                            <th>
                                <apex:outputText value="{!t}" />
                            </th>                   
                        </apex:repeat>
                    </tr>
                </apex:outputPanel>
            </thead>
            <tbody>
                <apex:repeat value="{!records}" var="r">
                    <tr>
                        <apex:repeat value="{!columnFieldsList}" var="f">
                            <td>
                                <apex:outputField value="{!r[f]}" />
                            </td>
                        </apex:repeat>
                    </tr>
                </apex:repeat>
            </tbody>
        </table>
    </div>    

</apex:component>

Apex Class

public with sharing class quickTableHandler {

    public String columnFields { get; set; }
    public String soql { get; set; }
    public String columnTitles { get; set; }

    public List<String> columnFieldsList {
        get {
            if(columnFieldsList == null && columnFields != null) {
                columnFieldsList = columnFields.split(',');
                for(Integer x = 0; x < columnFieldsList.size(); x++) {
                    columnFieldsList[x] = columnFieldsList[x].trim();
                }
            }
            return columnFieldsList;
        }
        set;
    }
    
    public List<String> columnTitlesList {
        get {
            if(columnTitlesList == null && columnTitles != null) {
                columnTitlesList = columnTitles.split(',');
                for(Integer x = 0; x < columnTitlesList.size(); x++) {
                    columnTitlesList[x] = columnTitlesList[x].trim();
                }
            }
            return columnTitlesList;
        }
        set;
    }

    public List<sObject> records {
        get {
            if(records == null && soql != null) {
                records = Database.query(soql);
            }
            return records;
        }
        set;
    }
}

How to find out, if custom fields are referenced in your code? by using Apex & VF

Standard

How to find out, if custom fields are referenced in your code?

There could be many ways of doing it. Some common ones I keep hearing are:

  • Try deleting a field from salesforce ui, you will know if its referenced anywhere?
  • Do a text search across your code from eclipse ide.
  • etc…

Well, here is my attempt. I will take help of Apex and Visual Force to answer above question.

Many of us may or may not be aware that salesforce provides few important standard objects like:

  • ApexClass
  • ApexPage
  • ApexComponent
  • ApexTrigger

You might be thinking, when do we use these objects? what are the use cases? well, that’s what this blog post attempts to do. To get you start thinking in this direction.

I used little vf and couple of classes to perform a text search across code and tell you if a custom field is referenced anywhere in your code. I tried keeping the code simple, you may tweak it as needed.

So here goes the code..enjoy..!

fields used

VF Page


<apex:page controller="SmartWays" >
 <apex:form >
 <apex:SelectList value="{!selectedObject}" size="1" onchange="initFieldsScript()">
 <apex:selectOptions value="{!Objects}"></apex:selectOptions>
 <apex:actionFunction action="{!initFields}" name="initFieldsScript" rerender="pbtFields">
 </apex:actionFunction>
 </apex:SelectList>
 <apex:pageBlock >
 <apex:pageblocktable value="{!lstFieldResult}" var="field" id="pbtFields">
 <apex:column headervalue="Field Name">{!field.FieldApiName}</apex:column>
 <apex:column headervalue="Is Used">{!field.IsUsed}</apex:column>
 </apex:pageblocktable></apex:pageBlock>
 </apex:form>
 </apex:page>

Apex Class


public class SmartWays{

public String selectedObject {set; get;}
 private List<ApexClass>     lstClasses = new List<ApexClass>();
 private List<ApexComponent> lstComponent = new List<ApexComponent>();
 private List<ApexPage>         lstPage = new List<ApexPage>();
 private List<ApexTrigger>     lstTrigger = new List<ApexTrigger>();
 Map<String, Schema.SObjectType> mapObjects = Schema.getGlobalDescribe();
 public List<FieldsWrapper> lstFieldResult {get; set;}

public SmartWays(){
 lstClasses = [select Name, Body from ApexClass];
 lstPage = [select Name, Markup from ApexPage];
 lstComponent = [select Name, Markup from ApexComponent];
 lstTrigger = [select Name, Body from ApexTrigger];
 selectedObject = '';
 }

public List<SelectOption> getObjects(){
 List<String> sortThis = new List<String>();

List<Schema.SObjectType> gd = mapObjects.Values();
 Set<String> lstKeys = mapObjects.keySet();
 sortThis.addAll(lstKeys);
 sortThis.sort();

List<SelectOption> options = new List<SelectOption>();
 for(String s : sortThis){
 options.add(new SelectOption(s,s));
 }

return options;
 }

public PageReference initFields(){
 lstFieldResult = new List<FieldsWrapper>();
 if(mapObjects.containskey(selectedObject)){
 Schema.SObjectType s = mapObjects.get(selectedObject);
 Schema.DescribeSObjectResult r = s.getDescribe();

Map<String, Schema.SObjectField> fields = r.fields.getMap() ;
 Set<String> fieldnames = fields.keySet();
 List<String> fieldList = new List<String>();
 fieldList.addAll(fieldNames);
 fieldList.sort();
 String fName = '';
 for(integer i=0; i<fieldList.size(); i++){
 fName = fieldList[i];
 if(fName.endswith('__c')){ //only include the custom fields
 FieldsWrapper field = new FieldsWrapper();
 field.FieldApiName = fName;
 field.isUsed = hasReferences(fName);
 lstFieldResult.add(field);
 }
 }
 }
 return null;
 }

private boolean hasReferences(string fieldName){
 Boolean bRet = false;
 for(ApexClass cls:lstClasses){
 if(cls.body.contains(fieldName)){
 bRet = true;
 break;
 }
 }

if(!bRet){
 for(ApexPage pg:lstPage){
 if(pg.Markup.contains(fieldName)){
 bRet = true;
 break;
 }
 }
 }

if(!bRet){
 for(ApexTrigger trg:lstTrigger){
 if(trg.Body.contains(fieldName)){
 bRet = true;
 break;
 }
 }
 }

if(!bRet){
 for(ApexComponent com:lstComponent){
 if(com.Markup.contains(fieldName)){
 bRet = true;
 break;
 }
 }
 }

return bRet;
 }

public class FieldsWrapper{
 public string FieldApiName {set; get;}
 public string FieldLabel {set; get;}
 public boolean isUsed {set; get;}
 }

}

Hope that’s helpful

Get your Visitor’s IP address via sites

Standard

Have you ever ran into a situation, where you need to figure out your site’s visitor’s IP address? Well, many of us may or may not have. But the fact is, while working with sites, sooner or later you will bump into this requirement.

So, like every requirement, even this one can be dealt with, in many different ways. Like

1. Use an existing program like http://jsonip.com or http://jsonip.appspot.com/
2. Write a program (which will return visitor ip) in your choice of language (like php, asp, jsp, etc..) and put it on a web server.
3. Create a public vf page and use apex in the background, to get your visitor’s ip address.

I wouldn’t suggest option # 1 and 2 as they may or may not be available when your visitors come to your site. But if you go with option 3
then its almost certain that your visitor ip address can be traced. Because both your site and ip tracing vf page will be on sfdc servers. So, if a visitor is able to see your site that mean you can trace their ip address, for sure.

Here is the sample code:

VF page: getip


<apex:page controller="getipController" showheader="false" contenttype="application/json">{!ipAddress}</apex:page>

 

Apex class getipController


public class getipController {
 public String ipAddress {get; set;}
 public getipController(){
 ipAddress = ApexPages.currentPage().getHeaders().get('X-Salesforce-SIP');
 }
 }

 

Now that you can have code in place. Go ahead and make this page public from your force.com site.

That’s it. Your ip tracing page is now ready to be used in your site.

Using jQuery, you could make a JSON call:




$.getJSON("your page url", function(data){alert(data);});



 

Hope that’s helpful.