Spring ’18 for Developers: Build Secure and Interactive Forms Faster

One slightly hidden gem in the Spring ’18 Release Notes is the introduction of two new Base Lightning Components—lightning:recordEditForm and lightning:inputField. In this blog post you’ll learn how to build your custom Lightning components even faster with these tools. But before we dig into the goodness provided by those components, let’s revisit where we’re coming from.

It took some time

When we first introduced Lightning, we provided developers with some basic components for entering and displaying fields according to data type. Those components reside in the force namespace and are force:inputField and force:outputField. Why are these components “basic”? Because you as a developer have to take care of things like field-level validation and styling these components to look like Lightning and use the Salesforce Lightning Design System (SLDS).

To address some of these gaps, we started to add Base Lightning Components to the mix. These components, which are in the lightning namespace, automatically inherit the CSS rules of the Salesforce Lightning Design System (SLDS). They include, for example, automated input validation capabilities that can be configured via markup. With these new components, it’s possible to create and maintain Lightning applications much faster than with components from the force namespace. Of course, you were still responsible for calling an Apex controller and handling the consumption of the data.

We addressed the aforementioned requirement of writing Apex by introducing Lightning Data Service (LDS), which went GA with our Winter ’18 release. Using LDS you are able to create, load, save, or delete a record by writing just a couple of lines of markup and a bit of JavaScript. The system automatically takes care of caching and permissions. No Apex needed. Let me repeat: no Apex needed. That also means no Apex tests needed. How cool is that?

But that isn’t still enough…

Introducing lightning:recordEditForm and lightning:inputField

If you paid attention to the Winter ’18 Release Notes (you did, right?), you likely found the new Base Lightning Component lightning:outputField. This component is the counterpart of the aforementioned force:outputField but with a lot more metadata awareness and SLDS styling.

<lightning:recordViewForm recordId="0030Y0000080eMuQAI" objectApiName="Contact">
    <div class="slds-box slds-theme_default">
        <lightning:outputField fieldName="Name" />
        <lightning:outputField fieldName="Phone"/>
        <lightning:outputField fieldName="Email" />
        <lightning:outputField fieldName="Birthdate" />
        <lightning:outputField fieldName="LeadSource" />
    </div>
</lightning:recordViewForm>

By just passing a record ID and the sObject API name as parameter values to the enclosing, lightning:recordViewForm tag, lightning:outputField automatically takes care of formatting the field values, displaying the field labels and so forth based on their sObject definitions.

And now with Spring ’18, we’re introducing lightning:recordEditForm and lightning:inputField.

<lightning:recordEditForm recordId="0030Y0000080eMuQAI" objectApiName="Contact">
    <div class="slds-box slds-theme_default">
        <lightning:messages />
        <lightning:inputField fieldName="Name" />
        <lightning:inputField fieldName="Phone"/>
        <lightning:inputField fieldName="Email" />
        <lightning:inputField fieldName="Birthdate" />
        <lightning:inputField fieldName="LeadSource" />
        <lightning:button class="slds-m-top_small" variant="brand" type="submit" name="update" label="Update" />
    </div>
</lightning:recordEditForm>

Code explanation:

  • Line 1: Instead of lightning:recordViewForm we’re using lightning:recordEditForm as the encapsulating tag. This tag tells the system that editable content should be handled.
  • Line 3: If you want to display error or validation messages to the end user (YES, you want to do that), you have to include <lightning:messages />. However, you don’t have to define those messages, as the framework automatically takes care of that based on the sObject definition!
  • Lines 4-8: You simply set the fieldName parameter for every lightning:inputField and voilà—you get your SLDS-styled input field, including validation and label, derived from the field definition on the sObject.
  • Line 9: For submitting the data to the backend, you have to add a button of type submit within the lightning:recordEditForm tag. This automatically updates the the database once pressed. No custom JavaScript and no Apex needed. You hear me? No custom JavaScript and no Apex needed!

This example is rather simple, but also shows the power and flexibility of lightning:recordEditForm and lightning:inputField. By passing only the record ID and the sObject API name, you no longer have to take care of:

  • Base Lightning Component configuration
  • label selection
  • field level validation and error messaging
  • field level security checks.

It’s all handled for you. But you may now wonder how you can combine lightning:inputField and lightning:outputField. Let’s look at an example that pulls all this power together.

Adding Lightning Data Service to the mix

Users often need to update account information and they need to do this while on a variety of record pages. Thanks to the new Base Lightning Components, we can now build a single component to accomplish this, rather than building quick actions for objects just to use the standard Related Record component.

<aura:component implements="flexipage:availableForRecordHome,force:hasRecordId" access="global">
    
    <aura:attribute name="editMode" type="Boolean" default="false" />
    <aura:attribute name="sourceRecord" type="Object" />
    <aura:attribute name="sourceRecordFields" type="Object" />
    <aura:attribute name="error" type="String" />
    
    <force:recordData aura:id="currentRecord"
                      recordId="{!v.recordId}"
                      fields="AccountId"
                      targetRecord="{!v.sourceRecord}"
                      targetFields="{!v.sourceRecordFields}"
                      targetError="{!v.error}" />
    
     <lightning:card >
         <aura:if isTrue="{!v.editMode}">
            <lightning:recordEditForm onload="{!c.handleAccountLoaded}"
                                      onsubmit="{!c.handleAccountSubmitted}"
                                      onsuccess="{!c.handleAccountSaved}"
                                      recordId="{!v.sourceRecordFields.accountId}"
                                      objectApiName="Account">
                
                <lightning:messages />
                
                <lightning:inputField fieldName="Phone" />
                <lightning:inputField fieldName="Rating" />
                <lightning:inputField fieldName="Description" />
                <lightning:button variant="brand" type="submit" name="save" label="Save" class="slds-m-top_medium"/>

            </lightning:recordEditForm>
            <aura:set attribute="else">
                <lightning:recordViewForm recordId="{!v.sourceRecordFields.AccountId}"
                                          objectApiName="Account">
                   
                    <lightning:outputField fieldName="Phone" />
                    <lightning:outputField fieldName="Rating" />
                    <lightning:outputField fieldName="Description" />
                    <lightning:button variant="brand" onclick="{!c.editAccount}" name="edit" label="Edit" class="slds-m-top_medium"/>
                    
                </lightning:recordViewForm>
                
            </aura:set>
        </aura:if>
    </lightning:card>
    
</aura:component>

Code explanation:

  • Line 1: First we’re using the force:hasRecordId interface on the component. This automatically adds an aura attribute recordId of type Id to the component.
  • Lines 8-13: By using LDS in combination with the recordId attribute a lookup of the AccountId field is performed. The resulting object is stored in the aura attribute contactFields (line 5). This allows us to dynamically fetch the AccountId value from the Contact record without writing any Apex or JavaScript code!
  • Line 16: Because we want to have a read and an edit mode for this component, we’re leveraging aura:if for conditional rendering.
  • Line 17-21: lightning:recordEditForm allows to automatically invoke custom JavaScript according to different circumstances, like when data is loaded, submitted, or after it has been saved. These calls are optional.
  • Line 20: We’re passing the value provided by LDS to set the ‘recordId’ attribute for our form. No Apex needed.
  • Line 28: This is the button that kicks off the save process. Note that there is no onclick event defined and with that no custom JavaScript is called. By defining the type as submit, lightning:recordEditForm automatically handles the save process. In case of any errors <lightning:messages /> will take care of showing them in the UI.

Last but not least, it’s important to mention that LDS as well as lightning:inputField and lightning:outputField are backed by our new UI API.

Where to learn more about lightning:recordEditForm and lightning:inputField

We’re investing heavily in making the Lightning development experience easier for you. By reducing the amount of code that needs to be written and focusing on metadata driven forms, you can now build custom Lightning components easier than ever before.

Here are some great resources that you should check out to get started:

You can also find the example shown above in this GitHub repo, so feel free to install it into the Salesforce DX scratch org of your choice.

About the author

René Winkelmeyer works as Senior Developer Evangelist at Salesforce. He focuses on enterprise integrations, mobile, and security with the Lightning Platform. You can follow him on Twitter @muenzpraeger.

Leave your comments...

Spring ’18 for Developers: Build Secure and Interactive Forms Faster