trailhead

Use Lightning Data Service

One of the big changes developers face when moving from the Visualforce world into Lightning components is how to communicate with the server. Up until the Summer ’17 release, this meant creating an Apex class to do anything—even simple CRUD interactions that were handled “automagically” in Visualforce. With the Summer ’17 release and the introduction of Lightning Data Service, this all changed. So, for our component, we use Lightning Data Service to create a new property record—without writing Apex!

Add force:recordData

  1. In the Developer Console, in the PropertyDialog component, add the following between the aura:attribute and c:PickListValues we just added:

    <aura:attribute name="propertyRecord" type="Property__c" />
    <force:recordData aura:id="forceRecord"
                    recordId="{!v.recordId}"
                    targetFields="{!v.propertyRecord}"
                    fields="Id,Name,Beds__c,Baths__c,Price__c,Status__c"
                    mode="EDIT" />
    

    Lightning Data Service uses an object named force:recordData to perform CRUD interactions on records. There are several other attributes for force:recordData, but for our purposes, we only need recordId, targetRecord, fields, and mode.

    When a value is assigned to the recordId attribute, behind the scenes, Lightning Data Service retrieves either the entire record or the requested fields. The resulting fields are stored in the attribute defined by the targetFields attribute; in this case, propertyRecord. Finally, the mode attribute defines whether or not this instance of force:recordData is in VIEW mode or EDIT mode. Obviously, since we’re creating a record, it needs to be in EDIT mode.

Initializing a New Record

  1. Add the following on a new line after the force:recordData tag:

    <aura:handler name="init" value="{!this}" action="{!c.doInit}" />
    
  2. Click Controller in the side navigation to add a controller to the component.

  3. Rename the default function from myAction to doInit and add the following to the function:

    component.find("forceRecord").getNewRecord(
            "Property__c",
            null,
            false,
            $A.getCallback(function() {
                var rec = component.get("v.propertyRecord");
                var error = component.get("v.recordError");
                if (error || (rec === null)) {
                    console.log("Error initializing record template: " + error);
                    return;
                }
            })
        );
    

    The getNewRecord of force:recordData takes four parameters. The first parameter, Property__c, defines the entity API name for the sObject of the record to be created. The next parameter is for the recordTypeId. We’re leaving it set to null, which simply says to use the default record type based on the user’s profile. The third parameter determines whether or not to load the record template from the client-side cache. And finally, the callback checks for an error or whether the propertyRecord attribute was not populated.

Save a New Record

  1. In the PropertyDialogController add a new function named saveRecord and pass the component, event, helper as parameters:

    saveRecord : function(component, event, helper) {
    }
    

    Don't forget the comma to separate the functions!

  2. Add the following to the new function:

    var propBeds = parseInt(component.find('propBeds').get("v.value"), 10);
    var propBaths = parseInt(component.find('propBaths').get("v.value"), 10);
    var propPrice = parseInt(component.find('propPrice').get("v.value"), 10);
    
    component.set("v.propertyRecord.Name", component.find('propName').get("v.value"));    
    component.set("v.propertyRecord.Beds__c", propBeds);
    component.set("v.propertyRecord.Baths__c", propBaths);
    component.set("v.propertyRecord.Price__c", propPrice);
    component.set("v.propertyRecord.Status__c", component.find('propStatus').get("v.value"));
    
    var tempRec = component.find("forceRecord");
    tempRec.saveRecord($A.getCallback(function(result) {
        console.log(result.state);
        var resultsToast = $A.get("e.force:showToast");
        if (result.state === "SUCCESS") {
            resultsToast.setParams({
                "title": "Saved",
                "message": "The record was saved."
            });
            resultsToast.fire();                
        } else if (result.state === "ERROR") {
            console.log('Error: ' + JSON.stringify(result.error));
            resultsToast.setParams({
                "title": "Error",
                "message": "There was an error saving the record: " + JSON.stringify(result.error)
            });
            resultsToast.fire();
        } else {
            console.log('Unknown problem, state: ' + result.state + ', error: ' + JSON.stringify(result.error));
        }
    }));
    

    When we save the record, we ensure that the values are correct for the field type. Beds__c, Baths__c and Price__c are all set to be integers in the Property__c object. So, when we grab the value from the input, we convert it from a String to an integer using the parseInt JavaScript method. Once converted, we update the values in the propertyRecord attribute along with the values from the other form fields.

    Next, we call the force:recordData method of saveRecord using the variable assignment of tempRec to save the new values of the record back to Salesforce. Oh, did we mention that that was it? Seriously, tempRec.saveRecord() and we’re done!

    Of course, there’s more going on here in the callback to the saveRecord method. After ensuring that the record was successfully saved, we throw up a toast to let the user know that the save worked.

  3. Save PropertyDialogController.js and switch back to the PropertyDialog component.

  4. Add onclick="{!c.saveRecord}" to the lightning:button that submits the dialog (the button with label="submit").

  5. Save the file.

Navigate to the New Record After Save

Once the record has been saved, we don’t want the dialog to just sit there. So, we have a choice to make: Either we navigate to the Property list, or to the newly created record. Let’s make an executive decision and navigate to the newly created record.

  1. In the Developer Console, click Helper in the side navigation to add a helper file to the PropertyDialog component.

    When you initially start building Lightning components, it feels natural to put all of the JavaScript functions in the controller file. However, within the controller file, you can’t call one function from another. So, in our example, if we built a function to navigate to a record, we couldn’t call it from the saveRecord function. Which would mean that we’d have to write the entire functionality into the saveRecord function. This is bad—it might lead us to repeat our code in a later function. Therefore, it’s a better practice to put anything we might need to either call multiple times or be called from another function, into the helper file.

  2. Replace the default contents of the helper file with:

    ({
        navigateTo: function(component, recId) {
            var navEvt = $A.get("e.force:navigateToSObject");
            navEvt.setParams({
                "recordId": recId
            });
            navEvt.fire();
        }
    })
    

    This function simply calls the built-in platform event force:navigateToSObject, passing the recordId that we receive from the callback of recordSave.

  3. Save the file.

  4. Switch back to PropertyDialogController.js.

  5. Add the following on a new line after resultsToast.fire(); in the Success State of the callback (somewhere around line 40):

    var recId = result.recordId;
    helper.navigateTo(component, recId);
    
  6. Save the file, then head back to your org and refresh the property detail page.

  7. Fill in the form with these values:

    • Name: 123 Main St.
    • Beds: 4
    • Baths: 3
    • Price: 500000
    • Status: Pre-Market
  8. Click Submit.

alt text: The record was successfully saved.

Are you impressed? You just saved a new record without writing any Apex code to do it! Even if you’re a hardcore developer, that’s got to feel pretty amazing. Next up, let’s finish what we set out to do and override the New button.

retargeting