Thursday, 8 February 2018

Caching Data with Storable Actions #Lightning Component Salesforce

Caching data at the client side can significantly reduce the number of server round-trips and improve the performance of your Lightning components. Server actions support optional client-side caching, and the Lightning Data Service is built on top of a sophisticated client caching mechanism.

In Lightning terminology, a server action is an Apex method that you invoke remotely from your Lightning Component. A storable action is a server action whose response is stored in the client cache so that subsequent requests for the same server method with the same set of arguments can be accessed from that cache.

Storable actions are the only currently supported type of storage. Storable actions cache server action response values. The storage name must be actions. Caching is especially beneficial for high-performance, mostly connected applications operating over high latency connections, such as 3G networks When you initialize storage, you can configure the expiration time, which is the duration in seconds that an entry is retained in storage..

Using storable actions, the cache behavior is controlled by two parameters set internally in the framework :
  • Expiration age: This is the age of the cached response. Whenever the response is older then the existing one and same vice versa. Expiration age is currently set to 900 seconds in Salesforce lightning.
  • Refresh age: Refresh age is the age of the response, when it gets refreshed, if the response is newer then the existing one, it will override the response, but lightning also calls the server method and get the response, if it different then the existing then it will override it as well. Refresh age is 30 second in lightning experience.

what to cache ?

The caching of the data should be decided on what is the response of your action, there are two type of action, one which returns everytime same thing, and another one is which is doesn't return the same response or dynamic.

The method which returns the same response each time called should be cached and other not,The setStorable function takes an optional argument, which is a configuration map of key-value pairs representing the storage options and values to set.

Cache Miss

If the action is not a cache hit as it doesn’t match a storage entry:
  • The action is sent to the server-side controller.
  • If the response is SUCCESS, the response is added to storage.
  • The callback in the client-side controller is executed.

Cache Hit

If the action is a cache hit as it matches a storage entry:
  • The callback in the client-side controller is executed with the cached action response.
  • If the response has been cached for longer than the refresh time, the storage entry is refreshed. When an application enables storable actions, a refresh time is configured. The refresh time is the duration in seconds before an entry is refreshed in storage. The refresh time is automatically configured in Lightning Experience and the Salesforce mobile app.
  • The action is sent to the server-side controller.
  • If the response is SUCCESS, the response is added to storage.
  • If the refreshed response is different from the cached response, the callback in the client-side controller is executed for a second time..

How to enable Storage Actions ?

To configure client-side storage for your standalone app, use <auraStorage:init> in the auraPreInitBlock attribute of your application’s template. For example:. 

<aura:component isTemplate="true" extends="aura:template">
    <aura:set attribute="auraPreInitBlock">
          defaultAutoRefreshInterval="30" />


Wednesday, 22 November 2017

Salesforce DX: Test Data migration using Salesforce DX

Here I am going to show case a small POC of Data migration using Salesforce DX, its really easy to use, and the process where you want to maintain the test data in different-different Sandbox, then Salesforce DX is for you.

So lets get started,
Before going further, if you have not installed Salesforce DX in your system and please go ahead and install it you system.

Here is the Trailhead link where you can find link to install and get to know more about SalesforcDX.

After installing open the git bash and check whether SalesforceDX got successfully installed or not.

So let me explain you a bit about this process using dx, here we will use two sandbox, one from where we will export the data and the other is the destination sandbox where we will import the data, now this is the first time process, where we are exporting the data from one sandbox, but if its recurring process then we will have the data in JSON format in our local machine, so we just need to export it to other sandboxes.

Please enter

$ sfdx force

If it show the cloud image made up of DX then its installed, now we will create a project first.

$ sfdx force:project:create -n web //create project, its not necessary you can skip this one also

//Add a new sandbox , on hitting this command it will ask you to login to you sandbox and authorize
$ sfdx force:auth:web:login --setalias my-sandbox --instanceurl

//after this do the same thing again and add another sandbox.
//Now if you want to check how many orgs you have added you can by below command
$ sfdx force:org:list

//you have to define an org as default to so that dx will fetch the data from that org. use below for the same
$ sfdx force:config:set --global

//now export the data, here we are exporting only account data, but you can do allot more then this
$ sfdx force:data:soql:query --query "Select Id, Name From Account"

If you'll check that file that DX has created will have the content something like below

    "records": [
            "attributes": {
                "type": "Account",
                "referenceId": "AccountRef1"
            "Name": "Sinclair Community College"
            "attributes": {
                "type": "Account",
                "referenceId": "AccountRef2"
            "Name": "The Institute of Electrical and Electronics Engineers, Inc."
            "attributes": {
                "type": "Account",
                "referenceId": "AccountRef61"
            "Name": "TestLastName"

In the command prompt you'll be able to see the data count as well.

Now to import the data to another sandbox, you just have to hit another command, as its so easy so here are the things need to consider before hitting the command

1. Define the correct source path of the JSON file.
2. Provide the correct sanbox username.
3. Sandbox should be from the list of the sandbox added in the DX.

//to import data to sandbox
$ sfdx force:data:tree:import --targetusername sfdx-out/export-demo-Account-plan.json

Your command prompt

Woohoo!! you have just performed the data migration using SalesforceDX

Here are some links that will be helpfull

Thanks you!!

Friday, 22 September 2017

Winter'18 - Basic Visualforce is now Ready for Lightning View #Salesforce

In this winter 18 release, Salesforce has upgraded what was required, now even if you are new to SLDS, no need to worry about as Salesforce have introduced "lightningStylesheets" tag just to make your life easy.
Designing in lightning sometime you need to search the class name and then add it your page to check whether its the same that you want.

So here is a simple demo of the old style visualforce page having all the things that we might use, and using the same visuaforce page in Lightning by changing nothing. Everything will taken care by salesforce just by using lightningStylesheets.
I have added almost all type of fields as well just to show how it looks without adding any further styling.

Take a look how it works

Here is the Visualforce page

Some good guy said

Thank you!

Monday, 11 September 2017

Using lightning:tree to display Account Hierarchy #Salesforce Lightning Component #Winter'18

 Winter'18 Salesforce have added a new lightning component called lightning:tree, using this we can display the hierarchy of Salesforce.

In this component is going to be great help to all the devs, when they want achieve the accordion looking hierarchy displaying component. This component support only version 41.0 and above

Here is the working demo

So in this post we have a small component which displays the account hierarchy upto 3 levels, I am not further on achieving the hierarchy of Account using Apex, so I did what I can using just a single SOQL.

Here is the component code

 <aura:component controller="LightningTreeApexController" implements="flexipage:availableForRecordHome,force:lightningQuickActionWithoutHeader,force:hasRecordId"> >  
   <aura:handler name="init" value="{!this}" action="{!c.doInit}" />  
   <aura:attribute name="items" type="Object"/>  
   <aura:attribute name="recordId" type="String"/>  
   <lightning:tree items="{! v.items }" header="Account Hierarchy" onselect="{!c.handleSelect}"/>  

Here Lightning component Controller code

   doInit: function (cmp, event, helper) {  
   handleSelect: function (cmp, event, helper) {  
     //return name of selected tree item  
     var myName = event.getParam('name');  
     alert("You selected: " + myName);  

Here is the helper code

   apexMethod : function(cmp) {  
     var action = cmp.get("c.getAccountHierarchy");  
     action.setParams({ accountId : cmp.get("v.recordId") });  
     action.setCallback(this, function(response) {  
       var state = response.getState();  
       if (state === "SUCCESS") {  
         cmp.set( "v.items", response.getReturnValue());  

Here is Apex Controller

 public class LightningTreeApexController {  
   public static List<items> getAccountHierarchy(Id accountId) {  
     //Wrapper instance  
     List<items> finalWrp = new List<items>();  
     //Going upto 2 level only as per SOQL limit  
     for(Account acc : [ Select Id, Name, Type, ParentId, Parent.Name, Parent.Type, Parent.ParentId, Parent.Parent.Name, Parent.Parent.Type From Account Where Id =: accountId]) {  
       //populating wrapper  
       List<items> trP1 = new List<items>{new items(acc.Type, acc.Name, false, null)};  
       List<items> trP2 = new List<items>{new items(acc.Parent.Type, acc.Parent.Name, false, trP1)};  
       finalWrp.add(new items(acc.Parent.Parent.Type, acc.Parent.Parent.Name, false, trP2));  
     System.debug('finalWrp:::' + finalWrp);  
     // return wrapper  
     return finalWrp;    

Here is wrapper class used in Apex controller

 public class items {  
   public string label { get; set; }  
   public string name { get; set; }  
   public Boolean expanded { get; set; }  
   public List<items> items { get; set; }  
   public items( String name, String label, Boolean expanded, List<items> items) {  
     this.label = label; = name;  
     this.expanded = expanded;  
     this.items = items;   

Some important links to learn more about Winter'18 Release

Salesforce Documentation

Lightning Design System : Lightning Tree

Salesforce Release Notes Winter'18

Thanks you

Sunday, 20 August 2017

Lightning Data Service - Salesforce Lightning Remote Objects

Lightning Data Service is in Beta, we can use lightning data service to create, upload, delete and edit salesforce object, without using apex controller, that is it is kind of Remote object that we have for salesforce visualforce page.

As it is beta, so many upgrades will be coming in future, Data access with Lightning Data Service is simpler than the equivalent using a server-side Apex controller. Read-only access can be entirely declarative in your component’s markup. It’s built on highly efficient local storage that’s shared across all components that use it. Records loaded in Lightning Data Service are cached and shared across components. Components accessing the same record see significant performance improvements, because a record is loaded only once, no matter how many components are using it.

here is a small and simple exam of lighting data component for creation of Contact record.

Here is the component code
 <aura:component implements="flexipage:availableForRecordHome,force:lightningQuickActionWithoutHeader,force:hasRecordId">  
   <aura:attribute name="account" type="Object"/>  
   <aura:attribute name="simpleAccount" type="Object"/>  
   <aura:attribute name="accountError" type="String"/>  
   <force:recordData aura:id="accountRecordLoader"  
     recordId="{!v.recordId}" fields="Name,BillingCity,BillingState" targetRecord="{!v.account}"  
     targetFields="{!v.simpleAccount}" targetError="{!v.accountError}"/>  
   <aura:attribute name="newContact" type="Object" access="private"/>  
   <aura:attribute name="simpleNewContact" type="Object" access="private"/>  
   <aura:attribute name="newContactError" type="String" access="private"/>  
   <force:recordData aura:id="contactRecordCreator"  
     layoutType="FULL" targetRecord="{!v.newContact}"  
     targetFields="{!v.simpleNewContact}" targetError="{!v.newContactError}" />  
   <aura:handler name="init" value="{!this}" action="{!c.doInit}"/>  
   <!-- Display a header with details about the account -->  
   <div class="slds-page-header" role="banner">  
     <p class="slds-text-heading--label">{!v.simpleAccount.Name}</p>  
     <h1 class="slds-page-header__title slds-m-right--small slds-truncate slds-align-left">Create New Contact</h1>  
   <!-- Display Lightning Data Service errors, if any -->  
   <aura:if isTrue="{!not(empty(v.accountError))}">  
     <div class="recordError">  
       <ui:message title="Error" severity="error" closable="true">  
   <aura:if isTrue="{!not(empty(v.newContactError))}">  
     <div class="recordError">  
       <ui:message title="Error" severity="error" closable="true">  
   <!-- Display the new contact form -->  
   <lightning:input aura:id="contactField" name="firstName" label="First Name" value="{!v.simpleNewContact.FirstName}" required="true"/>  
   <lightning:input aura:id="contactField" name="lastname" label="Last Name" value="{!v.simpleNewContact.LastName}" required="true"/>  
   <lightning:input aura:id="contactField" name="title" label="Title" value="{!v.simpleNewContact.Title}" />  
   <lightning:input aura:id="contactField" type="phone" name="phone" label="Phone Number"   
            messageWhenPatternMismatch="The phone number must contain 7, 10, or 11 digits. Hyphens are optional."  
           value="{!v.simpleNewContact.Phone}" required="true"/>  
   <lightning:input aura:id="contactField" type="email" name="email" label="Email" value="{!v.simpleNewContact.Email}" />  
   <lightning:button label="Cancel" onclick="{!c.handleCancel}" class="slds-m-top--medium" />  
   <lightning:button label="Save Contact" onclick="{!c.handleSaveContact}" variant="brand" class="slds-m-top--medium"/>  

Controller code

   doInit: function(component, event, helper) {  
       "Contact", null, false,   
       $A.getCallback(function() {  
         var rec = component.get("v.newContact");  
         var error = component.get("v.newContactError");  
   handleSaveContact: function(component, event, helper) {  
     if(helper.validateContactForm(component)) {  
       component.set("v.simpleNewContact.AccountId", component.get("v.recordId"));  
       component.find("contactRecordCreator").saveRecord(function(saveResult) {  
         if (saveResult.state === "SUCCESS") {  
           var resultsToast = $A.get("e.force:showToast");  
             "title": "Contact Saved",  
             "message": "The new contact was created."  
   handleCancel: function(component, event, helper) {  

Helper code

   validateContactForm: function(component) {  
     var validContact = true;  
           var allValid = component.find('contactField').reduce(function (validFields, inputCmp) {  
       return validFields && inputCmp.get('v.validity').valid;  
     }, true);  
     if (allValid) {  
       var account = component.get("v.account");  

This component you can use in Account Object detail page layout, and then try creating a contact record.
There are few things to keep in mind before thinking to use to Data service,

  • Can't be use for multiple records or mass DML's
  • Only available in Lightning & Salesforce1
  • Not all objects are supported by Lightning Data Service, listed in the link

Sunday, 6 August 2017

Installing Lightning CLI and Scanning #Salesforce Lightning Component Code

This blog post is about installing Salesforce Lightning CLI, and how to scan your lightning component code for javascript coding issues and lighting issues. 

Lightning CLI alerts you to specific issues related to LockerService. Issues that are flagged include incorrect Lightning components code, and usage of unsupported or private JavaScript API methods. Lightning CLI installs into the Heroku Toolbelt, and is used on the command line.

Salesforce Lightning CLI is Heroku toolbelt plugin, need to install Heroku toolbelt, Lightning CLI relieas on Heroku toolbelt, so if you don't have Heroku installed, please install from the below link.

After installing Heroku, open cmd, and login to Heroku, git bash doesn't have this option of login to heroku, so need to use cmd only.

After successfull installation of heroku, check for node and npm, and then check for the version of theirs, and then install Lighting CLI

Enter below command

heroku plugins:install salesforce-lightning-cli

You have successfully installed Lightning CLI now. Its time to run and scan your lightning component JS code now.
You can scan a Lightning component in one shot, or a single JS file, to scan enter below command

heroku lightning:lint  ...path-of-your-lightning-component

Here is how Lightning CLI shows the component code errors, 

Above snapshot shows, what you need to modify in the controller and helper code, as it only scans the JS files.

Important links

Thanks !
Hope it helps.

Wednesday, 2 August 2017

Salesforce Progress Indicator Using Lightning Component

Here is the example of Salesforce Progress Indicator using lighting component, and using Salesforce lightning design system, below is how it looks

Here is how it works,

Here is the lightning component code

Component code

 <aura:component implements="force:appHostable,flexipage:availableForAllPageTypes,flexipage:availableForRecordHome,force:hasRecordId" access="global" >  
   <aura:attribute name="iconForStep1" type="String" default="utility:progress" />  
   <aura:attribute name="iconForStep2" type="String" default="utility:progress" />  
   <aura:attribute name="iconForStep3" type="String" default="utility:progress" />  
   <aura:attribute name="iconForStep4" type="String" default="utility:progress" />  
   <aura:attribute name="iconForStep5" type="String" default="utility:progress" />  
   <aura:handler name="init" value="{!this}" action="{!c.doInit}"/>  
   <div class="demo-only" style="padding: 3rem 1rem 0px; background: rgb(244, 246, 249);">  
     <div class="slds-progress slds-progress_shade">  
       <ol class="slds-progress__list">  
         <li class="slds-progress__item">  
           <lightning:buttonIcon aura:id="step1" iconName="{!v.iconForStep1}" class="slds-progress__marker slds-progress__marker_icon" size="small" alternativeText="Step 1 - Completed" />  
         <li class="slds-progress__item">  
           <lightning:buttonIcon aura:id="step2" iconName="{!v.iconForStep2}" class="slds-progress__marker slds-progress__marker_icon" size="small" alternativeText="Step 2 - Error"/>  
         <li class="slds-progress__item">  
           <lightning:buttonIcon aura:id="step3" iconName="{!v.iconForStep3}" class="slds-progress__marker slds-progress__marker_icon" size="small" alternativeText="Step 3"/>  
         <li class="slds-progress__item">  
           <lightning:buttonIcon aura:id="step4" iconName="{!v.iconForStep4}" class="slds-progress__marker slds-progress__marker_icon" size="x-small" alternativeText="Step 4"/>  
         <li class="slds-progress__item">  
           <lightning:buttonIcon aura:id="step5" iconName="{!v.iconForStep5}" class="slds-progress__marker slds-progress__marker_icon" size="x-small" alternativeText="Step 5"/>  
       <!-- this is for the line in between the dots -->  
       <div class="slds-progress-bar slds-progress-bar_small" aria-valuemin="0" aria-valuemax="100" aria-valuenow="50" role="progressbar">  
         <span aura:id="progress" class="slds-progress-bar__value">  
     <div aura:id="tooltip">  
       <div class="slds-popover slds-popover_tooltip slds-nubbin_bottom" role="tooltip" style="position: absolute; top: 5px; left: calc(83% + 8px); transform: translateX(-50%);">  
         <div class="slds-popover__body">Done</div>  
   <div class="demo-only" style="padding: 3rem 1rem 0px; background: rgb(244, 246, 249); position: absolute; left: calc(30% + 15px);">  
     <button class="slds-button slds-button_brand" onclick="{!c.step1Check}">Step 1 Check</button>  
     <button class="slds-button slds-button_brand" onclick="{!c.step2Check}">Step 2 Check</button>  
     <button class="slds-button slds-button_brand" onclick="{!c.step3Check}">Step 3 Check</button>  
     <button class="slds-button slds-button_brand" onclick="{!c.step4Check}">Step 4 Check</button>  
     <button class="slds-button slds-button_brand" onclick="{!c.step5Check}">Step 5 Check</button>  

And here is the controller code

   doInit : function(component, event, helper) {  
     var prog = component.find('progress');  
     $A.util.addClass(prog, 'default');  
     var toggleTooltip = component.find("tooltip");  
     $A.util.addClass(toggleTooltip, "tooltip");  
   step1Check: function(component, event, helper) {  
     var cmpTarget = component.find('step1');  
     $A.util.addClass(cmpTarget, 'slds-is-completed');  
     var prog = component.find('progress');  
     $A.util.removeClass(prog, 'default');  
     $A.util.toggleClass(prog, 'step1');  
   step2Check : function(component, event, helper) {  
     var cmpTarget = component.find('step2');  
     $A.util.addClass(cmpTarget, 'slds-has-error');  
     var prog = component.find('progress');  
     $A.util.toggleClass(prog, 'step2');  
   step3Check : function(component, event, helper) {  
     var cmpTarget = component.find('step3');  
     $A.util.addClass(cmpTarget, 'slds-has-error');  
     var prog = component.find('progress');  
     $A.util.toggleClass(prog, 'step3');  
   step4Check : function(component, event, helper) {  
     var cmpTarget = component.find('step4');  
     $A.util.addClass(cmpTarget, 'slds-has-error');  
     var prog = component.find('progress');  
     $A.util.toggleClass(prog, 'step4');  
   step5Check : function(component, event, helper) {  
     var cmpTarget = component.find('step5');  
     $A.util.addClass(cmpTarget, 'slds-has-error');  
     var toggleTooltip = component.find("tooltip");  
     $A.util.removeClass(toggleTooltip, "tooltip");  

Here the style code for the component

 .THIS {  
 .THIS .step1 {  
 .THIS .step2 {  
 .THIS .step3 {  
 .THIS .step4 {  
 .THIS .tooltip {  
   display: none;  
 .THIS .default {  

To use this component you need to create a test app

 <aura:application extends="force:slds">  
   <c:ProgressBar />   

We can add many more icons, you can find all over Here in Progress Indicator

Here is source code in github.