[SalesForce] Auto-populate lookup fields

I have a standard Object (ServiceContract) which has a Master-Detail relation with ContractLineItem (also a standard object). ContractLineItem further has a master-Detail relation with a custom object – TransactionLineItem.

When i click on "New Transaction Line Item" button on contract line item page layout, another page opens where you can create a new TransactionLineItem record. On that page, there is a lookup to ServiceContract and ContractLineItem. I want these two autopopulated.

Can anyone give any suggestion. I know the simplest way is to put a custom button (which uses javascript) for "New Transaction Line Item" and use URL hacking. But it involves a bit of hardcoding. Is there a way to be able to do this without any kind of hardcoding? So that when we push it all into production, i don't have to change anything.

Best Answer

Solution 1: URL Hacking without JS

URL hacking doesn't require you to use javascript. I created a short video to explain the way URL hacking works a couple of years ago.

The simplest way is to use URL hacking in your live system and refresh your sandbox. The field ids for fields in live and sandbox systems are the same after a refresh.

However, this doesn't answer your question. Therefore there is solution 2.

Solution 2: Apex and Tooling API

As proposed by Andy you can use the Tooling API to get field Ids from Salesforce. He is using APEX and a Tooling API wrapper to query the required field ids:

// Constructs the Tooling API wrapper (default constructor uses user session Id)
ToolingAPI toolingAPI = new ToolingAPI();

// Query CustomObject object by DeveloperName (note no __c suffix required)
List<ToolingAPI.CustomObject> customObjects = (List<ToolingAPI.CustomObject>)
     toolingAPI.query('Select Id, DeveloperName, NamespacePrefix From CustomObject Where DeveloperName = \'Test\'').records;

// Query CustomField object by TableEnumOrId (use CustomObject Id not name for Custom Objects)
ToolingAPI.CustomObject customObject = customObjects[0];
Id customObjectId = customObject.Id;
List<ToolingAPI.CustomField> customFields = (List<ToolingAPI.CustomField>)
     toolingAPI.query('Select Id, DeveloperName, NamespacePrefix, TableEnumOrId From CustomField Where TableEnumOrId = \'' + customObjectId + '\'').records;

// Dump field names (reapply the __c suffix) and their Id's
System.debug(customObject.DeveloperName + '__c : ' + customObject.Id);
for(ToolingAPI.CustomField customField : customFields)
     System.debug(
          customObject.DeveloperName + '__c.' +
          customField.DeveloperName + '__c : ' +
          customField.Id);

In the most scenarios this kind of "hack" seems to be a bit too complicated compared to standard URL hacks...

Implementation outline for Solution 2

  1. Create a new visualforce page. Make sure that you are using the standard controller of your object.
  2. Create a new custom controller to extend the existing standard controller
  3. Implement a method which returns a page reference.
  4. use the tooling api right, within your method to query the required field ids and construct the new url (like you would have done it in a standard URL hack.)
  5. don't forget to wire the visualforce page action attribute with the action method which was implemented before
  6. Create a new button which opens the new visualforce page.

  7. Don't forget to write a test class. Don't forget to mock all call outs. (callouts are not available during test)

Before implementing 1-6 please consider the following aspects:

  • Using the tooling API will consume a bunch of API request. (Make sure that consuming the requests is ok. Or implement a caching mechanism.)
  • The implementation takes some time (I assume that it will take about 1 day to implement.) Additional testing might be required.
Related Topic