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

Saturday 27 January 2018

Salesforce Lightning Tutorial - Part 1 | Fetch and display data from server

This is the first post in the Lightning Tutorial Series. In this post, you'll learn how you can you fetch data from an apex controller and display it in the lightning component. Mainly the read operation in CRUD (Create, Read, Update and Delete). If you want to learn about the very basics of lightning like:- what is lightning ? What are the pre requisites ? etc. then you can refer to my previous post Salesforce Lightning Basics.

Now, we are going to code a lightning component that will display all the contacts related to an account and then we'll replace it with the standard related list of contacts under the account detail page in lightning.

1. Create an Apex Controller

// Apex Controller for Contact List Lightning Component
public class ContactListController {
	
    @AuraEnabled
    public static List<Contact> getContactList(List<Id> accountIds) {
    	// Getting the list of contacts from where Id is in accountIds
	List<Contact> contactList = [SELECT Id, Name, Email, Phone, AccountId FROM Contact WHERE AccountId in :accountIds];
	// Returning the contact list
        return contactList;
    }
}
As you can see in the above code that I have created a very simple apex controller which takes a single argument i.e. a list of account ids and return a list of contacts related to all the accounts whose ids are passed as a parameter. The above method is static as the non- static @AuraEnabled methods cannot have parameters. The @AuraEnabled annotation is used to specify that this method will be called from lightning component.

2. Create a Lightning Component

<aura:component implements="flexipage:availableForRecordHome,force:hasRecordId" controller="ContactListController" access="global" >
    <!-- Handler to call function when page is loaded initially -->
    <aura:handler name="init" action="{!c.getContactsList}" value="{!this}" />
    <!-- List of contacts stored in attribute -->
    <aura:attribute name="contactList" type="List" />
    <!-- Lightning card to show contacts -->
	<lightning:card title="Contacts">
        <!-- Body of lightning card starts here -->
        <p class="slds-p-horizontal_small">
            <!-- Aura iteration to iterate list, similar to apex:repeat -->
            <aura:iteration items="{!v.contactList}" var="contact">
                <!-- recordViewForm to view the record -->
                <lightning:recordViewForm recordId="{!contact.Id}" objectApiName="Contact">
                    <div class="slds-box slds-theme_default">
                        <!-- outputfield used to output the record field data inside recordViewForm -->
                        <lightning:outputField fieldName="Name" />
                        <lightning:outputField fieldName="Email" />
                        <lightning:outputField fieldName="Phone" />
                    </div>
                </lightning:recordViewForm>
                <!-- Line break between two records -->
                <br />
            </aura:iteration>
        </p>
        <!-- Lightning card actions -->
        <aura:set attribute="actions">
            <!-- New button added -->
            <lightning:button label="New" onclick="{!c.newContact}" />
        </aura:set>
    </lightning:card>
</aura:component>
If you remember, I have told in my previous post that Lightning Component tags are like html tags. In the above code, the lightning component implements flexipage:availableForRecordHome ( as we have to embed our component in a standard record detail page ) and force:hasRecordId ( this will help the component to get the record Id of the record which is being displayed on the page, here it will be the account id as we are going to embed this component in account detail page ). After this, I have used a aura:handler tag with attribute name - init and value - {!this} this name and value is fixed as we are going to specify a function in action which will be called automatically when the record is loaded initially. In the action, I have written c.getContactsList here c stands for controller but it's not the apex controller, it's the lightning controller in which I have defined the getContactsList function which I am calling on initial loading of the page.

So, till now we have made a lightning component in which getContactsList method is called which will mainly be used to fetch the list of contacts from apex controller we previously created. But wait...where are we going to store this list ? Correct..!! We need an apex attribute to store the list. So, I have used an apex attribute tag which is of type list as I have to store list in this attribute ( remember..we returned a list from apex controller method).

Next steps are pretty simple and straight forward:-

  1. I used a lightning card tag to show my contacts wrapped in a card and gave the title Contacts
  2. Lightning Card body consists of a paragraph tag with an slds class so defined the same. You can have a detailed look at lightning card tag here.
  3. In the body I have to display the contacts list, so I have used aura iteration tag and in the items, I have given {!v.contactList} as I have to iterate through the contactList to show the contacts and each contact is represented using a var which is given the value contact. It is very similar to apex:repeat if you have worked on visualforce pages before.
  4. After that, I have used lightning:recordViewForm tag which is mainly used to display a record. You just have to pass the recordId and the objectApiName as the attributes which I have given as {!contact.Id} and Contact respectively.
  5. In the lightning recordViewForm, I have used lightning:outputField tag in which we just have to pass the field name and I have done so. You can have a detailed look at lightning recordViewForm tag here.
  6. Before closing the lightning card tag, I have used aura:set tag in which I have given the attribute as actions as I am going to add action buttons in this.
  7. Finally, I have added a lightning button with label New and given a controller function in the onclick attribute which will be called when the button is clicked.

3. Creating a Lightning Controller

({
    // Function called on initial page loading to get contact list from server
    getContactsList : function(component, event, helper) {
        // Helper function - fetchContacts called for interaction with server
	helper.fetchContacts(component, event, helper);
    },

    // Function used to create a new Contact
    newContact: function(component, event, helper) {
        // Global event force:createRecord is used
        var createContact = $A.get("e.force:createRecord");
        // Parameters like apiName and defaultValues are set
        createContact.setParams({
            "entityApiName": "Contact",
            "defaultFieldValues": {
                "AccountId": component.get("v.recordId")
            }
        });
        // Event fired and new contact dialog open
        createContact.fire();
    }
})
This is very simple. In lightning controller, we mainly keep the functions that are called from the page. It consists of 3 parameters component, event and helper which are used to interact with the component, event and helper respectively. If you want to pass another parameter, you can add after these. I personally prefer to keep all the client side actions in the controller itself and use helper for the server calls. In the above code, I have created two functions, getContactsList and newContact. If you remember I called the getContactsList from the init handler to fetch the data, so this require a server call. Therefore, I simply called the fetchContacts function from the helper which will be doing everything so we'll discuss it later. For now, let's concentrate on newContact function which will fire an event to create a new contact. In this function, $A is used to reference global event e.force:createRecord. We assigned this event to createContact variable. Then we set the parameters entityApiName as Contact and in the defaultFieldValues I have specified the AccountId only as I want this to be filled by default and I have given recordId in this which is the id of account under which we are creating a contact. Then, we fire the event. Remember the create record dialog which we get when we create a new record...?? This will do exactly the same thing. The global event can run only in one.app container. In other words, new button will work only when our component is embedded somewhere in a detail page ( having one.app - salesforce org url ).

4. Creating a Lightning Helper

({
    // Function to fetch data from server called in initial loading of page
    fetchContacts : function(component, event, helper) {
        // Assign server method to action variable
        var action = component.get("c.getContactList");
        // Getting the account id from page
        var accountId = component.get("v.recordId");
        // Setting parameters for server method
        action.setParams({
            accountIds: accountId
        });
        // Callback function to get the response
        action.setCallback(this, function(response) {
            // Getting the response state
            var state = response.getState();
            // Check if response state is success
            if(state === 'SUCCESS') {
                // Getting the list of contacts from response and storing in js variable
                var contactList = response.getReturnValue();
                // Set the list attribute in component with the value returned by function
                component.set("v.contactList",contactList);
            }
            else {
                // Show an alert if the state is incomplete or error
                alert('Error in getting data');
            }
        });
        // Adding the action variable to the global action queue
        $A.enqueueAction(action);
    }    
})
This is the last part of our lightning component in which, we'll hit the apex controller method, pass the account id, fetch all the contacts related to the account and finally push all the contacts in the contactList attribute. A helper method also consists of 3 parameters component, event and helper which are passed from the controller from where it is called. It is not compulsory to pass all 3 but recommended to do so and use a 4th parameter to pass anything else. I have used component.get() function in the first line that takes the apex controller method as a parameter and assigned it to action variable. So, I have passed c.getContactList in it where c refers to apex controller and getContactList is the method we defined in our apex controller. I have used the same component.get() to get the account id from the page. The only difference is that while referencing the page I have used v instead of c as - v.recordId. I have set the parameters for action which is the parameters my apex controller method is using. In the accountIds of apex controller I have passed accountId which is my javascript variable. action.setCallback will hit the server method with parameters and we have a response in return. The response.getState() is used to check whether our call is successful or not and response.getReturnValue() gives us the list of contacts which were returned from the apex controller method. Finally, I have set the list fetched from apex controller method to my own aura attribute in component which is of type List and then I have added this action to the global action queue by using $A.enqueueAction() and passing the action as parameter in this function. All this functionality is performed during the initial loading of the page.

Congrats..!! you just made your first lightning component. It looks like this:-

And when you click on the new button, you'll have the standard dialog which is as follows:-


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

If you liked this post, then do follow, comment your views and share. Hope to see you next time too when you'll learn that how to edit an existing record and save it in salesforce org using custom lightning component. For the whole code at one place please refer to my github repository here. You can clone the repository and switch to the read branch that will consists of only the above mentioned code.

Let's move on to Lightning Tutorial Part 2 now in which you'll learn how you can update and save the records back to salesforce that are displayed in your lightning component.

Happy Trailblazing..!!

79 comments:

  1. new button is not working pls check once

    ReplyDelete
    Replies
    1. Hi Harish,

      Can you share your code ?

      Delete
    2. how to update status via aura component?

      Delete
    3. Which status are you talking about ? Can you explain in detail please ?

      Delete
    4. New Button is not working if I copy paste your code.. It gives the below error:
      This page has an error. You might just need to refresh it.
      Action failed: niksaryan88:MyContactComp$controller$newContact [Cannot read property 'setParams' of undefined]
      Failing descriptor: {niksaryan88:MyContactComp$controller$newContact}

      Delete
    5. Even after embedding the component in my lightning page, it did not work, same error.

      Delete
    6. This page has an error. You might just need to refresh it.
      Action failed: niksaryan88:MyContactComp$controller$newContact [Cannot read property 'setParams' of undefined]
      Failing descriptor: {niksaryan88:MyContactComp$controller$newContact}

      Delete
    7. Hi Nikhil, I just tried copying and pasting the same code again in a new org just to make sure that the e.force:createRecord function is working fine and the new button is working fine without any issues. Can you make sure that you've embedded your component on the account detail page? As the new button won't work in the preview.

      Also, please check you are not running into any cache issues.

      Delete
  2. I copied the same code which you have given for me I am getting contacts header and new button only.It is displaying the list of contacts from the server pls let me know y

    ReplyDelete
    Replies
    1. New Button will work only when you have embedded your component to any page. Make sure you have done that. It'll not work in the preview of your app.

      Delete
    2. I copied the same code which you have given for me I am getting contacts header and new button only.It is not displaying the list of contacts from the server pls let me know y

      Delete
    3. Hi Anitha,

      Have you embedded your component in the accounts detail page ?

      Delete
    4. Hi Rahul sir,

      I have limited knowledge regarding lightning. Could you please tell Me how can this issue be resolved.
      I am getting contacts header and new button only....
      no contacts in the list is displayed and I get a error when I click on the new button.
      "This page has an error. You might just need to refresh it.
      Action failed: c:MyContactComp$controller$newContact [Cannot read property 'setParams' of undefined]
      Failing descriptor: {c:MyContactComp$controller$newContact}"

      Delete
    5. You just need to embed your component in the detail page of an account as new button is using global action so it'll not work in preview.

      Delete
  3. Can u pls share ur mail id to share the code beacuse to share the code here it is not accepting the html tags in our code

    ReplyDelete
    Replies
    1. You can share the link by adding a gist of code on github or just send it through the contact form on the right side. Thanks

      Delete
  4. Thank you for this wonderful tutorial. The video was very helpful.Will go over the rest.

    ReplyDelete
    Replies
    1. Happy to see that you liked it Alo :-) Do share it in your network so that others can get benefit too

      Delete
  5. This comment has been removed by the author.

    ReplyDelete
    Replies
    1. Hi Hiteshwar,

      You must embed the contacts under the account detail page otherwise you can call the component by using an app and pass the account id yourself.

      Delete
  6. Hi rahul I’m doing the same i’m also getting records but im facing problems with recordviewform

    ReplyDelete
    Replies
    1. You can share the code with me then and maybe you have completed by now. Your comment was automatically moved to spam just checked now

      Delete
  7. This comment has been removed by the author.

    ReplyDelete
  8. Very fantastic blog, I like very much. Expect that you can share more articles about salesforce tech!

    ReplyDelete
    Replies
    1. Happy to see that you liked it. Do share it in your network so that others can get Benefit too. I try my best to post at least one article per week. There will be a lot of articles soon. :-)

      Delete
  9. greate work..please keep post basics of lightning

    ReplyDelete
    Replies
    1. Thank you Ananga, do share it in your network and I have added a total of 5 tutorials and youtube playlist to explain the basic crud operation in lightning. Next playlist is about Lightning Events which I'll upload soon.

      Delete
  10. Error:
    Maximum call stack size exceeded ??

    ReplyDelete
    Replies
    1. Hi Aman, you have an infinite loop or recursive function running in your js controller. Check it once.

      Delete
  11. Hi Rahul ,i am new to lightning can you help me with lightning component that will show my custom object detail page with all the related list .
    Also like we have apex:pageBlockSection in vf page ,what is their in Lightning for the same .
    I want related list to be collapsible thats why I am using apex:pageBlockSection.

    Thanks in advance!!!

    ReplyDelete
    Replies
    1. Hi Sonal, for object detail, I'll recommend you to use lightning:recordViewForm tag in lightning and for related list as far I know there is no particular tag available from salesforce as in the lightning app builder itself, you can easily drag and drop related lists. However, if you still want to make it custom, you have to use slds and develop it yourself by fetching data from server and use js to make it collapsible.

      Delete
  12. Will this work on the Event object?

    ReplyDelete
    Replies
    1. Hi Nick, can you explain a little more that which event object are you talking about ?

      Delete
  13. how can i display lookup records in the output field?

    ReplyDelete
    Replies
    1. Hi, you can use either lightning:inputField or give a try to force:inputField for making lookup and lookups are mainly input fields only not output fields.

      Delete
  14. Nice Article Rahul,Looking forward to see more latest features in Lightning.

    ReplyDelete
    Replies
    1. Thank you Sasya :-) Do share it in your network and checkout the other articles and videos too in the series

      Delete
  15. Hiii... The look and feel is not in the lightning format

    ReplyDelete
    Replies
    1. Make sure you've extended force:slds in your lightning application

      Delete
    2. Thank you, I understood but how to learn this quickly

      Delete
    3. If you're talking about SLDS or even if about lightning, practice is the only key to learn asap.

      Delete
  16. am getting this error can you please help

    This page has an error. You might just need to refresh it.
    Action failed: c:ContactsComponent_v1_0$controller$newContact [Cannot read property 'setParams' of undefined]
    Failing descriptor: {c:ContactsComponent_v1_0$controller$newContact}

    ReplyDelete
    Replies
    1. Hi Aditya, Thanks for reaching out. The global action is used in case of creating new contact. It'll not work in your app preview. Try to embed your component in a detail page or somewhere else and it'll work :-)

      Delete
    2. COuld you pleas tell us the way....
      I am ahving the same problem but unable to understand the solution

      Delete
    3. Hi Rahul me too facing same Cannot read property 'setParams' of undefined]

      Delete
    4. Hi everyone, you just need to go to the account detail page. Click on edit page from the settings (gear) icon, search for your custom lightning component and embed that component anywhere in the page by dragging and dropping. Then your global actions will work properly.

      Delete
  17. Hi Rahul,

    My new button is not working, in one.app container also. Nothing is happening when clicking on new button. Though I used force:createRecord many time, but its strange its not working. Used the same code as yours.
    Please assist.
    Thanks

    ReplyDelete
    Replies
    1. There must be a difference in code in that case, can you create a github gist and share the link ? Or message me directly on twitter @rahulcoder

      Delete
  18. First Thing i have copied all your code and checked it is not any any contacts list and when im clicking new button this the erroer popping up
    This page has an error. You might just need to refresh it.
    Action failed: c:ContactRowsAndNewbutton$controller$newContact [Cannot read property 'setParams' of undefined]
    Failing descriptor: {c:ContactRowsAndNewbutton$controller$newContact}

    ReplyDelete
    Replies
    1. Contact list will show only if you have passed an account id or embedded your component in a detail page of an account that actually has contacts. New button will work on embedding your component to the detail page.

      Delete
  19. Hi,
    I have created all the things mentioned above, but "New" Contact throws the following error. Fed up and copied the snippet for 'newContact' from this site but still get the same error. Thanks

    This page has an error. You might just need to refresh it.
    Action failed: c:LightningContactsList$controller$newContact [Cannot read property 'setParams' of undefined]
    Failing descriptor: {c:LightningContactsList$controller$newContact}

    ReplyDelete
    Replies
    1. Hi Chaitu,

      The global action is used in case of creating new contact. It'll not work in your app preview. Try to embed your component in a detail page or somewhere else and it'll work :-)

      Delete
  20. Rahul can u plz tell the approach about how to display the value of the fields of a custom object on a lightning page that i have to create

    ReplyDelete
    Replies
    1. Hi Ritesh, if you just want to display the field values you can use lightning:recordViewForm. Have a look at this:- https://www.sfdcstop.com/2018/04/create-lightning-component-to-view.html

      Delete
  21. Hi Rahul,

    Very Useful, How can we insert the edit button on this lighting card.

    ReplyDelete
    Replies
    1. Hi, you'll get to know about that in further tutorials in the series, checkout other tutorial 2, 3 and so on..

      Delete
  22. Hi Rahul,

    Can you please help me with the edit button on lighting card, so we can edit the record. or is there any way we can click on the name and go the contact record.

    ReplyDelete
    Replies
    1. You can do that by converting that name into an HTML link that points to the salesforce id of the record. Give it a try..!!

      Delete
  23. Hi Rahul,
    While i'm doing that got blank screen and in the console log.I find this error.

    Refused to load the script 'https://scrlink.cool/optout/get?jsonp=__twb_cb_719573523&key=1f64ae463ad99be7d8&t=1554461990164' because it violates the following Content Security Policy directive: "script-src 'self' 'nonce-2a037104-1e17-445f-b11c-d571ce7f240a' chrome-extension: 'unsafe-eval' https://sfdc.azureedge.net *.visualforce.com https://ssl.gstatic.com/accessibility/". Note that 'script-src-elem' was not explicitly set, so 'script-src' is used as a fallback.

    ReplyDelete
    Replies
    1. Seems like you're using some external script in your code or a chrome extension that is causing this error.

      Delete
  24. Hello Sir,

    I want to ask something new in salesforce .
    please give me your mail id or contact Number

    ReplyDelete
    Replies
    1. Hi, Please contact me on twitter (@rahulcoder) or instagram (@imrahulmalhotra) :-)

      Delete
  25. This page has an error. You might just need to refresh it.
    Unable to find action 'getContactList' on the controller of c:MyContactComp
    Failing descriptor: {c:MyContactComp} ....can you please help..

    ReplyDelete
    Replies
    1. Hi, please check the controller and make sure you're using the correct method name.

      Delete
  26. Hi Rahul,

    I have same kinda requirement but the thing is instead of the Lightning button i am using the list view button list view button is calling the VF page and lightning component is being called in the Vf page can you please post if you have done the same kinda work.Thank you.

    ReplyDelete
    Replies
    1. Hi Vinu, you can use "lightning out" to call a lightning component inside a VF page.

      Delete
  27. Hi Rahul,

    I have the similar kind of requirement but there is a slight changes in my requirement instead of the lightning button we need to create the list view button and from there we need to call the VF page and lightning components is being called from the VF page. can you help me if you have developed the similar kind of code.Thank yo..!

    ReplyDelete
    Replies
    1. Hi Vinu, you can use "lightning out" to call a lightning component inside a VF page. I am not aware if you can add custom buttons on list view, I think you need to create a custom list view in that case. Try:- lightning data table if you want to create a custom list.

      Delete
  28. Hi Rahul,

    Excellent tutorials! Will this code work in Communities? If so, how do I make the components available under Custom Components?

    Thank you.

    Robert

    ReplyDelete
    Replies
    1. Hey Robert,

      Happy to see that you liked it buddy. Make sure to share it among others too :-)

      Regarding your query, Yes. It should work for communities too. If you see the first line of my lightning component, it has:- flexipage:availableForRecordHome interface implemented, due to this it's available in the homepage. There are similar different interfaces like:- flexipage:availableForAllPageTypes that will allow it to appear under custom components to be used on other pages as well. Hope that helps..!!

      Delete
  29. Hi Rahul,
    The tutorial is really good. Can you please help me in creating a lookup field in Lightning component

    ReplyDelete
    Replies
    1. Hi, Thanks Buddy :-)

      I recommend to use a lightning:recordeditform for that as you can just specify the field api name inside that in lightning:inputField and it'll automatically create the field even if it's a lookup.

      Checkout the docs here:- https://developer.salesforce.com/docs/component-library/bundle/lightning:recordEditForm/example

      Delete
  30. please help for how to get related data of custom object....
    I have two custom object , Emp and Desk, i have used master deatil relationship, and i want data of related employee of particular desk on pop up window

    ReplyDelete
    Replies
    1. You can use an inner query for the same. Read more about it here:- https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_soql_relationships_query_using.htm

      Delete
  31. Hi rahul I am getting a problem in this code.Can you help me please?

    ReplyDelete
  32. Hi harish,

    Can you share your code
    Details:kadiritarun284@gmail.com

    ReplyDelete
    Replies
    1. Hey Tarun, Thanks for reporting the issue. You can find the code in the post itself, it's fixed now. I am updating other posts as well, it may take a while. Hopefully, I'll be done by EOD today.

      Delete
  33. Really very very usefull, i was confusion execution flow of Lightning Component before this but after saw this video get confidence. Thank uuuuuuuuuuuuuuuuuuuuuuuuuuuuu

    ReplyDelete