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>  
   </div>  
   <!-- 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">  
         {!v.accountError}  
       </ui:message>  
     </div>  
   </aura:if>  
   <aura:if isTrue="{!not(empty(v.newContactError))}">  
     <div class="recordError">  
       <ui:message title="Error" severity="error" closable="true">  
         {!v.newContactError}  
       </ui:message>  
     </div>  
   </aura:if>  
   <!-- 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"   
            pattern="^(1?(-?\d{3})-?)?(\d{3})(-?\d{4})$"  
            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"/>  
 </aura:component>  

Controller code

 ({  
   doInit: function(component, event, helper) {  
     component.find("contactRecordCreator").getNewRecord(  
       "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");  
           resultsToast.setParams({  
             "title": "Contact Saved",  
             "message": "The new contact was created."  
           });  
           $A.get("e.force:closeQuickAction").fire();  
           resultsToast.fire();  
           $A.get("e.force:refreshView").fire();  
         }  
       });  
     }  
   },  
   handleCancel: function(component, event, helper) {  
     $A.get("e.force:closeQuickAction").fire();  
   },  
 })  

Helper code

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

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
Thanks


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>  
         <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>  
         <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>  
         <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>  
         <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"/>  
         </li>  
       </ol>  
       <!-- 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">  
         </span>  
       </div>  
     </div>  
     <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>  
     </div>  
   </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>  
   </div>  
 </aura:component>  

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) {  
     component.set("v.iconForStep1",  
            component.get("v.iconForStep1")=="utility:progress"?"utility:success":"utility:progress");  
     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) {  
     component.set("v.iconForStep2",  
            component.get("v.iconForStep2")=="utility:progress"?"utility:success":"utility:progress");  
     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) {  
     component.set("v.iconForStep3",  
            component.get("v.iconForStep3")=="utility:progress"?"utility:success":"utility:progress");  
     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) {  
     component.set("v.iconForStep4",  
            component.get("v.iconForStep4")=="utility:progress"?"utility:success":"utility:progress");  
     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) {  
     component.set("v.iconForStep5",  
            component.get("v.iconForStep5")=="utility:progress"?"utility:success":"utility:progress");  
     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 {  
   width:260px;  
 }  
 .THIS .step2 {  
   width:520px;  
 }  
 .THIS .step3 {  
   width:780px;  
 }  
 .THIS .step4 {  
   width:1050px;  
 }  
 .THIS .tooltip {  
   display: none;  
 }  
 .THIS .default {  
   width:0px;  
 }  

To use this component you need to create a test app

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

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

Here is source code in github.

Thanks