SFDC Stop - Always the latest about Salesforce

Full Tutorial Series with videos, free apps, live sessions, salesforce consulting and much more.

Telegram logo   Join our Telegram Channel

Sunday, 4 February 2018

Salesforce Lightning Tutorial - Part 2 | Update and Save Records

This is the second post in Lightning Tutorial Series and in this post, you'll learn about how to update the record displayed using a lightning component and save the record. In this post, I'll be extending the code used in my first post so, if you are just starting or need to learn about updating records only do have a look at my previous post or at least the code mentioned in that here.

There are some changes in our previous code too that I'll specify while explaining the additional work. As we have already fetched the data from apex controller and displayed in our lightning component, our next step is to provide functionality to update the records and save it back to salesforce within our lightning component itself.

1. Apex Controller

Starting with the apex controller again, up-till now we had only one method in our apex controller, which was used to fetch the contact list. Now we are going to add another method in which we'll pass the contact list to be updated as a parameter and our method will update that list.

As you can see in the above code, I have added another method named - saveContactList which is taking List<Contact> i.e. a list of contacts as a parameter. In this method, we are forming a map which has a key value pair both of string type Map<String,String>. I have named that map resultMap. This map will contain two key-value pairs in which one will tell that the update operation has been performed successfully or not and the second one will hold the message associated with the result of the operation. This resultMap is sent to the lightning component so that it can show the success or error message to the user accordingly.

In the method, I have added try catch that are similar to any programming language and are used to catch exception. In try, I am updating the contactList using the update keyword and if it is updated successfully, I am adding the specific values in resultMap whereas in case of any exception, I am adding e.getMessage() in the map where e is an instance of class Exception and the getMessage() give the exception message as a string. Finally, I am returning the resultMap.

I have made a change in existing code in the getContactList method, you can see that FirstName and LastName are added in query instead of Name as now we have to edit the data and contact Name can be edited as first-name and last-name separately. So, we have to fetch them separately.

2. Lightning Component

Moving on to the Contact List lightning component, have a look at the below code first :-

In the existing code, I have made a small change in lightning:recordViewForm in which I have added FirstName and LastName output fields instead of Name as we are fetching the first name and last name separately using the SOQL. You can see that I have added another aura:iteration tag and a div inside it which has the same slds-box slds-theme_default class as applied earlier in the div inside lightning:recordViewForm tag. Here, we don't need lightning:recordViewForm as we are going to use lightning:input tags to add an input field. You can see two wrapper divs  here in which one has an aura:id of recordViewForm and the second one has an aura:id of recordEditForm. These are used to hide/show one form at a time whose functionality we'll implement in the controller. The recordEditForm div also has a class of formHide which keep it hidden initially. I have also added another button in the lightning card actions which has a variant of brand (blue color) and a label of Edit and has a name attribute with value edit. This method is calling the editContacts function from the lightning controller specified as onclick="{!c.editContacts}".

One last thing I want to mention in this is that I have added a pattern attribute which is associated with lightning:input tag. The pattern attribute has a regular expression pattern="\([0-9]{3}\) [0-9]{3}-[0-9]{4}" which means that the phone number can be of the form ( <3 numbers between 0-9> ) <space> <3 numbers between 0-9> - <4 numbers between 0-9> which helps us to enter a valid phone number. I don't have api version 42.0 yet but if you have that in your org, I recommend you to use lightning:recordEditForm instead of using lightning:input. lightning:recordEditForm has a very similar syntax as lightning:recordViewForm. It is used to edit the form and it's much easier as you may not have to apply regular expression in that. Give it a shot and let me know in the result in the comments section.

3. Lightning CSS

You must be wondering about the formHide class added with wrapper div of edit component. As I have told earlier this css class is used to hide the edit form initially.

As you can see in the above code, In the formHide class, I have added display:none so that my element is not displayed where I have applied this css. That's all for css for now.

4. Lightning Controller

Our next step is to make a lightning controller that will show/hide the recordEditForm, take updated records from recordEditForm and will pass it to the helper so that it can be saved using saveContactList method int the apex controller.

In the above code, you can see that I have added an editContacts function which is called by clicking on the edit action button in our component. So, first of all we are getting a reference to the button using the event.getSource() function, then we are getting the value in the name attribute of that button. We'll use this name value to hide/show the form accordingly. After this line, we are getting the reference to recordViewForm and recordEditForm respectively by using component.find() in which we have to pass the aura:id of the element whose reference we want to have.

After this, I have added a simple if-else which is checking the value of the name attribute if it is edit which it was initially in the component, then it will add formHide class to the recordViewForm attribute so that on clicking edit button, recordViewForm is hidden and it will remove the formHide class from the recordEditForm attribute so that it is displayed. This functionality is accomplished using $A.util.addClass() and $A.util.removeClass() in which $A is the global instance and util is the class containing addClass() and removeClass() methods. In case of edit, the button name is changed to save and label to Save. Whereas, if the button's name is save, then it will call the helper function named - saveContacts to save the list of contacts.

5. Lightning Helper

Moving on to the last part, our Lightning Helper in which I have added a single function to save the contacts. This function will call our apex controller's saveContactList method to save the contact's list. One great thing in lightning is that as you can see in the component's code that I have used contactList attribute to pass in aura:iteration in both view and edit form so that any change in record edit form will automatically effect the contactList attribute value too i.e. the records list and we can simply pick this list and pass to apex controller to save. Let's have a look at code now :- 

As you can see in the above code, first of all I am getting the contact's list and then the reference to viewForm and editForm in the same way as done earlier. Then I have initialized a toast event so that I can show a success or error toast with a proper message like we have in lightning. It is a global event that we get by passing e.force:showToast in the $A.get method. I have defined a saveAction js variable that is pointing to saveContactList apex controller method. Rest steps are same as we are getting the state and then the response from apex controller method. As I have added two keys in map returned from apex controller namely - status and message. So, I am checking if dataMap.status is error then I am setting the toast with params - type : error, mode:dismissable ( it will automatically dismiss after timeout or by clicking on X button ) and a suitable title and message. Then I fired the toast event to show the error message.

Whereas if my contactList is updated and success is there in status, then it will show the recordViewForm back again, hide the recordEditForm, set the button's label and name to Edit and edit respectively and finally fire a toast with a success message to tell the user that data is updated successfully.

You have added the update records functionality to your lightning component too. Your final component looks like this when you click on edit button :-

And when you save your record by clicking on save, it changes back to it's initial form:-

Tired of reading or just scrolled down..!! Don't worry, you can watch the video too.

If you liked this post then do follow, subscribe, comment your views or any feedback and share it with everyone in your circle so that they can also get benefit by this. Hope to see you next time too when we'll learn how to delete a record by embedding a delete button in our component. For the whole code at one place, please refer to my github repository here. You can fork this repo and do your own changes. However please switch to update branch to get the code specified here and not the future changes. Otherwise, directly go to the update branch by clicking here.

Let's move on to Lightning Tutorial Part 3 now in which you'll learn how you can delete the records that are displayed in your lightning component.

Happy Trailblazing..!!


  1. Thank you for this wonderful tutorial. I have one query when I click on edit button and modify the details and then click on save button, the changes are not reflecting immediately on view page. I have to manually refresh the page and then changes are reflecting. I think the same problem I observed in Video. Is there any solution or wayout for this?

    1. Hi, yes you're right and to implement the same, you can get the updated data on the save records call response from apex controller and set the contactList again with the updated values. Give it a try..!!

    2. Hi,you can Firing the standard force:refreshview event on Save Function after the success (toastEvent.fire();) and handle this force:refreshview event on component and call the init method.

    3. Sounds good..!! Have you implemented that ?

  2. Hi,

    How to include a custom picklist in Contact ?


    1. Hi Ramanujam, if you want to include a custom picklist in a lightning component, a good option is to use lightning-combobox. Have a look at the docs:- https://developer.salesforce.com/docs/component-library/bundle/lightning-combobox

  3. Hi Rahul,
    i have taken your code as it is but I am not able to view any record, only the contacts title and new and Edit are appearing. kindly let me know what I m missing

  4. I believe I am not getting the recordId as i tested that with Alert but get 'undefined"

    1. Hi, make sure you've appended force:hasRecordId in your component and using your component in a detail page.

  5. Great set of videos. Thank you for teaching me.

    1. Good to know that you liked it Sid :-) Make sure to share it among your peers too..!!

  6. Great stuff. loved the the way you explained it. Could you please embed some SOSL in it? also if you have time, could you work on web components as well? Thanks :)

  7. Awesome work, Could you please embed some SOSL in it and perhaps when you have time, could you please do some Web components work? Thanks :)

    1. Great to see that you liked it Sal, Can you please post your suggestion here:- https://www.sfdcstop.com/p/what-do-you-want-us-to-post-next.html I'll consider it after I've finished the integration tutorial series that I am posting nowadays.

  8. Hi Rahul,

    Thank you for creating these great videos! I really like how you explain as yo present.

    I am using your code as a proof of concept in the Community we are developing, however when I click the EDIT button I receive the following error:

    This page has an error. You might just need to refresh it.
    Error in $a.getCallback() [Cannot read property 'setParams' of undefined]
    Callback failed:apex://ContactListController/ACTION$saveContactList
    Failing descriptor:{markup://c:ContactList}

    Can you help?

    Kind regards,


    1. Hi Robert,

      I think the issue is with the save button as described in your comment below so replying there.

  9. Hi Rahul,

    Thank you for creating the excellent videos. I especially appreciate how you explain how and why as part of teaching concepts.

    I am using your code, but cannot get past and error when I click the Save button:

    This page has an error. You might just need to refresh it.
    Error is $A.getCallback()[Cannot read property 'setParams' of undefined]
    Callback failed:apex://ContactListController/ACTION$saveContactList
    Failing descriptor:{markup://C:ContactList}

    Can you help solve this error?

    Thank you.


    1. Thank you Robert for your feedback. Happy to know that you liked my videos :-)

      Regarding the issue, I believe that's because the saveAction variable is not defined. Check this line in your code:- var saveAction = component.get("c.saveContactList"); and make sure you've created an apex method named "saveContactList" in your class. I can help more if you can share your code by creating a github gist.

      You can also copy and paste the exact code from here:- https://github.com/rahulmalhotra/SFDC-Lightning/blob/update/src/aura/ContactList/ContactListHelper.js and see if that works.

      Apex class code:- https://github.com/rahulmalhotra/SFDC-Lightning/blob/update/src/classes/ContactListController.cls

      Hope that helps..!!

    2. Hi Rahul,

      I am trying to adapt your code for Case -> CaseComment application in our Customer Service Community...is this even possible?

    3. Hey Robert, not sure about what's happening in your scenario as I need to have a look at the whole thing. But, lightning components are available and can be used in community very easily. So, it should be possible.

  10. Really awesome videos...great explanation.