Monday, April 27, 2020

Javascript Promise.all : Way to perform action when Multiple Parallel enqueued Actions are Completed in Lightning Components

As we all know that all actions from Lightning components are sent to server in asynchronous manner and we can not predict the sequence about response from server.

If we have requirement to wait for all operations to complete and then perform some action on lightning components like hiding the spinner or displaying all data at once.

We can either queue the first server call and when we get response then we perform second server call. For this you can use Javascript Promise pattern to sequence the server call. Please refer below URL for complete understanding of sequencing of server call using javascript promise.

JavaScript Promises vs Callback Functions in Lightning Components

Now if we need to fire server calls in parallel and want to wait for all response, then you can utilize promise.all methods to achieve this. This will execute many promises in parallel and wait until all of them are ready. Below is syntax to use promise.all:
 
//create array of promise and pass it to promise.all 
var promiseArray =[promise1, promise2];
var combinedPromise = Promise.all(promiseArray);
//this return single promise. Now handle it with then and catch
combinedPromise
.then($A.getCallback(function(results){
 //handle success
 var promise1Results = results[0]; //Results from Promise 1
 var promise2Results = results[1]; //Results from Promise 2
})) 
.catch($A.getCallback(function () { 
 //Handle errors on any promise here
 console.log('Some error has occured'); 
}));

Note:
  • Promise.all takes an array of promises and returns a new promise.
  • The new promise resolves when all listed promises are settled, and the array of their results becomes its result.
  • Order of the resulting array members is the same as in its source promises. Even though the first promise takes the longest time to resolve, it’s still first in the array of results.
  • If any of the promises is rejected, the promise returned by Promise.all immediately rejects with that error.
  • For example, if there are multiple fetch calls and one fails, the others will still continue to execute, but Promise.all won’t watch them anymore. They will probably settle, but their results will be ignored. Promise.all does nothing to cancel them, as there’s no concept of “cancellation” in promises.
  • This will help to improve the performance of lightning components as server operations are not performed in sequential order. Due to parallel call to server, lightning components will perform better.
I have created a sample lightning component which fetch Account and Task records from server and displays it in UI only when both operations are completed and response is returned to lightning components. below is gif image displaying the lightning component functionality:


Below is complete snippet for your reference:

Hope this will help!!

Friday, April 17, 2020

Get the Content (Blob) of File from Box and Store/Manipulate it in Salesforce

Through this blog, I am going to share sample apex script through which you can get content of file from box as blob and then store or manipulate it within salesforce.

I have already written a blog to explain how to get box access token (needed for handshake with Box) and to display file content in salesforce in VF page without storing it in salesforce. You can cosider it as Mashup inSalesforce. Please refer below URL to that:

Box and Salesforce Integration

In order to get box file content, we need to have box file Id and box access token.

Box does not provide direct API to get file content. First you need to do callout to get download URL and then you perform another API callout to get file content. Also you perform another API call to get file details like filename in order to store it in salesforce.

I am going to store box file in salesforce library for demo purpose. You can store it as attachments or read the content on the fly to perform some logic instead of saving it.

Add below URLs in remote site settings before performing the callouts:
  • https://api.box.com
  • https://dl.boxcloud.com 

Below is required code and it is self explainatory as comments are mentioned for each methods:

Now run below script in developer console:

string boxFileId='6542xxx28604';
string access_token='0xxxxxxxxxxxxxxxxxxxxxxxxxxxredx0P';
string sfdcLibraryName='Box_File_Library';
string boxFilename= SK_BoxAPIUtilityClass.findFileNameFromBox(boxFileId,access_token);
system.debug('****boxFilename:'+boxFilename);
SK_BoxAPIUtilityClass.readFileContentFromBox(boxFileId,boxFilename,sfdcLibraryName,access_token);



Use Case

During sandbox refresh, all custom settings data gets refreshed from production values. So before refresh, you have to take back up each custom settings data and after refresh, you need to update the custom setting records. In order to automate this, you can write script through which you can push all custom setting data to box folder. Code to upload the files from Salesforce to box is already shared in blog  Box and Salesforce Integration.

Now we need to get the content of all csv files stored in box and update the custom setting in salesforce. Once you get the content of file, you can parse csv file and update custom settings.

Hope this helps!!!


Saturday, April 11, 2020

JavaScript Promises vs Callback Functions in Lightning Components

As we all know that all server calls from lightning components are asynchronous in nature. If we call 2 different apex methods from lightning components, then there is no surety that which will return response first. In order to provide sequencing between these 2 calls, we have to write second method call in callback function of first apex call as mentioned below:

findDataUsingNormalCall : function(component, event, helper) {
  var actionName1= component.get("c.findMyAccounts");
  var params1={"numberOfRecords":2};
  actionName1.setParams(params1);
  actionName1.setCallback(this, function(response) {
    var state = response.getState();
    if (state === "SUCCESS") {
        var apexResponse1=response.getReturnValue();
        component.set("v.ltngAccList",apexResponse1);
       //Now perform second Call
        var actionName2= component.get("c.findMyPendingTasks");
        var params2={"numberOfRecords":2};
        actionName2.setParams(params2);
        actionName2.setCallback(this, function(response) {
           state = response.getState();
           if (state === "SUCCESS") {
              var apexResponse2=response.getReturnValue();
              component.set("v.ltngTaskList",apexResponse2);
           }else if(state === "ERROR"){
              var errors2 = response.getError();
              console.error(errors2);
           }
        });
        $A.enqueueAction(actionName2);
     }else if(state === "ERROR"){
        var errors1 = response.getError();
        console.error(errors1);
     }
  });
  $A.enqueueAction(actionName1);

Now if you have to perform multiple server side apex calls from lightning components in sequential order, code becomes very difficult to understand and read and difficult to maintain this kind of code.

Javascript Promises

Promise pattern is very common in javascript to handle asynchronous operations.  Prior to promises events and callback functions were used but they had limited functionalities and created unmanageable code.

Promise can have 3 states:
  • Pending
  • Fulfilled
  • Rejected
Use below syntax to create promise:

var promise1 = new Promise($A.getCallback(function(resolve, reject){
     //perform logic like server call
     if (/* success */) {  
        resolve("result");
     }else {
        reject("error");
     }
}));
  • Constructor takes only one argument as a function. 
  • Callback function takes two arguments, resolve and reject
  • Perform operations inside the callback function and if everything went well then call resolve.
  • If desired operations do not go well then call reject.
In order to consume promise, use .then or .catch methods as shown below:

promise1 . 
    .then($A.getCallback(function(result){
             //handle success
 }), 
 $A.getCallback(function(error){
            //handle error
        })
     ) 
    .catch($A.getCallback(function () { 
        console.log('Some error has occured'); 
    }));

Remember:
  1. then() method automatically invoked when promise is either resolved (fulfilled) or reject.
  2. then() method takes 2 functions as parameters:
    • If promise is resolved and a result is received, First function is executed.
    • If promise is rejected and an error is received, Second function is executed(optional).
  3. catch() method is invoked when a promise is either rejected or some error has occurred in execution. catch take 1 function as parameter. If you are using the second parameters for then function then use catch for error handling.
Calling multiple asynchronous functions and Chaining them using Promises

You can use below pattern in order to perform different asynchronous operation in synchronous manner.

new Promise($A.getCallback(function(resolve, reject){}))
    .then(
        // resolve handler
        $A.getCallback(function(result) {
   //when first call is successfull, then create new 
   //instance of promise to make another call
          return new Promise($A.getCallback(function(resolve,reject){}));
        }),
 // reject handler
        $A.getCallback(function(error) {
            console.log("Promise was rejected: ", error);
    //you can create another promise for error handling
        })
    )
    .then(
        // resolve handler
        $A.getCallback(function() {
            //perform logic when second call is successfull
        })
    );
I have created a sample lightning component which explain the functionality of callback function and promise pattern. Below are details about this component functionality:
  • Component contains 2 button which invoke 2 different apex methods by using callback pattern and promise pattern.
  • When user clicks on "Fetch 2 records using callback pattern" button, system fires 2 server calls to get account and task records in asynchronous manner. So records will get displayed on UI based on response from server. There will be no sequencing of these 2 method invocation.
  • When user clicks on "Fetch 3 records using promise pattern", system first fire an asynchronous call to get account records and once account data is recieved, then it will fire another asynchronous call to get task records. This functionality uses promise pattern to fire 2 asynchronous call in synchronous manner. 


Below is code snippet:

Best Practices:
  • Always use catch or reject handler.
  • Always use $A.getCallback() when using promise pattern in lightning components. Even if you do not use this, then sometimes it will work but it will be very difficult to debug if something went wrong. Sometimes if you don't use it, then results may get delayed on UI and can cause performance issues. 
Hope this will help!!

Thursday, January 30, 2020

Fetch All Workflow Email Alert Details Related to Object Using Tooling API

Through this blog, I will sharing script which can help to get complete information about all the email alerts configured in Salesforce using workflow rules for any sObject.

Imagine a scenario in which you need to extract all email alert configured or created for different workflow rules for specific object so that it can be reviewed or analyzed. If you do this activity manually then you have to open each workflow email alert and note down details like recipient, ccEmails, senderAddress, email template etc. This will be very hectic if you have lots of email configured.

In order to solve this scenario, I am using Tooling API through which we can get complete details about workflow email alert. Through apex script, we can generate these details and send email (with csv file as attachment) to user with all details.

First of all, inorder to parser JSON response, we need to create apex class (SK_EmailAlertJSONParser) which will act as parser for JSON. After this we can run the script in developer console and user will get email with all information regarding email alert.


Below is snapshot of csv file that we will receive after running above script in developer console.
I have specified objectId as "Contact". For custom object, specify 15 digit or 18 digit id.


This script can be used to fetch information from other salesforce org also. Suppose you don't want to deploy this script in production, then save SK_EmailAlertJSOnParser class in sandbox and in developer console (using execute anonymous window)  just specify the domainUrl for production and sessiond id production for admin user.

Don't forget to add domainUrl in remote site settings before running this script in execute anonymous window in developer console.

Hope this will help!!1

Thursday, January 9, 2020

How to Delete all Files from Library using Apex

If you have to delete any library, then first you have to delete all the files present in that library. For this purpose you can run below mentioned simple apex script to delete all files from library.

string LibraryName='Demo Library';
ContentWorkspace ws = [SELECT Id, RootContentFolderId FROM ContentWorkspace WHERE Name = :LibraryName LIMIT 1];
List<ContentDocument> contentDocumentIds = new List<ContentDocument>();
for(ContentDocumentLink con:[select id,LinkedEntityId,ContentDocumentId   from ContentDocumentLink  where LinkedEntityId=:ws.Id]){
    contentDocumentIds.add(new ContentDocument(id=con.ContentDocumentId));
}
system.debug('********contentDocumentIds:'+contentDocumentIds);
system.debug('********contentDocumentIds.size:'+contentDocumentIds.size());
database.delete(contentDocumentIds,false);


Hope this will help!!

Wednesday, January 8, 2020

Download Multiple Files from Libraries

Consider a scenario in which we are suppose to download all files from libraries. Below are different approach which can be utilized:

Approach 1: Salesforce UI Download Button

If the file size is around 60 or less in library then you can use Salesforce UI to download all files at one time.

Open any library, click on show all button, then click on display options and select "Show 60 results per page". By doing this, you will be able to see 60 files at once in library. Now you can click on select all checkbox and click download button. This will help you to download files at once.
If you have more than 60 files, then click on next page and then again download all files. This process will become hectic if you have more than 1000 files in library.

Approch 2:URL hack

I performed some search on google and found out that there is another way to download all files as zip by specifying the contentversion Ids of file in URL. I can call it as URL hack and everyone mentioned that it is not recommended way. Below is URL format that you need to use:

https://xxxxxx.salesforce.com/sfc/servlet.shepherd/version/download/068xxxxxxxxxxxxxxx/068yyyyyyyyyyyyyyy/068wwwwwwwwwwwwwww/068zzzzzzzzzzzzz?

Just paste this URL and files will be downloaded as zip file.

If you have more than 1000 files in library, then you have to build different URL by specifying 10 or 15 record id in one URL. I was able to download zip file with size around 400Mb using one URL.

Approach 3: Using Apex Script & Tab Save Chrome Extension

One of my friend told me about Tab Save  chrome extension. You just need to paste all files download url and click on download.



This will download all files in your downloads folder or folder that you have specified in chrome download settings.

Now we wrote simple apex script which will send email with all URLs(file download URL) in csv file. Suppose you want to get download URLs for all files present in library "Demo Download Library", then refer below script:

Run above script in developer console by specifying your library name. You will receive email with all file download URLs. Now you just copy and paste these URLs in Tab Save edit window and click on download.

I have used Tab Save extension to download around 1500 files and it was working fine.

Now you have all 3 approaches and you can decide what to chose based on your requirements.

Hope this will help!!



Tuesday, November 19, 2019

How to Convert Salesforce Classic Notes into Lightning Notes

As now everyone is migrating to Lightning, Salesforce supports lightning Notes(ContentNote) instead of Classic Notes. So while migrating to lightning, we have to convert all classic Notes to lightning Notes. Salesforce provide an appexchange app called magic mover for this purpose.

If you don't want to install this app and would like to perform this conversion, then you can do it with very simple apex script.

If you want to understand How to Convert Salesforce Attachments into Salesforce Files then refer below URL:

Convert Salesforce Attachments into Salesforce Files


I have created a batch class which will convert all Notes related to object (based on query that you pass) to ContentNote and you will receive an email with all details once batch job is completed.

Suppose you want to convert all the notes related to Account to Lightning Notes, then use below script in execute anonymous in developer console.

string qstring='Select id from Account';
SK_ConvertNotesForLightningBatch newjob= new SK_ConvertNotesForLightningBatch(qstring);
database.executeBatch(newjob);

Below is snapshot of csv file which you receive after this batch job completed.

Hope this will help!!