The simplest way to get custom field id dynamically in Lightning

I have a lightning component where I need to display link to related list of children relationship record for given custom object record.

Since I developed this application on sandbox, I can’t hardcode this link since it will change after I deploy this application to production. So I was thinking of building the link dynamically by dynamically retrieving the custom field id.

This is short version of Lightning component

<aura:component controller="LEXCont">
    <aura:attribute name="relatedLinkPrefix" type="String" />
    <aura:attribute name="projectId" type="String" />
    <a href="{!v.relatedLinkPrefix + v.projectId}" target="_blank" >Related months</a>
</aura:component>

These are two methods from LEXCont class

static String restGet(String endPoint, String method, String sid) {
    Http h = new Http();
    HttpRequest hr = new HttpRequest();
    hr.setHeader('Authorization', 'Bearer ' + sid);
    hr.setTimeout(60000);   
    hr.setEndpoint(endPoint);   
    hr.setMethod(method);
    HttpResponse r = h.send(hr);            
    return r.getBody(); 
}

@AuraEnabled
public static String getRelatedDebugLink() {
    try{
        String baseURL = URL.getSalesforceBaseUrl().toExternalForm();
        String monthObjectId = restGet( baseURL + '/services/data/v38.0/tooling/query?q=select+Id+from+CustomObject+where+DeveloperName+=+\'Month\'', 'GET', UserInfo.getSessionId() );
        monthObjectId = monthObjectId.substringAfter('"Id":"').substringBefore('"');
        String projectLookupFieldId = restGet( baseURL + '/services/data/v38.0/tooling/query?q=select+Id+from+CustomField+where+TableEnumOrId=\'' + monthObjectId + '\'AND+DeveloperName=\'Project\'', 'GET', UserInfo.getSessionId() );
        projectLookupFieldId = projectLookupFieldId.substringAfter('"Id":"').substringBefore('"');            
        return '/' + Month__c.sobjecttype.getDescribe().getKeyPrefix() + '?rlid=' + projectLookupFieldId + '&id=';
    } catch( Exception ex ){
        throw new AuraHandledException( ex.getMessage() );
    }
}

In this code I am trying to execute two Tooling API queries: the first one

Select Id from CustomObject where DeveloperName = 'Month'

to get custom Object Id and the next one

select Id from CustomField where TableEnumOrId=:monthObjectId AND DeveloperName='Project'

to get the actual custom field Id.

Since we can’t run query on CustomField and CustomObject objects directly, I had to use REST API to make these queries.

I mean I can’t just write inline queries like

SObject cs = [ select id from CustomObject ];

or

SObject cf = [ select id from CustomField ];

because if I try to do that I will receive error message

sObject type 'CustomObject' is not supported. If you are attempting to use a custom object, be sure to append the '__c' after the entity name. Please reference your WSDL or the describe call for the appropriate names.

and

sObject type 'CustomField' is not supported. If you are attempting to use a custom object, be sure to append the '__c' after the entity name. Please reference your WSDL or the describe call for the appropriate names.

correspondingly, because CustomObject and CustomField object are only exposed for Tooling API.

The code for getRelatedDebugLink method works fine if I use it from Anonymous Execution window or from Visualforce page but doesn’t work for Lightning, since Lightning Session ID doesn’t have to full access to Salesforce API.

When I run the same code from Anonymous execution window, I got the result custom field id but when I run this in Lightning, I receive error

This session is not valid for use with the REST API

I know that I could use some additional visualforce page exposing full-access session id

<apex:page>
    Start_Of_Session_Id{!$Api.Session_ID}End_Of_Session_Id
</apex:page>

which I could use to get full-access session id or I could hardcode my username and password and perform SOAP login to get full-access session id, however it would be too complex. I wondered for a while if there is any concise or elegant solution to this, and today I have found very elegant and concise solution.

I have discovered that there are FieldDefinition and EntityDefinition objects in Salesforce which are not only available for using in Tooling API but also generally available for inline queries and for Lightning Controllers.

So by using this object and making query

select DurableId from FieldDefinition where EntityDefinition.label = 'Month' and label = 'Project' 

I can avoid making callout to REST API, rewriting my method as follows:

@AuraEnabled
public static String getRelatedDebugLink() {
    try{
        String projectLookupFieldId = [ select DurableId from FieldDefinition where EntityDefinition.label = 'Month' and label = 'Project' ].DurableId.substringAfter('.');            
        return '/' + Month__c.sobjecttype.getDescribe().getKeyPrefix() + '?rlid=' + projectLookupFieldId + '&id=';
    } catch( Exception ex ){
        throw new AuraHandledException( ex.getMessage() );
    }
}

 

Advertisements
This entry was posted in custom, field, salesforce, Uncategorized and tagged , , , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s