Newer Version Available

This content describes an older version of this product. View Latest

Lightning Data Service Example

Here’s a longer, more complete example of using Lightning Data Service to create a “Quick Contact” action panel.

Example

This example is intended to be added as a Lightning action on the account object. Clicking the action’s button on the account layout opens a panel to create a new contact.Example of Lighning action using Lightning Data Services

This example is very similar to the example provided in Configure Components for Record-Specific Actions. Compare the two examples to better understand the differences between using @AuraEnabled Apex controllers and using Lightning Data Service.

ldsQuickContact.cmp
1<aura:component implements="force:lightningQuickActionWithoutHeader,force:hasRecordId">
2
3    <aura:attribute name="account" type="Object"/>
4    <aura:attribute name="accountError" type="String"/>
5    <force:recordPreview aura:id="accountRecordLoader"
6      recordId="{!v.recordId}"
7      fields="Name,BillingCity,BillingState"
8      targetRecord="{!v.account}"
9      targetError="{!v.accountError}"
10      />
11
12    <aura:attribute name="newContact" type="Object" access="private"/>
13    <aura:attribute name="newContactError" type="String" access="private"/>
14    <aura:attribute name="hasErrors" type="Boolean"
15        description="Indicate whether there were failures when validating the contact." />
16    <force:recordPreview aura:id="contactRecordCreator"
17        layoutType="FULL"
18        targetRecord="{!v.newContact}"
19        targetError="{!v.newContactError}"
20        />
21
22    <aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
23
24    <!-- Display a header with details about the account -->
25    <div class="slds-page-header" role="banner">
26        <p class="slds-text-heading--label">{!v.account.Name}</p>
27        <h1 class="slds-page-header__title slds-m-right--small
28            slds-truncate slds-align-left">Create New Contact</h1>
29    </div>
30
31    <!-- Display Lightning Data Service errors, if any -->
32    <aura:if isTrue="{!not(empty(v.accountError))}">
33        <div class="recordError">
34            <ui:message title="Error" severity="error" closable="true">
35                {!v.accountError}
36            </ui:message>
37        </div>
38    </aura:if>
39    <aura:if isTrue="{!not(empty(v.newContactError))}">
40        <div class="recordError">
41            <ui:message title="Error" severity="error" closable="true">
42                {!v.newContactError}
43            </ui:message>
44        </div>
45    </aura:if>
46
47    <!-- Display form validation errors, if any -->
48    <aura:if isTrue="{!v.hasErrors}">
49        <div class="formValidationError">
50            <ui:message title="Error" severity="error" closable="true">
51                The new contact can't be saved because it's not valid.
52                Please review and correct the errors in the form.
53            </ui:message>
54        </div>
55    </aura:if>
56
57    <!-- Display the new contact form -->
58    <div class="slds-form--stacked">
59
60        <div class="slds-form-element">
61            <label class="slds-form-element__label" for="contactFirstName">First Name: </label>
62            <div class="slds-form-element__control">
63              <ui:inputText class="slds-input" aura:id="contactFirstName"
64                value="{!v.newContact.FirstName}" required="true"/>
65            </div>
66        </div>
67        <div class="slds-form-element">
68            <label class="slds-form-element__label" for="contactLastName">Last Name: </label>
69            <div class="slds-form-element__control">
70              <ui:inputText class="slds-input" aura:id="contactLastName"
71                value="{!v.newContact.LastName}" required="true"/>
72            </div>
73        </div>
74
75        <div class="slds-form-element">
76            <label class="slds-form-element__label" for="contactTitle">Title: </label>
77            <div class="slds-form-element__control">
78              <ui:inputText class="slds-input" aura:id="contactTitle"
79                value="{!v.newContact.Title}" />
80            </div>
81        </div>
82
83        <div class="slds-form-element">
84            <label class="slds-form-element__label" for="contactPhone">Phone Number: </label>
85            <div class="slds-form-element__control">
86              <ui:inputPhone class="slds-input" aura:id="contactPhone"
87                value="{!v.newContact.Phone}" required="true"/>
88            </div>
89        </div>
90        <div class="slds-form-element">
91            <label class="slds-form-element__label" for="contactEmail">Email: </label>
92            <div class="slds-form-element__control">
93              <ui:inputEmail class="slds-input" aura:id="contactEmail"
94                value="{!v.newContact.Email}" />
95            </div>
96        </div>
97
98        <div class="slds-form-element">
99            <ui:button label="Cancel" press="{!c.handleCancel}"
100                class="slds-button slds-button--neutral" />
101            <ui:button label="Save Contact" press="{!c.handleSaveContact}"
102                class="slds-button slds-button--brand" />
103        </div>
104
105    </div>
106
107</aura:component>
ldsQuickContactController.js
1({
2    doInit: function(component, event, helper) {
3        component.find("contactRecordCreator").getNewRecord(
4            "Contact",
5            null,
6            null,
7            false,
8            $A.getCallback(function() {
9                var rec = component.get("v.newContact");
10                var error = component.get("v.newContactError");
11                if(error || (rec === null)) {
12                    console.log("Error initializing record template: " + error);
13                }
14                else {
15                    console.log("Record template initialized: " + rec.sobjectType);
16                }
17            })
18        );
19    },
20
21    handleSaveContact: function(component, event, helper) {
22        if(helper.validateContactForm(component)) {
23            component.set("v.hasErrors", false);
24            component.set("v.newContact.AccountId", component.get("v.recordId"));
25            component.find("contactRecordCreator").saveRecord(function(saveResult) {
26                if (saveResult.state === "SUCCESS" || saveResult.state === "DRAFT") {
27
28                    // Success! Prepare a toast UI message
29                    var resultsToast = $A.get("e.force:showToast");
30                    resultsToast.setParams({
31                        "title": "Contact Saved",
32                        "message": "The new contact was created."
33                    });
34
35                    // Update the UI: close panel, show toast, refresh account page
36                    $A.get("e.force:closeQuickAction").fire();
37                    resultsToast.fire();
38
39                    // Reload the view so components not using force:recordPreview
40                    // are updated
41                    $A.get("e.force:refreshView").fire();
42                }
43                else if (saveResult.state === "INCOMPLETE") {
44                    console.log("User is offline, device doesn't support drafts.");
45                }
46                else if (saveResult.state === "ERROR") {
47                    console.log('Problem saving contact, error: ' +
48                                 JSON.stringify(saveResult.error));
49                }
50                else {
51                    console.log('Unknown problem, state: ' + saveResult.state +
52                                ', error: ' + JSON.stringify(saveResult.error));
53                }
54            });
55        }
56        else {
57            // New contact form failed validation, show a message to review errors
58            component.set("v.hasErrors", true);
59        }
60    },
61
62    handleCancel: function(component, event, helper) {
63        $A.get("e.force:closeQuickAction").fire();
64    },
65})

The callback passed to getNewRecord() must be wrapped in $A.getCallback() to ensure correct access context when the callback is invoked. If the callback is passed in without being wrapped in $A.getCallback(), any attempt to access private attributes of your component results in access check failures.

Even if you’re not accessing private attributes, it’s a best practice to always wrap the callback function for getNewRecord() in $A.getCallback(). Never mix (contexts), never worry.

Note

ldsQuickContactHelper.js
1({
2    validateContactForm: function(component) {
3        var validContact = true;
4
5        // First and Last Name are required
6        var firstNameField = component.find("contactFirstName");
7        if($A.util.isEmpty(firstNameField.get("v.value"))) {
8            validContact = false;
9            firstNameField.set("v.errors", [{message:"First name can't be blank"}]);
10        }
11        else {
12            firstNameField.set("v.errors", null);
13        }
14        var lastNameField = component.find("contactLastName");
15        if($A.util.isEmpty(lastNameField.get("v.value"))) {
16            validContact = false;
17            lastNameField.set("v.errors", [{message:"Last name can't be blank"}]);
18        }
19        else {
20            lastNameField.set("v.errors", null);
21        }
22
23        // Verify we have an account to attach it to
24        var account = component.get("v.account");
25        if($A.util.isEmpty(account)) {
26            validContact = false;
27            console.log("Quick action context doesn't have a valid account.");
28        }
29
30        // TODO: (Maybe) Validate email and phone number
31
32        return validContact;
33    }
34})