Salesforce UI API Lightning Example

In this blog, I am going to explain how to use Salesforce UI API.Salesforce has the number of APIs to build the native and mobile apps.  Salesforce UI allows you to build native mobile apps and custom web apps. The Great advantage of the Salesforce UI API, you get data and metadata in a single response. You don’t have to worry about layouts, picklists, field-level security, or sharing.

Step 1: Create Connected App 

Create a salesforce connected app as shown below. We need to create a named credential to authenticate the web service call. Go to setup –> create apps–> create a new connected app as shown below and save it to get consumer key and secret key. In this step use any URL as callback URL. later after confirmed the auth provides we will replace the callback URL from auth provider callback URL

After saving the connected app you will get consumer key and consumer secret which we will use to configure the Auth provides.

Step 2: Auth Provider 

Now we need to create an auth provide as shown below. Go to setup –> administration  –> Security control -> create a new Auth provider as shown below .

Replace the connected App callback URL with Auth provide callback URL

Step 3: Named credentials 

Create a named credentials as shown below for authenticating salesforce REST API from the lightning component. 

Code :

Below is the apex class that used to get the data and metadata from the Salesforce UI API.Based on the account selected, you will get the response which contains data and metadata.

public class AuraUIExamples {
    
    @AuraEnabled
    public static List<Account> getAllAccounts(){
        return [Select id, name from Account limit 10];    
    }
    public Map<String, String> uiDisplayList {get;set ; }
    public String accName { get; set; }
    
    public AuraUIExamples(){
        uiDisplayList = new Map<String, String>();
    }
    @AuraEnabled
    public static List<UIDisplay> parseRecord(String accId){
        Http h = new Http();
        
        List<UIDisplay> listRst = new List<UIDisplay>() ;
        
        HttpRequest httpReq = new HttpRequest();
        httpReq.setMethod('GET');
        httpReq.setEndpoint('callout:REST_API1/services/data/v41.0/ui-api/record-ui/'+accId);
        HttpResponse res = h.send(httpReq);
        Map<String, Object> root = (Map<String, Object>)JSON.deserializeUntyped(res.getBody());
        Map<String, Object> records = (Map<String, Object>)root.get('records');
        Map<String, Object> records1 = (Map<String, Object>)records.get(accId);
        Map<String, Object> records2 = (Map<String, Object>)records1.get('fields');
        for(String keys : records2.keySet()){
            Map<String, Object> sttt = (Map<String, Object>)records2.get(keys) ;
            if((String)sttt.values()[0]!=null){
                System.debug('sttt'+sttt);
                listRst.add(new UIDisplay(keys ,(String)sttt.values()[0] ));
            }
        }
        
        System.debug('listRst'+listRst);
        return listRst ; 
    }
    
    public class UIDisplay {
        @AuraEnabled
        public String label {get;set;}
        @AuraEnabled
        public String value {get;set;}
        public UIDisplay(String label , String value){
            this.label = label ; 
            this.value = value;
        }
        
    }
    
    
}

Create a lightning component Component that will display the data based on the selected account from the drop-down.

<aura:component implements="force:appHostable,flexipage:availableForAllPageTypes" access="global" controller="AuraUIExamples">
    <aura:attribute name="options" type="Account[]" />
    
    <aura:attribute name="result" type="AuraUIExamples.UIDisplay[]" />
    <aura:attribute name="selectedValue" type="String" default=""/>
    <aura:handler name="init" value="{!this}" action="{!c.loadOptions}" />
    <lightning:layout horizontalAlign="center">
        
        <lightning:layoutItem flexibility="auto" padding="horizontal-small">
            <lightning:select name="accountSelect" label="" aura:id="accountSelect" value="{!v.selectedValue}">
                <aura:iteration items="{!v.options}" var="item">
                    <option text="{!item.Name}" value="{!item.Id}" selected="{!item.selected}"/>
                </aura:iteration>
            </lightning:select>
        </lightning:layoutItem>
        <lightning:layoutItem flexibility="auto" padding="around-medium">
            <lightning:button variant="brand" label="Get Selected Account Details" onclick="{! c.getAccountDetails }" aura:id="SearchButton" />
        </lightning:layoutItem>   
    </lightning:layout>
    <lightning:layout horizontalAlign="center">
        
        <table class="slds-table">
            <thead class="headerStyle">
                <tr class="slds-text-title--caps ">
                    <th scope="col">
                        <div class="slds-truncate" title="Label">Label</div>
                    </th>
                    <th scope="col">
                        <div class="slds-truncate" title="Value">Value</div>
                    </th>
                    
                </tr>
            </thead>
            <tbody>
                <aura:iteration items="{!v.result}" var="obj">
                    <tr>
                        <th scope="row" data-label="Label">
                            <div class="slds-truncate" title="{! obj.label }">{! obj.label }</div>
                        </th>
                        <td data-label="Value">
                            <div class="slds-truncate" title="{! obj.label }">{! obj.value }</div>
                        </td>
                        
                    </tr>
                </aura:iteration>
            </tbody>
        </table>
    </lightning:layout>
    
    
</aura:component>
({
    loadOptions: function (component, event, helper) {
        helper.getAccounts(component);
    },
    getAccountDetails: function (component, event, helper) {
        var accountId = component.find("accountSelect").get("v.value");
        console.log('accountId'+accountId);
        var action = component.get("c.parseRecord");
        action.setParams({
            accId : accountId
        });
        action.setCallback(this, function(response) {
            var state = response.getState();
            if (state === "SUCCESS") {
                component.set("v.result", response.getReturnValue());
            }
            else if (state === "INCOMPLETE") {
            }
                else if (state === "ERROR") {
                    var errors = response.getError();
                    if (errors) {
                        if (errors[0] && errors[0].message) {
                            console.log("Error message: " + 
                                        errors[0].message);
                        }
                    } else {
                        console.log("Unknown error");
                    }
                }
        });
        $A.enqueueAction(action);
        
        
    }
})

helper

({
    getAccounts : function(component) {
        var action = component.get("c.getAllAccounts");
        action.setCallback(this, function(response) {
            var state = response.getState();
            if (state === "SUCCESS") {
                component.set("v.options", response.getReturnValue());
            }
            
            else if (state === "INCOMPLETE") {
                // do something
            }
                else if (state === "ERROR") {
                    var errors = response.getError();
                    if (errors) {
                        if (errors[0] && errors[0].message) {
                            console.log("Error message: " + 
                                        errors[0].message);
                        }
                    } else {
                        console.log("Unknown error");
                    }
                }
        });
        $A.enqueueAction(action);
        
        
        
    },
})

 

.THIS table{
    text-align: center;
    border: solid 1px #86bbc2;
    font: normal 13px Arial, sans-serif;
}
.THIS thead th {
    background-color: #DDEFEF;
    border: solid 1px #DDEEEE;
    padding: 10px;
    text-align: center;
}
.THIS tbody td {
    border: solid 1px #DDEEEE;
    padding: 10px;
}
.THIS tbody tr:nth-child(odd) {
    background-color: #fff;
}
.THIS tbody tr:nth-child(even) {
    background-color: #EEF7EE;
}

 

Salesforce UI API

In this blog, I am going to explain how to use Salesforce UI API.Salesforce has the number of APIs to build the native and mobile apps.  Salesforce UI allows you to build native mobile apps and custom web apps. The Great advantage of the Salesforce UI API, you get data and metadata in a single response. You don’t have to worry about layouts, picklists, field-level security, or sharing.

Step 1: Create Connected App 

Create a salesforce connected app as shown below.  In this post, i am using named credential to authenticate the web service call. Go to setup –> create apps–> create a new connected app as shown below and save it to get consumer key and secret key. In this step use any URL as callback URL. later after confirmed the auth provides we will replace the callback URL from auth provider callback URL

After saving the connected app you will get consumer key and consumer secret which we will use to configure the Auth provides.

Step 2: Auth Provider 

Now we need to create an auth provide as shown below. Go to setup –> administration  –> Security control -> create a new Auth provider as shown below .

Replace the connected App callback URL with Auth provide callback URL

Step 3: Named credentials 

Create a named credentials as shown below for authenticating Salesforce REST API.

Code :

public class UIExamples {
    
    public string accId{get;set;}
    public Map<String, String> uiDisplayList {get;set ; }
    public String accName { get; set; }    
    public List<selectOption> getAccountValues() {
        List<selectOption> options = new List<selectOption>();       
        for(Account a : [Select Id , Name from Account Limit 10 ]){
            options.add(new selectOption(a.Id,a.Name));
        }
        return options;
    } 
    
    public UIExamples(){
        uiDisplayList = new Map<String, String>();
    }
    
    public void parseRecord(){
        Http h = new Http();
        HttpRequest httpReq = new HttpRequest();
        httpReq.setMethod('GET');
        httpReq.setEndpoint('callout:REST_API1/services/data/v41.0/ui-api/record-ui/'+accName);
        HttpResponse res = h.send(httpReq);
        Map<String, Object> root = (Map<String, Object>)JSON.deserializeUntyped(res.getBody());
        Map<String, Object> records = (Map<String, Object>)root.get('records');
        Map<String, Object> records1 = (Map<String, Object>)records.get(accName);
        Map<String, Object> records2 = (Map<String, Object>)records1.get('fields');
        for(String keys : records2.keySet()){
            Map<String, Object> sttt = (Map<String, Object>)records2.get(keys) ;
            if((String)sttt.values()[0]!=null){
                uiDisplayList.put( keys ,(String)sttt.values()[0]) ;
            }
        }
    }
    
    public class UIDisplay {
        
        public String label {get;set;}
        public String value {get;set;}
        public UIDisplay(String label , String value){
            this.label = label ; 
            this.value = value;
        }
        
    }
    
}

Visualforce page
Create a visualforce page that shows the data and metadata from based on selected account.

<apex:page controller="UIExamples" sidebar="false" showHeader="true" lightningStylesheets="true">
    <apex:slds />
    <apex:form >
        <div align="center">
            <b> Select Account to see the details .</b>
            <apex:selectList size="1" value="{!accName}" >
                <apex:actionSupport event="onchange" action="{!parseRecord}"/>      
                <apex:selectOptions value="{!AccountValues}">
                </apex:selectOptions>
            </apex:selectList>
        </div>
        <br/>
        <div align="center">
            
            
            <apex:pageBlock>
                <apex:pageBlockTable value="{!uiDisplayList}" var="dirKey" columns="2" styleClass="styleHeader" >
                    <apex:column value="{!dirKey}" headerValue="Label" />
                    <apex:column value="{!uiDisplayList[dirKey]}"  headerValue="Value"/>
                </apex:pageBlockTable>
            </apex:pageBlock>
        </div>
    </apex:form>
</apex:page>

 

 

Lightning Attributes unbound vs bound bindings expressions

Introduction:-

In this blog, I am going to explain how to use salesforce attribute unbound vs bound binding. Attributes are key parts of a web component-based framework like lighting, Polymer and react etc which are used to communicate or exchange data between components. You can think it like a member variable in Java. Here is the example of attributes

<aura: attribute name="whom" type="String" default="world" required="true"/>

Now if you see the below components having an attribute name message which is referred in the component by using {!v.message} with {!} expression know as the bounded expression. Salesforce supports two types of expression bounded and unbounded to pass the attribute values.

<aura:component >
<aura:attribute type="String" name="message" default="Welcome to salesforce" description="Simple Message " />
<aura:attribute type="Account" name="acc" default="{'sObjectType':'Account', 'Name':'SFDC'}" description="Account attribues "/>
<aura:attribute type="List" name="types" default="['Salesforce', 'force.com', 'Lightning']" description="Collection type" />
<div>
{!v.message}
</div>
<div>
{!v.acc.Name}
</div>

<div>
{!v.types[0]}
</div>
</aura:component>

Expression Binding: –

Salesforce supports two type of binding expression in Salesforce namely bounded and Unbounded.  The two forms exhibit different behaviors for data binding and updates when you pass an expression from a parent component to a child component that it contains.

{! Expression} (Bound Expressions)

Data updates in either component are reflected through bi-directional data binding in both components. Similarly, change notifications are triggered in both the parent and child components. Means if you update any attributes in parent components those changes will be updated to child component attributes.

{#Expression} (Unbound Expressions)

Data updates behave, as you would expect in JavaScript. Primitives, such as String, are passed by value, and data updates for the expression in the parent and child are decoupled.Objects, such as Array or Map, are passed by reference so changes to the data in the child propagate to the parent. However, change handlers in the parent won’t be notified so it will not be re-rendered. The same behavior applies for changes in the parent propagating to the child.

Bi-directional data binding is expensive for performance and it creates hard-to-debug errors due to the propagation of data changes. So its recommend using the {#expression} syntax instead when you pass an expression from a parent component to a child component unless you require bi-directional data binding.

Here is the simple Component ChildExp1.cmp with bounded expression

<aura:component >
    <!-- Primitive type Attributes  and are passed by value, and data updates for the expression in the parent and child are decoupled. -->
    <!-- Objects, such as Array or Map, are passed by reference -->
    
    <h6> <b>Inner Component</b></h6> <br/>
    <aura:attribute name="welcomemessage" type="String" default="Welcome to Child Component"/>
    <aura:attribute name="acc" type="Account" default="{'sObjectType':'Account' , 'Name':'Child Account '} "/>
    <aura:attribute name="booleanValue" type="Boolean"/>
    <aura:attribute name="numberValue" type="Double"/>
    <aura:attribute name="stringValue" type="String"/>
    <aura:attribute name="listValue" type="List" default="['red', 'green', 'blue']"/>
    <aura:attribute name="mapValue" type="Map" default="{ a: 'label1', b: 'label2' }"/>
    <div>
      <b>  Child Component Welcome Message : {!v.welcomemessage}</b>
    </div>
    <div>
       <b> Child Component Account Name : {!v.acc.Name}</b>
    </div>
    <div>{!v.booleanValue}</div>
    <div >{!v.numberValue}</div>
    <div >{!v.stringValue}</div>
    <div >
        <aura:iteration aura:id="box" items="{!v.listValue}" var="message" indexVar="index">
            {!index}:{!message}<br/>
        </aura:iteration>
    </div>
    <br/>
    <div >{!v.mapValue}</div>
    <p><ui:button label="Update Child Component " press="{!c.updateMessage}"/></p>
    
    
    
</aura:component>

 

({
    updateMessage : function(component, event, helper) {
        component.set("v.welcomemessage", "updated :: Child message");
        component.set("v.acc",{'sobjectType':'Account',
                               'Name': 'Updated: Child Account'
                              });
        component.set("v.booleanValue", "false");
        component.set("v.numberValue", "120.90");
        component.set("v.stringValue", "updated by Child stringValue message");
        component.set("v.listValue", "['First', 'Second', 'Third']");
     },
    
    
})

Here is the parent Component which is passing referring the child component to and pass the attributes by using Bound expression

<aura:component >
   
   <b> Parent Compoent :</b>
     
    <aura:attribute name="parentAttr" type="String" default="Welcome to Parent Message"/>
    <aura:attribute name="accParnet" type="Account" default="{'sObjectType':'Account' , 'Name':'Parent Account '} "/>
    <aura:attribute name="booleanValue" type="Boolean"/>
    <aura:attribute name="numberValue" type="Double"/>
    <aura:attribute name="stringValue" type="String"/>
    <aura:attribute name="listValue" type="List" default="['red', 'green', 'blue']"/>
    <aura:attribute name="mapValue" type="Map" default="{ a: 'label1', b: 'label2' }"/>
    
    
    <p>Parent Component Primitive type: {!v.parentAttr}</p>
    <p>Parent Component Non Primitive Types : {!v.accParnet.Name}</p>
   
    <div >{!v.booleanValue}</div>
    <div >{!v.numberValue}</div>
    <div>{!v.stringValue}</div>
    <div>{!v.mapValue}</div>
    <div>
        <aura:iteration aura:id="box" items="{!v.listValue}" var="message" indexVar="index">
            {!index}:{!message}<br />
        </aura:iteration>
    </div>
    <br/>
    
    <div>
        
        <c:ChildExpr1 aura:id="innerCmp" stringValue="{!v.stringValue}" 
                      booleanValue="{!v.booleanValue}" numberValue="{!v.numberValue}" listValue="{!v.listValue}" 
                      mapValue="{!v.mapValue}" welcomemessage="{!v.parentAttr}" acc="{!v.accParnet}"/>
        
        
    </div>
      <p><ui:button label="Update Message - Parent"
                  press="{!c.updateParentMessage}"/></p>
  
    
</aura:component>

 

({
    updateParentMessage: function(cmp) {
        cmp.set("v.parentAttr", "updated parent attribute");
        cmp.set("v.accParnet",{'sobjectType':'Account',
                               'Name': 'Updated: Parent Account'
                              });
        cmp.set("v.booleanValue",false);
        cmp.set("v.numberValue","8335");
        cmp.set("v.stringValue","CHANGED string value");
    },
    
    
})

If you click on Update Message – Parent  Button those changes will be now propagated to the child component and vice versa which is similar to two-way data binding. 

 

Now Replace the child component invocation in the Parent Component with the below code by using Unbound Expression Now the parent component changes will not propagate to the child component which acts like as unidirectional binding. 

   
        <c:ChildExpr1 aura:id="innerCmp" stringValue="{#v.stringValue}" 
                      booleanValue="{#v.booleanValue}" numberValue="{#v.numberValue}" listValue="{#v.listValue}" 
                      mapValue="{#v.mapValue}" welcomemessage="{#v.parentAttr}" acc="{#v.accParnet}"/>

Now When you click Update Child Component data its will update only child component attributes and when you click on the Update Message -Parent parent component its update the parent component data which is unidirectional data binding. Now let see how handler works with unbound and bound expression.When you use a bound expression, a change in the attribute in the parent or child component triggers the change handler in both components. When you use an unbound expression, the change is not propagated between components so the change handler is only triggered in the component that contains the changed attribute.

Now update childExpr1.cmp with below code

<aura:component >
    <aura:attribute name="childAttr" type="String" />
    <aura:handler name="change" value="{!v.childAttr}" action="{!c.onChildAttrChange}"/>  
    <p>childExpr childAttr: {!v.childAttr}</p>
    <p><lightning:button label="Update childAttr"
                         onclick="{!c.updateChildAttr}"/></p>
</aura:component>

Here is the controller

({
    updateChildAttr: function(cmp) {
        cmp.set("v.childAttr", "updated child attribute");
    },
    onChildAttrChange: function(cmp, evt) {
        console.log("childAttr has changed");
        console.log("old value: " + evt.getParam("oldValue"));
        console.log("current value: " + evt.getParam("value"));
    }
})

Here is the ParentExpr1.cmp

<aura:component >
    <aura:attribute name="parentAttr" type="String" default="parent attribute"/>
    <aura:handler name="change" value="{!v.parentAttr}" action="{!c.onParentAttrChange}"/>
    <c:childExpr1 childAttr="{!v.parentAttr}" />
    <p>parentExpr parentAttr: {!v.parentAttr}</p>
    <p><lightning:button label="Update parentAttr"
                         onclick="{!c.updateParentAttr}"/></p>
</aura:component>
({
    updateParentAttr: function(cmp) {
        cmp.set("v.parentAttr", "updated parent attribute");
    },
    onParentAttrChange: function(cmp, evt) {
        console.log("parentAttr has changed");
        console.log("old value: " + evt.getParam("oldValue"));
        console.log("current value: " + evt.getParam("value"));
    }
})

Press the Update parentAttr button. The change handlers for c:parentExpr1 and c:childExpr1 are both triggered as we’re using a bound expression.

Now Change c:parentExpr1 to use an unbound expression instead as like this. <c:childExpr1 childAttr=”{#v.parentAttr}” />  which use an unbound expression, the change is not propagated between childExp1.cmp and parentExpr1.cmp .</c:

 

 

 

Lightning Aura.Action Attributes

In this blog, I am going to explain salesforce lightning Aura.Action Attribute Type.With the Aura.Action attribute type you can able to pass the actions handlers from the parent component to child components such as on-click or other HTML actions like on** actions.  Although Aura.Action works for passing an action handler to a child component, its recommended for registering an event in the child component and firing the event in the child’s controller instead. Then, handle the event in the parent component. This example demonstrates how to pass an action handler from a parent component to a child component.Here’s the child component with the Aura.Action attribute. The on-click handler for the button uses the value of the on-click attribute, which has the type of Aura.Action.Create the new Lightning component with below code.
AuraAction.cmp

<aura:component>
    <aura:attribute name="pressButton" type="Aura.Action" required="true"/>
    <aura:attribute name="pressDiv" type="Aura.Action" required="true"/>
    
    <ui:button aura:id="theButton" label="Press Me" press="{!v.pressButton}"/>
    <div aura:id="theDiv" onclick="{!v.pressDiv}">Click Me</div> 
</aura:component>

The above component is having two Aura.Action attributes which are used to pass from the parent component to child component on invoke on button press and click on div section handler actions.

AuraActionInvoke.cmp

The below component  is parent component which passes the action to the child component

<aura:component>
    <aura:attribute name="push" type="Boolean" default="false"/>
    <div aura:id="displayResult">No action has run yet</div>
    <c:AuraAction aura:id="fixture" pressButton="{!c.pressButton}"  pressDiv="{!c.pressDiv}"/>
    
</aura:component>
({
    pressDiv: function(cmp, event) {
        var div = cmp.find("displayResult");
        if (div) {
            div.getElement().innerHTML = "Div Action is Presed";
        }
    },
    pressButton: function(cmp, event) {
        var div = cmp.find("displayResult");
        if (div) {
            div.getElement().innerHTML = "Button Action is Pressed";
        }
    },
    
})

Simple Auraapp.app

<aura:application >
    <c:AuraActionInvoke/>	
</aura:application>

Now if you see the above app, when the user clicks on the Press Me button it will pass the action handler from the parent component to child component. Similarly, even user click on Click Me text also passes the action handler to child component and update the parent component.