Wednesday, 7 October 2015

Dynamic CustomField ID in URL hacking through Tooling API (Getting custom field id from Tooling API dynamically)

As we know that when want to autopopulate a custom field on standard insertion page from a custom button we do url hacking with custom field id. But custom field id is different from one org to other org. So when we deploy the custom button then again we have to replace the custom field id from the destination org. That means we have to change custom field ids whenever we deploy custom button from one org to another org manually.
If we do the same thing dynamically we don't need to worry about replace of custom field id after deployment.

For getting custom field id dynamically from a specificic custom field on an object   we can use "Tooling  API". We have an object "CustomField" to get the custom  field information from "Tooling API".We can get 18 characters id of custom field. But for populating customfield salesforce expects only 15 characters so after getting the id of custom field from tooling api we have to make it from 18 characters to 15 characters.

Tooling Api supports Rest API. So we can get the custom field id by using http callouts as shown below.

HttpRequest req = new HttpRequest();
req.setHeader('Authorization','Bearer ' + UserInfo.getSessionID());
 req.setHeader('Content-Type','application/json');
 req.setEndpoint(toolingapiurl);
  req.setMethod('GET');  
  // Send the request, and return a response
  HttpResponse res = h.send(req);     

For example i have "languages__c" custom field on contact object. I want to populate it with a value "English" from custom button "Create Contact" on Account record detail page as shown below.

Account Detail Page










Custom button code as shown below:

{!REQUIRESCRIPT("/soap/ajax/29.0/connection.js")}
{!REQUIRESCRIPT("/soap/ajax/29.0/apex.js")}
var result = sforce.apex.execute("RetrieveCustomFieldIdCls","getCustomFieldID",{customFieldName:"Languages__c",objectName:"Contact"});
window.open('/003/e?retURL=%2F{!Account.Id}&accid={!Account.Id}&'+result+'=English','_self');

in the above code "result" variable gets the custom field id from a method "getCustomFieldId" referenced in the "sforce.apex.execute" method.
here we are passing two parameters "Custom Field Name","Object Name".
I am passing " Languages__c"," Contact".When we click on custom button "Create Contact" it retrieves the "Languages__c" custom field id and then preparing url in the next line as shown below.

window.open('/003/e?retURL=%2F{!Account.Id}&accid={!Account.Id}&'+result+'=English','_self');
Here "result" variable contains custom field id.
Now we don't need to replaces the custom field id after deployment.Becase we are dynamically getting the customfield id from Tooling API.

Class  for custom button to retrieve custom field Id:

global class RetrieveCustomFieldIdCls {
    webservice static string getCustomFieldID(String customFieldName,String objectName){
        String customFieldId='';
        String customField=customFieldName.removeEndIgnoreCase('__c');     
        Http h = new Http();
       
         // Instantiate a new HTTP request, specify the method (GET) as well as the endpoint
        HttpRequest req = new HttpRequest();
        req.setHeader('Authorization','Bearer ' + UserInfo.getSessionID());
        req.setHeader('Content-Type','application/json');
        String fullFileURL = URL.getSalesforceBaseUrl().toExternalForm();
        String url1=fullFileURL+'/services/data/v28.0/tooling/query/?q=Select+id,+DeveloperName+from+customField+Where+DeveloperName=\'' + customField + '\'+and+TableEnumOrId=\''+objectName+'\'';
        req.setEndpoint(url1);
        req.setMethod('GET');  
        // Send the request, and return a response
        HttpResponse res = h.send(req);   
        RetrieveFieldParsercls retrieveObj=(RetrieveFieldParsercls) System.JSON.deserialize(res.getBody(), RetrieveFieldParsercls.class);
        System.debug('##:'+retrieveObj);
        for(RetrieveFieldParsercls.retrieveFieldDetails retrieveFieldDetailObj:retrieveObj.records){
                customFieldId=String.valueOf(retrieveFieldDetailObj.Id).substring(0,15);
        }  
        return customFieldId;  
    }
}

JSON parser class:
public class RetrieveFieldParsercls{
public Integer size; //1
public Integer totalSize; //1
public boolean done;
public cls_queryLocator queryLocator;
public String entityTypeName; //CustomFieldDefinition
public retrieveFieldDetails[] records;
public class cls_queryLocator {
}
public class retrieveFieldDetails {
public cls_attributes attributes;
public String Id; //00N280000025vdlEAA
public String DeveloperName; //Active
}
public class cls_attributes {
public String type; //CustomField
public String url; ///services/data/v28.0/tooling/sobjects/CustomField/00N280000025vdlEAA
}

}

Note:-we are doing http callout so we have to set endpoint url in Remote Site Settings accordingly.

Contact Screen when we click on "Create Contact" button on account record detail page