Apex

How do Lightning Components interact with Salesforce?

Posted on

Hi All,

Today one of my blog visitor asked me, how do Lightning Components interact with Salesforce? How does Lightning component get data from server? I thought to write an article on this, it might help you also to understand the architecture of Lightning Component Framework.

Below image will help you in understanding this.

salesforce

 

  1. Whenever a Lightning Component or an App runs on browser of Mobile device, it first download all component resources(i.e. Styles, Scripts, Markup) on mobile device. They are contained in browser’s memory to support display and processing that is why we call it client-side.
  2. Now if you want to call a apex method from client side, you will fire an event on client side. This event will call a JavaScript method on client-side. This client-side method will make an HTTP requests to Salesforce to call apex method on server-side. Like you do in VisualForce using action function or other JavaScript.
  3. This HTTP request to call apex method will be asynchronous. Asynchronous means you will make the request and forget about it and the controller returns to the client. The processing will be done on server-side.
  4. In the meantime Salesforce processes the logic by executing some apex.
  5. Finally when it is done with processing and gets some resulted data or not, it makes a callback to the browser/client-side. The client response by invoking an associated JavaScript callback function which extract data passed back by apex methods. This data can be assigned to component attributes. Now display will be automatically refreshed.

Hope this will be helpful 🙂

DropBox Lightning Component

Posted on Updated on

Hi All,

Today i will be showing you DropBox Lightning Component created by me and my colleague Sushil Kumar.

Dropbox is a file hosting service operated by Dropbox, Inc., headquartered in San Francisco, California,
that offers cloud storage, file synchronization, personal cloud, and client software. There are limits in storage of files in Salesforce. If you need a secure and free storage space for your files, you can use DropBox Lightning Component to store files directly in your DropBox app from Salesforce.

Features of this Lightning Component are :

  1. You can use this component on any sObject.
  2. You can store files for a specific record.
  3. You can upload multiple files.
  4. You can delete files directly in DropBox.
  5. You can view you files.

Click here to install Manage Package in your org.

After installing package register for My Domain.

Make sure you have DropBox Account. If you don’t have you can sign up and create DropBox App as below.

Sign up Dropbox account from DropBox website.

After the Sign up login into your dropbox account and then create a Dropbox App using following steps:

  1. Go to on dropbox developer edition i.e. https://www.dropbox.com/developer
  2. Click on My Apps > Create App.
  3. Then fill all information about app and then click on create. See below screen shot.

dropbox

Manage Dropbox Key from Custom setting

Insert a record in custom setting using following steps:

  1. Navigate to Setup > Develop > Custom Settings, click on Manage of “Dropbox Key”.
  2. Click on New, than insert following value:

App Key : from DropBox App

App Secret : from DropBox App

Redirect URI : from salesforce <your domain>/apex/DropBoxOAuth or copy url from preview of DropBoxOAuth page.

isAuthentication : false

Click on Save.

Add Redirect URI in Dropbox App

To add Redirect URI, Open your Dropbox App and you must set auth2 Redirect URIs same as above Redirect URL.

That’s It.

Your final result will look like this.

Thanks. 🙂

Understanding Server Side Errors In Lightning

Posted on Updated on

Hi All,

Every Salesforce developer might have faced server-side/apex errors or exceptions while running VF pages or Lightning Components. I have also faced errors while running VF pages and Lightning Components. It is easy to understand and handle errors on VF page but there is difference when you are working with Lightning Components.

If there is any error on VF page, it will show you user friendly or appropriate error message with line number, when you are not handling it. And if you are handling this exception, you can easily show them using or .

When you are running Lightning Components and if there is any server side error occur it will not show you error on browser. I don’t know why, maybe Lightning is still improving that’s why.

Run below code in your org.

//Apex Controller
public class DemoExceptionController{

    @AuraEnabled
    public static String getServerErrorMessage(){
		//DML Exception
        contact con = new contact();
        insert con;
		
		return 'anything';
	}
}
//ExceptionDemo.cmp
<aura:component controller="DemoExceptionController">
    
    <aura:attribute name="message" type="String"/>
	
    <ui:button label="Show Error" press="{!c.showError}"/>
    <br/>
	Error Message :<ui:outputText value="{!v.message}"/>
	
</aura:component>
//ExceptionDemoController.js
({
	showError : function(component, event, helper) {
		var action = component.get("c.getServerErrorMessage");
		
        action.setCallback(this, function(a) {
            component.set("v.message", a.getReturnValue());
		});
		$A.enqueueAction(action);
	}
})

When you click on “Show Error” button a DML exception will occur on server. This error should be shown on browser by system but it is not shown. I modified ExceptionDemoController.js to manually show server side errors.

({
	showError : function(component, event, helper) {
		var action = component.get("c.getServerErrorMessage");
		
        action.setCallback(this, function(a) {
            component.set("v.message", a.getReturnValue());
            
			if (a.getState() === "SUCCESS") {
				component.set("v.message", a.getReturnValue());
			} else if (a.getState() === "ERROR"){
                console.log(a.getError());
                var errors = a.getError();
				if(errors[0] && errors[0].pageErrors)
					component.set("v.message", errors[0].pageErrors[0].message);    
			}
			
        });
		$A.enqueueAction(action);
	}
})

Now when you click on “Show Error” button it will show you user friendly error message.

Now modify Apex Controller and ExceptionDemoController.js to show different type of error.

//Apex Controller
public class DemoExceptionController{

    @AuraEnabled
    public static String getServerErrorMessage(){
		//List Exception        
        List<Integer> li = new List<Integer>();
        li.add(15);
        Integer i2 = li[1]; // Causes a ListException
	}
}

//ExceptionDemoController.js
({
	showError : function(component, event, helper) {
		var action = component.get("c.getServerErrorMessage");
		
        action.setCallback(this, function(a) {
            component.set("v.message", a.getReturnValue());
            
			if (a.getState() === "SUCCESS") {
				component.set("v.message", a.getReturnValue());
			} else if (a.getState() === "ERROR"){
                console.log(a.getError());
                var errors = a.getError();
                if(errors[0] && errors[0].message)// To show other type of exceptions
                    component.set("v.message", errors[0].message);
                if(errors[0] && errors[0].pageErrors) // To show DML exceptions
            		component.set("v.message", errors[0].pageErrors[0].message);    
			}
        });
		$A.enqueueAction(action);
	}
})

Now when you click on “Show Error” button, this time it will not show you correct user friendly message instead of this “An internal server error has occurred” message will be shown. I tried with other type of exceptions to see the cases in which “An internal server error has occurred” message will be shown and in which correct user friendly message will be shown. In every case “An internal server error has occurred” message is shown except DML exception.

If you want to show appropriate error message you can handle exception to return appropriate error message.

//Apex Controller
public class DemoExceptionController{

    @AuraEnabled
    public static String getServerErrorMessage(){
		try{
            List<Integer> li = new List<Integer>();
            li.add(15);
            Integer i2 = li[1]; // Causes a ListException
        }catch(Exception e){
            return e.getMessage();
            
        }
	}
}

I know this is not a right way to show error message but I am just giving you an idea to show appropriate error message. You can write your own logic according to your requirement.

Thanks 🙂

Who Viewed Record Last Lightning Component

Posted on

Hi All,

In this article I will tell you how to create Lightning Component which shows list of users who viewed record.You can use this Lightning Component for any object whether it is a custom object or standard object.

This can be useful when trying to trace who last Viewed a record? There’s no way to do this in salesforce as of now.It would be great if you could see on a record if anyone has recently viewed it, so I thought to create this Component.

To implement this you have to do following things.
1) On any object you want to use this Lightning Component, create a new custom textarea(255) field called “Last Visited By“.
2) Set History Tracking on for this field.

When complete it will look like this.

Let’s walk through code.

LastVisitedController.apxc :

public with sharing class LastVisitedController{
    
    @AuraEnabled
    public static sObject getViewersList(String recordId, String objectName){
        System.debug('objectName = '+objectName +' recordId = '+recordId);
        
        String query = 'SELECT Id, Name, '+
                       '(Select OldValue, NewValue, Field From Histories Where Field = \'Last_Visited_By__c\' ORDER BY CreatedDate DESC) '+
                       'FROM '+objectName +' Where Id = \''+ recordId + '\' LIMIT 1' ;
        
        sObject obj = Database.Query(query);
        
        return obj;
    }
    
    @AuraEnabled
    public static void updateRecord(String recordId, String objectName){
        Datetime sdate = System.now();        //Format the datetime value to your locale        
        String sysTime = sdate.format('dd/MM/yyyy HH:mm');
    
        String query = 'SELECT Id, Name, Last_Visited_By__c '+
                        'FROM '+objectName +' Where Id = \''+ recordId + '\' LIMIT 1' ;
        
        sObject obj = Database.Query(query);
        obj.put('Last_Visited_By__c' , System.Userinfo.getFirstName() + ' '+ System.Userinfo.getLastName() +' '+ sysTime);
        update obj;
    }
    
}

The getViewersList method is used to return list of users who visited record recently. Method updateRecord is used to update “Last Visited By” field when a user visited record.

LastVisitedCmp.cmp :

<aura:component controller="LastVisitedController" implements="force:appHostable,force:hasRecordId,force:hasSObjectName,flexipage:availableForAllPageTypes">
    <ltng:require styles="/resource/SLDS/assets/styles/salesforce-lightning-design-system-vf.css"/>
    <!-- Atrribute Defination for Object Name -->
	<aura:attribute name="sObjectName" type="String"></aura:attribute>
    <!-- Atrribute Defination for Record Id -->
	<aura:attribute name="recordId" type="String"></aura:attribute>
    <!-- Atrribute Defination for Who visited -->
	<aura:attribute name="visitorsList" type="sObject"></aura:attribute>
    <!-- Event Handler for init Event-->
    <aura:handler name="init" value="{!this}" action="{!c.doInit}"></aura:handler>
    <!--page header-->
    <div class="slds">
        <div class="slds-page-header">
            <div class="slds-grid">
                <div class="slds-col slds-has-flexi-truncate">
                    <div class="slds-media">
                        <div class="slds-media__body">
                            <div class="slds-grid">
                                <h1 class="slds-text-heading--medium slds-m-right--small slds-truncate slds-align-middle">Recently Visited By</h1>
                            </div>
                        </div>
                    </div>
                </div>
            </div>   
        </div>
    </div>
    <!--Container-->
    <div class="container" style="overflow-y:scroll;height:300px">
        <ul class="slds-list--vertical slds-has-cards">
            <aura:iteration items="{!v.visitorsList.Histories}" var="h">
                <li class="slds-list__item">
                    <div class="slds-tile slds-tile--board">
                        <div class="slds-tile__detail">
                            <p class="slds-text-heading--medium">{!h.NewValue}</p>
                        </div>
                    </div>
                </li>
            </aura:iteration>	
        </ul>
    </div>
</aura:component>

The force:appHostable interface indicates the component can be hosted in the Salesforce1 Mobile app.
The flexipage:availableForAllPageTypes interface indicates the component can be used in App Builder.
The force:hasRecordId interface indicates the current record Id should be injected in the component’s recordId attribute.
The force:hasSObjectName interface indicates the current sObjectName should be injected in the component’s sObjectName attribute.

When the component is instantiated on the page, the current record Id and sObject are automatically injected in the recordId and sObjectName attribute. You can then make calls to the server passing the recordId and sObjectName as a parameter to retrieve or save data for that specific record.

LastVisitedCmpController.js :

({
	doInit : function(component, event, helper) {
		helper.getViewerList(component);
	},
})

LastVisitedCmpHelper.js :

({
	getViewerList : function(component) {
		var action = component.get("c.getViewersList");
        action.setParams({
            "recordId" : component.get("v.recordId"),
            "objectName" : component.get("v.sObjectName")
        });
        action.setCallback(this, function(action) {
        	component.set("v.visitorsList",action.getReturnValue());
        });
        
        $A.enqueueAction(action);
	},
    updateRecord : function(component) {
		var action = component.get("c.updateRecord");
        action.setParams({
            "recordId" : component.get("v.recordId"),
            "objectName" : component.get("v.sObjectName")
        });
        $A.enqueueAction(action);
	},
})

LastVisitedCmpRenderer.js :

({
    afterRender : function(component,helper){
        this.superAfterRender();
        helper.updateRecord(component);
    }	
})

The afterRender will be called when Component render completly. It will call helper function which updates “Last Viewed By” field of current record in the background.

🙂

Oauth Salesforce with Lightning Out

Posted on

Hi All,

In this article, I will explain the code which can be used for connecting and getting the records
from different or multiple salesforce organization using Apex and Lightning Out.

To start first you need to authorize URLs which can be accessed from salesforce environment.
Go to Setup > Administration Setup > Security Controls > Remote Site Settings.

Create one CONNECTED APP go to SETUP > BUILD > CREATE > APP > CONNECTED APP > NEW.

Create Custom Setting for Version,Client Id,Client Secret. Go to SETUP > BUILD > DEVELOP > CUSTOM Settings.

After completing all the steps let’s start coding.

CallBackURLController.apxc :

public with sharing class CallBackURLController{

    @AuraEnabled
    public Static List<Contact> getContacts(String Accesscode){
    
        version__c vrsn = [select name, ClientId__c, ClientSecret__c from version__c limit 1];
        Accesscode = Accesscode.replace('=','%3D').trim();
        String redireUri = 'https://skdomain-dev-ed--c.ap2.visual.force.com/apex/callbackurl';
        String loginUri = 'https://login.salesforce.com';
        String header = '';
        String endpoint = '';
                
        String reqbody = 'grant_type=authorization_code' + '&client_id=' + vrsn.ClientId__c +
            '&client_secret=' + vrsn.ClientSecret__c + '&code=' + Accesscode + '&redirect_uri=' + redireUri;
        
        endpoint = loginUri + '/services/oauth2/token?' + reqbody;
        
        Map<String, object> mapReqBody = CallBackURLController.getHTTPResponse(endpoint, header, 'POST');
        
        header = string.valueOf(mapReqBody.get('token_type')) + ' ' + string.valueOf(mapReqBody.get('access_token'));
        endpoint = loginUri + '/services/oauth2/userinfo';
        
        ///// User Info       
        Map<String, object> mapReqInfoBody = CallBackURLController.getHTTPResponse(endpoint, header, 'POST');
        
        ///// Query Request
        Map<String, object> mapURI = (Map<String, object>) mapReqInfoBody.get('urls');
        
        string queryUri = string.valueOf(mapURI.get('query')).replace('{version}',vrsn.name);
        endpoint = queryUri + '?q=select+id,Name,Phone,Email+from+contact+where+phone+!=null+limit+1000';
       
        Map<String, object> mapReqQryBody = CallBackURLController.getHTTPResponse(endpoint, header, 'GET');
        string strCons = JSON.serialize(mapReqQryBody.get('records'));
        list<contact> lstCon = (list<contact>) JSON.deserialize(strCons, List<contact>.class);
        return lstCon;
    }
    
    public static Map<String, object> getHTTPResponse(String endpoint, String header, String method){
        HttpRequest req = new HttpRequest();  
        req.setMethod(method);
        req.setEndpoint(endpoint);
        if(header != ''){
            req.setHeader('Content-Type', 'application/json');
            req.setHeader('Authorization', header);
        }
        Http httpReq = new Http();  
        HTTPResponse res = httpReq.send(req);
        return (Map<String, object>)JSON.deserializeUntyped(res.getBody());
    }
    
}

This class is making a callout to other Salesforce Org and fetching Contacts of that Salesforce Org.

LightningOutApp.app :

<aura:application access="GLOBAL" extends="ltng:outApp">
    <aura:dependency resource="c:LightningOutCmp" />
</aura:application>

LightningOutCmp.cmp :

<aura:component controller="CallBackURLController" implements="force:appHostable">
    <aura:attribute name="code" type="String" default=""/>
    <aura:attribute name="contacts" type="Contact[]" />
    <aura:if isTrue="{!v.code==''}">
    	<ui:button label="login into Other Org" press="{!c.redirect}"/>
        <aura:set attribute="else">
        	<ui:button label="Get Contacts" press="{!c.getCons}"/>
        </aura:set>
  	</aura:if> 
    
    <div id="tblDiv" style="display:none">
        <table>
            <tr>
                <th>Name</th>
                <th>Phone</th>
                <th>Email</th>
            </tr>
            <aura:iteration items="{!v.contacts}" var="con">
               <tr>
                   <td>{!con.Name}</td>
                   <td>{!con.Phone}</td>
                   <td>{!con.Email}</td>
                </tr>
            </aura:iteration>        
        </table>
    </div>
</aura:component>

This component will be used in Visualforce Page.

LightningOutCmpController.js :

({
	redirect : function(component, event, helper) {
        window.location.href = 'https://login.salesforce.com/services/oauth2/authorize?response_type=code&client_id=[YOUR CLIENT ID]&redirect_uri=[REDIRECT URL]&prompt=login&display=popup';        
    },
    getCons : function(component, event, helper) {
        document.getElementById("tblDiv").style.display = "block";
        var code = component.get("v.code");        
    	helper.getContacts(component, code);
    },
}

Redirect() function will redirct to the login page for Salesforce Login. getCons() function will get Contact from logged in Salesforce Org.

LightningOutCmpHelper.js :

({
    getContacts: function(component, code) {        
        var action = component.get("c.getContacts");
        action.setParams({
            "Accesscode": code
        });
        var self = this;
        action.setCallback(this, function(actionResult) {
            component.set("v.contacts", actionResult.getReturnValue());       
        });        
        $A.enqueueAction(action);
    },
})

CallBackUrlPage.page

<apex:page showHeader="false" sidebar="false" standardStylesheets="false">
 <!-- Lightning Resources-->
    <apex:includeScript value="/lightning/lightning.out.js" /> 
    <!-- JavaScript to make Remote Objects calls -->
    <script>
        var code="{!$CurrentPage.parameters.code}";
        
        $Lightning.use("c:LightningOutApp", function() {
            $Lightning.createComponent("c:LightningOutCmp",
                  { "code" : code },
                  "lightningComponent",
                  function(cmp) {
                    // any further setup goes here
            });
        });
    </script>
     
    <!-- Lightning Component -->
    <div id="lightningComponent"/>
</apex:page>

When completed it will look like this.

12204800_921217127916108_1436226568_n 12204574_921217134582774_409109935_n 12207968_921217131249441_1515473630_n 12208016_921217124582775_1057121612_n

 

When you click on “Login into Other Org” it will prompt you to login to salesforce. After logging in it will redirect you to Component Page and when you click on “Get Contacts” button it will fetch records from other Salesforce Org.