[SalesForce] RecordTypes, Dependant Picklist values within Lightning Components

We have built a Lightning Component for displaying OrderLines__c (custom object). Since we need to utilize picklist values we could not use the lightning:datatable. I found a great guide on sfdcmonkey.com (http://sfdcmonkey.com/2017/12/08/lightning-data-table-inline-editing/) of how to build my own data table with inline edit supporting picklists.

The problem is that our OrderLines__c object is also utilizing Record Types. However there does not seem to be a straight forward way to get the picklist values for a specific Record Type in Apex. I can use the User Interface API (https://developer.salesforce.com/docs/atlas.en-us.uiapi.meta/uiapi/ui_api_resources_picklist_values.htm).

But since every OrderLine__c is its own component. This mean there is going to be one call for every line. Which is going to end up in a lot of API calls.

So my question is:
What is the best approach to handle this?

I have been thinking about using Apex Scheduler and update a static resource with the current values. However I am hoping there is a better solution.

Best Answer

You can use a helper object to share data across multiple components. This is the principle behind the lightning:empApi component; it shares a connection across multiple components to multiplex a streaming API connection. I'm not going to write a full, production-ready solution for this, but I have written a demo that should get you started.


<aura:component controller="DescribeRequestController">
    <aura:handler name="init" action="{!c.init}" value="{!this}" />
    <aura:method name="getDescribe" action="{!c.handleDescribeRequest}">
        <aura:attribute name="entityName" type="String" />
        <aura:attribute name="callback" type="Function" />
    </aura:method>
</aura:component>

({
    init: function(component, event, helper) {
        helper.init();
    },
    handleDescribeRequest: function(component, event, helper) {
        helper.handleDescribe(component, event);
    }
})

({
    init: function() {
        // state information
        this.queue = [];
        this.describes = {};
        this.isInCallback = false;
    },
    handleDescribe: function(component, event) {
        var params = event.getParams();
        if(this.describes[params.entityName]) {
            // We already described this!
            params.callback(this.describes[params.entityName]);
        } else {
            // Place into queue for processing
            this.queue.push(params);
            this.handleDescribeCallback(component, event);
        }
    },
    handleDescribeCallback: function(component, event) {
        // We're waiting on other results
        if(this.isInCallback) {
            return;
        }
        this.isInCallback = true;
        var action = component.get("c.getDescribe");
        action.setParams({entityName: this.queue[0].entityName });
        action.setCallback(this, function(result) {
            // We're not busy after this
            this.isInCallback = false;
            this.describes[this.queue[0].entityName] = JSON.parse(result.getReturnValue());
            // Find all pending items that were waiting for this describe, do callback
            this.queue.filter(item => this.describes[item.entityName])
                .forEach(item => item.callback(this.describes[item.entityName]));
            // Remove all those items we just dispatched
            this.queue = this.queue.filter(item => !this.describes[item.entityName]);
            // If we have any more work to do, let's do so
            if(this.queue.length) {
                this.handleDescribeCallback(component, event);
            }
        });
    }
})

public class DescribeRequestController {
  @AuraEnabled public static String getDescribe(String entityName) {
    HttpRequest req = new HttpRequest();
    req.setMethod('GET');
    req.setEndpoint(
      'callout:salesforce/services/data/v43.0/sobjects/'+
      entityName+'/describe');
    return new http().send(req).getBody();
  }
}

This code, of course, doesn't have any error handling, and should not be considered production-ready, but it should demonstrate enough technique to get you to a viable solution. Once you have the describe info, you'll have the "validFor" bitmap, which you'll need to parse yourself. See this answer for how to parse this bitmap.

Related Topic