Lightning Data Services

08:02 2 Comments A+ a-


Lightning Data Services

What is LDS :
                        LDS is Lightning Component that display the data on Page in Salesforce  Lightning. Using LDS we don’t need any apex  controller to perform CRUD operation. using LDS we can increase the performance. It also provide the way to cache the data to work offline in case user is not connected to network. Once the connection is restored data will sync.
LDS also handle Field Level Security and sharing rules security. Record loaded in Lightning Data Services are stored in cache and shared between all components.Using LDS all component performance is increase because data is loaded once and used by many component, no need to make separate request from different-different components . when any of the component  updates  a record then other component will  automatically updated with new value.

force:recordData :
                                    This tag is must be used to load the data in component  using LDS.
Attributes of force:recordData : 
recordId : Id of current page record that will be load
      mode : (Edit,View) its depend on what operation we are performing. If we want to update,create then Mode=’Edit’ else Mode=’View’
layoutType : specify the layout type to display record and its determine what field are included in component. 
          fields : specifies which fields in the record to query.

Target Attribute :
1.      targetRecord  : populate with loaded record.
2.      targetField      : view of loaded record.
3.     targetError      :  populate with error.    

Methods :
1.      saveRecord() : insert of update the current record in force:recordData.
2.      deleteRecord() : delete the current record in force:recordData.
3.      getNewRecord() :  load the new record instance to insert the record of that object from force:recordData.
4.      reloadRecord() : reload the current record with new data.

Keep In Mind When Using It :
i.                LDS is simple but it’s not complete replacement of apex controller.
ii.              LDS is not supported in lightning out and visualforce page. Its only for lightning.
iii.            LDS perform CRUD only on single record. It’s not supported for bulk data.
iv.             In Summer 17, release LDS used force:recordPreview component.But now it’s completely replaced by force:recordData. Difference between force:recordPreview  and force:recordData  is force:recordData  returns record in new shape using UI API and targetfield is added in parameter.
v.               To update from force:recordPreview  to force:recordData is to change reference from targetRecord to targetField.
vi.              If you want to query multiple operations in one transaction then use apex controller @AuraEnabled.


Example :
            Here we are creating a component that is added on Account detail page. It will create a new contact for current account record.


1. Create a new Record :

    Lightning Component :
    <aura:component implements="flexipage:availableForRecordHome, force:hasRecordId">
<aura:attribute name="newContact" type="Object"/>
<aura:attribute name="createContact" type="Object"/>
<aura:attribute name="newContactError" type="String"/>
<force:recordData aura:id="contactRecordCreator"
    layoutType="FULL"
    targetRecord="{!v.newContact}"
    targetFields ="{!v.createContact}"
    targetError="{!v.newContactError}"/>
<aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
            <div class="Create Contact">
                        <lightning:card iconName="action:new_contact" title="Create Contact">
                                                <div class="slds-p-horizontal--small">
<lightning:input aura:id="contactField" label="First Name" value="{!v.createContact.FirstName}"/>
<lightning:input aura:id="contactField" label="Last Name" value="{!v.createContact.LastName}"/>
<lightning:button label="Save Contact" variant="brand" onclick="{!c.handleSaveContact}"/>
                                    </div>
</lightning:card>
            </div>
    <aura:if isTrue="{!not(empty(v.newContactError))}">
        <div class="recordError">
            {!v.newContactError}</div>
    </aura:if>
    </aura:component>

   Lightning Controller :
   ({
    doInit: function(component, event, helper) {
        console.log('changes');
        component.find("contactRecordCreator").getNewRecord(
            "Contact", // sObject type (entityAPIName)
            null,      // recordTypeId
            false,     // skip cache?
            $A.getCallback(function() {
                var rec = component.get("v.newContact");
                var error = component.get("v.newContactError");
                if(error || (rec === null)) {
                    console.log("Error initializing record template: " + error);
                }
                else {
                    console.log("Record template initialized: " + rec.sobjectType);
                }
            })
        );
    },
    SaveContact: function(component, event, helper) {
        component.set("v.createContact.AccountId", component.get("v.recordId"));
        component.find("contactRecordCreator").saveRecord(function(saveResult) {
            if (saveResult.state === "SUCCESS" || saveResult.state === "DRAFT") {
                var resultsToast = $A.get("e.force:showToast");
                resultsToast.setParams({
                    "title": "Saved",
                    "message": "New Contact ."
                });
                resultsToast.fire();
            } else if (saveResult.state === "INCOMPLETE") {
                console.log("User is offline, device doesn't support drafts.");
            } else if (saveResult.state === "ERROR") {
                console.log(JSON.stringify(saveResult.error));
            } else {
                console.log('Unknown problem, state: ' + saveResult.state);
            }
        });
    }
    })
Result :


2. Delete A record :
            Here we added Delete Component on Account Detail Page. It will Delete Current Account when we click on Delete Button in below component.

Lightning Component :
<aura:component implements="flexipage:availableForRecordHome,force:hasRecordId">
    <aura:attribute name="recordError" type="String" access="private"/>
    <force:recordData aura:id="dataRecord"
            recordId="{!v.recordId}"
            fields="Id"
            targetError="{!v.recordError}"
            recordUpdated="{!c.handleRecordUpdated}"/>
     <div class="Delete Record">
            <lightning:card iconName="delete" title="Delete Record">
                                    <div class="slds-p-horizontal--small">
<lightning:button label="Delete Record" variant="destructive" onclick="{!c.handleDeleteRecord}"/>
                                    </div>
            </lightning:card>
       </div>
    <aura:if isTrue="{!not(empty(v.recordError))}">
        <div class="recordError"> {!v.recordError}</div>
     </aura:if>
</aura:component>

Lightning Controller :
({
handleDeleteRecord: function(component, event, helper) {
             component.find("dataRecord").deleteRecord($A.getCallback(function(deleteResult) {
            if (deleteResult.state === "SUCCESS" || deleteResult.state === "DRAFT") {
                console.log("Record is deleted.");
            } else if (deleteResult.state === "INCOMPLETE") {
                console.log("User is offline, device doesn't support drafts.");
            } else if (deleteResult.state === "ERROR") {
                console.log('Problem deleting record, error: ');
            } else {
                console.log('Unknown problem, state: ');
            }
        }));
    },
 handleRecordUpdated: function(component, event, helper) {
        var eventParams = event.getParams();
        if(eventParams.changeType === "CHANGED") {
        } else if(eventParams.changeType === "LOADED") {
        } else if(eventParams.changeType === "REMOVED") {
            var resultsToast = $A.get("e.force:showToast");
            resultsToast.setParams({
                "title": "Deleted",
                "message": "The record was deleted."
            });
            resultsToast.fire();

        } else if(eventParams.changeType === "ERROR") { }
    }
})

Result :


3. Update a Record :
            Here We create a component that will update the account detail on Account Detail page on click of save Button in component.

Lightning Component :
<aura:component implements="flexipage:availableForRecordHome,force:hasRecordId">
    <aura:attribute name="record" type="Object"/>
    <aura:attribute name="accRecord" type="Object"/>
    <aura:attribute name="recordError" type="String"/>
    <force:recordData aura:id="recordHandler"
      recordId="{!v.recordId}"
      layoutType="FULL"
      targetRecord="{!v.record}"
      targetFields="{!v.accRecord}"
      targetError="{!v.recordError}"
      mode="EDIT"
      />
    <div class="Record Details">
        <lightning:card iconName="action:edit" title="Edit Account">
            <div class="slds-p-horizontal--small">
               <lightning:input label="Account Name" value="{!v.accRecord.Name}"/>
               <br/>
               <lightning:button label="Save Account" variant="brand" onclick="{!c.SaveRecord}" />
            </div>
        </lightning:card>
    </div>
    <aura:if isTrue="{!not(empty(v.recordError))}">
        <div class="recordError">
            {!v.recordError}</div>
    </aura:if>
</aura:component>

Lightning Controller :
({
    SaveRecord: function(component, event, helper) {
        component.find("recordHandler").saveRecord($A.getCallback(function(saveResult) {
            if (saveResult.state === "SUCCESS" || saveResult.state === "DRAFT") {
                console.log("User drafts.");
            } else if (saveResult.state === "INCOMPLETE") {
                console.log("User is offline, device doesn't support drafts.");
            } else if (saveResult.state === "ERROR") {
                console.log('Problem saving record, error: ' + JSON.stringify(saveResult.error));
            } else {
                console.log('Unknown problem, state: ' + saveResult.state + ', error: ' + JSON.stringify(saveResult.error));
            }
        }));
    }
})

Result :