Lightning Component To Display Contacts Related To Particular Account | Salesforce Lightning

salesforce lightning component to display contacts realted to particular account

Salesforce Lightning Component to Display Contacts Related to particular Account


Prerequisites :

- Lightning Experience must be enabled in your Org.
- My Domain Must be enabled and deployed.


Step 1 : Create Apex Class for fetching Contact Details :

Use notation “@AuraEnabled” so that it is available in our component.

--------------------------------------------------Apex Class------------------------------------------------------
public with sharing class AjinkyaTestLightningAccController 
{
    @AuraEnabled
    public static list<Contact> getRelatedList(Id recordId)
    {
        List<Contact> Conlist = [Select id, name,firstname,lastname from Contact where AccountId=: recordId ];
        return Conlist;
    }
}
--------------------------------------------------Apex Class------------------------------------------------------

Step 2 : Create a New lightning Component :

- Add Controller name in the Component 
- Create attributes of ID and Contact List so that we can fetch the records from the controller to Component.



--------------------------------------------------Cmp------------------------------------------------------
<aura:component controller = "AjinkyaTestLightningAccController" implements="flexipage:availableForRecordHome,force:hasRecordId" access="global" >
    <aura:attribute name="recordId" type="Id" />
    <aura:attribute name="ContactList" type="Contact[]" />
</aura:component>
--------------------------------------------------Cmp-------------------------------------------------------

Step 3 : Create Controller (JS) for this Component :

- Create any variable from where can call our method written in apex class and retrieve the data. 

- In Our example, we have created a variable ConList where we are calling the method “getRelatedList(Id recordId)” which we have created in our class earlier in 1st step.


- In Lightning component, the syntax for calling method is “c.methodname”  in our case it will be “c.getRelatedList”.


- Now We have to pass the parameter of ID (Account ID) so that it will query our data. Using the same variable Conlist we will add a parameter to the method. “.setParams()” is the method for setting parameter. In our example it will be “Conlist.setParams()”


- After setting parameter we have to set data in component attributes we created earlier in Step 2. “.setCallback()” method will return our data from query and using component.set(“v.attributename” , data.getReturnValue())  we will set the values in the component. In our example it will be - component.set(“v.ContactList” , data.getReturnValue()).


--------------------------------------------------JS------------------------------------------------------
({
myAction : function(component, event, helper) 
    {
        var ConList = component.get("c.getRelatedList");
        ConList.setParams
        ({
            recordId: component.get("v.recordId")
        });
        
        ConList.setCallback(this, function(data) 
                           {
                               component.set("v.ContactList", data.getReturnValue());
                           });
        $A.enqueueAction(ConList);
}
})
--------------------------------------------------JS------------------------------------------------------

Step 4 : Change component code to display the data :

- We have to use “aura:handler” to call an action function from our JS.
--------------------------------------------------Cmp-------------------------------------------------------
<aura:component controller = "AjinkyaTestLightningAccController" implements="flexipage:availableForRecordHome,force:hasRecordId" access="global" >
<aura:attribute name="recordId" type="Id" />
    <aura:attribute name="ContactList" type="Contact[]" />
    <aura:handler name="init" value="{!this}" action="{!c.myAction}" />
    <aura:iteration  items="{!v.ContactList}" var="con">
        Contact Name = {!con.Name} <br/>
    </aura:iteration>
</aura:component>
--------------------------------------------------Cmp-------------------------------------------------------

Step 5 : Add the component to Our Lightning Page.

- Click on Account Tab 
- Open any account which has related contacts.
- Click on Setup button Edit Page.





Now add our created component to this Page.


C:\Users\Administrator\Desktop\Session Prep\LightningComponent2.PNG


Save the Page. If a pop up appears to assign as org default then click on Assign as Org Default button. If a pop up doesn't appear your component is saved.

Now Go Back to an Account Detail page with contacts in it. You can see the component we just added.


C:\Users\Administrator\Desktop\Session Prep\LightningComponent4.PNG
Let's add some design to it. 

You can add any designs (CSS) of your choices. Explore the salesforce lightning design system (SLDS )library.

Step 6 : Decorating our component.

--------------------------------------------------Cmp-------------------------------------------------------

<aura:component controller = "AjinkyaTestLightningAccController" implements="flexipage:availableForRecordHome,force:hasRecordId" access="global" >
    <aura:attribute name="recordId" type="Id" />
    <aura:attribute name="ContactList" type="Contact[]" />
    <aura:handler name="init" value="{!this}" action="{!c.myAction}" />
    <lightning:card iconName="standard:work_capacity_usage" title="Related Contacts">
        <table class="slds-table slds-table_cell-buffer slds-table_bordered">
            <thead>
                <tr class="slds-line-height_reset">
                    <th class="slds-text-title_caps" scope="col">
                        <div class="slds-truncate" title="File Name">FirstName</div>
                    </th>
                    <th class="slds-text-title_caps" scope="col">
                        <div class="slds-truncate" title="File Name">LastName</div>
                    </th>
                </tr>
            </thead>
            <tbody>
                <aura:iteration  items="{!v.ContactList}" var="con">
                    <tr class="slds-hint-parent">
                        <td data-label="File Name">
                            <div class="slds-truncate" title="File Name">{!con.FirstName}</div>  
                        </td>
                        <td data-label="File Name">
                            <div class="slds-truncate" title="File Name">{!con.LastName}</div>  
                        </td>
                    </tr>
                </aura:iteration>
            </tbody>
        </table>
    </lightning:card>
</aura:component>
--------------------------------------------------Cmp-------------------------------------------------------

This is Our Final Component After some designing, we have used an HTML table to store values. 

C:\Users\Administrator\Desktop\Session Prep\LightningComponent5.PNG


Step 7: Now we have a problem in the above component. Did you think of a
scenario where there are no contacts in account what will happen ? 

Let's have a look into it. Create a new account with no contacts in it or else open any existing account with no contacts.

C:\Users\Administrator\Desktop\Session Prep\LightningComponent6.PNG

- As we can see in the above picture there are no contacts still we have a view of table headers.(“FIRSTNAME”, “LASTNAME”). Or Sometimes in some of the components may cause a component crash and will throw an error message if no data is retrieved.

- Let’s handle this by adding Aura if-else. (You can refer EPISODE 9 if you are unaware of using it.)

- Let’s use our decorated component for this.

- We just need to add : <aura:if isTrue="Our Condition"> before our table starts.
And finish this with else condition after our table part ends.
(You can write any error message you want).

After adding our condition, code will look something like this : 
--------------------------------------------------Cmp-------------------------------------------------------

<aura:component controller = "AjinkyaTestLightningAccController" implements="flexipage:availableForRecordHome,force:hasRecordId" access="global" >
    <aura:attribute name="recordId" type="Id" />
    <aura:attribute name="ContactList" type="Contact[]" />
    <aura:handler name="init" value="{!this}" action="{!c.myAction}" />
    <lightning:card iconName="standard:work_capacity_usage" title="Related Contacts">
        <aura:if isTrue="{!not(empty(v.ContactList))}">
            <table class="slds-table slds-table_cell-buffer slds-table_bordered">
                <thead>
                    <tr class="slds-line-height_reset">
                        <th class="slds-text-title_caps" scope="col">
                            <div class="slds-truncate" title="First Name">FirstName</div>
                        </th>
                        <th class="slds-text-title_caps" scope="col">
                            <div class="slds-truncate" title="last Name">LastName</div>
                        </th>
                    </tr>
                </thead>
                <tbody>
                    <aura:iteration  items="{!v.ContactList}" var="con">
                        <tr class="slds-hint-parent">
                            <td data-label="File Name">
                                <div class="slds-truncate" title="File Name">{!con.FirstName}</div>  
                            </td>
                            <td data-label="File Name">
                                <div class="slds-truncate" title="File Name">{!con.LastName}</div>  
                            </td>
                        </tr>
                    </aura:iteration>
                </tbody>
            </table>
            <aura:set attribute="else">
                <div Style="text-align : center"> " There are no related contacts "</div>
            </aura:set>
        </aura:if>
    </lightning:card>
</aura:component>

--------------------------------------------------Cmp-------------------------------------------------------

Output for above code (If there are no contacts): 

C:\Users\Administrator\Desktop\Session Prep\LightningComponent7.PNG

- We have handled the scenario where there are no related Contacts in Account.

- Let’s Take this Component to little advance level.


--------------------------------------------------------------------------------------------------------------------------------------------

Step 7: Inline Editing.

- Firstly let’s replace our normal HTML table to lightning DataTable.

- Delete our previous table.


- Create a new attribute of list type to store the column values. (Column values are mandatory for lightning datatable, we will discuss it as we go ahead with component).

--------------------------------------------------Cmp-------------------------------------------------------

<aura:component controller = "AjinkyaTestLightningAccController" implements="flexipage:availableForRecordHome,force:hasRecordId" access="global" >
    <aura:attribute name="recordId" type="Id" />
    <aura:attribute name="ContactList" type="Contact[]"/>
    <aura:attribute name="columns" type="List"/>
    
    <aura:handler name="init" value="{!this}" action="{!c.myAction}" />
    <lightning:card iconName="standard:work_capacity_usage" title="Related Contacts">
        <aura:if isTrue="{!not(empty(v.ContactList))}">
            
            <aura:set attribute="else">
                <div Style="text-align : center"> " There are no related contacts " </div>
            </aura:set>
        </aura:if>
    </lightning:card>
</aura:component>

--------------------------------------------------Cmp-------------------------------------------------------
- In the above code snippet we have removed our old table and just added a new attribute “columns” of type “list”.
- Now add column values from our JS(which was created by us earlier).

--------------------------------------------------JS------------------------------------------------------
({
myAction : function(component, event, helper) 
     {

component.set('v.columns', [
            {label: 'First Name', fieldName: 'FirstName', type: 'text' },
            {label: 'Last Name', fieldName: 'LastName', type: 'text' }
         ]);

        var ConList = component.get("c.getRelatedList");
         ConList.setParams
         ({
            recordId: component.get("v.recordId")
         });
        
         ConList.setCallback(this, function(data) 
                           {
                               component.set("v.ContactList", data.getReturnValue());
                           });
         $A.enqueueAction(ConList);
}
})
--------------------------------------------------JS------------------------------------------------------

- By adding these above 2 lines we will automatically store the column header of our fields with
its values in a list “column”.

Time to add datatable :
--------------------------------------------------Cmp-------------------------------------------------------
<aura:component controller = "AjinkyaTestLightningAccController" implements="flexipage:availableForRecordHome,force:hasRecordId" access="global" >
    <aura:attribute name="recordId" type="Id" />
    <aura:attribute name="ContactList" type="Contact[]"/>
    <aura:attribute name="columns" type="List"/>
    
    <aura:handler name="init" value="{!this}" action="{!c.myAction}" />
    <lightning:card iconName="standard:work_capacity_usage" title="Related Contacts">
        <aura:if isTrue="{!not(empty(v.ContactList))}">
            <lightning:datatable data="{!v.ContactList }" 
                         columns="{!v.columns }" 
                         keyField="Id"
                         hideCheckboxColumn="true"/>
            <aura:set attribute="else">
                <div Style="text-align : center"> " There are no related contacts " </div>
            </aura:set>
        </aura:if>
    </lightning:card>
</aura:component>
--------------------------------------------------Cmp-------------------------------------------------------

Making above changes Our output will remain the same as before(Same as HTML table we created earlier) but now we have access to more functionalities of the lightning data table.

How about changing or editing random fields from the same page. Let’s do it.

Firstly add a parameter to the 2 column fields we just added in JS: (“editable : true”)
Which will allow us to edit fields directly.

--------------------------------------------------JS------------------------------------------------------
({
myAction : function(component, event, helper) 
     {

component.set('v.columns', [
            {label: 'First Name', fieldName: 'FirstName', type: 'text' ,  editable: true},
            {label: 'Last Name', fieldName: 'LastName', type: 'text' ,  editable: true}
         ]);

        var ConList = component.get("c.getRelatedList");
         ConList.setParams
         ({
            recordId: component.get("v.recordId")
         });
        
         ConList.setCallback(this, function(data) 
                           {
                               component.set("v.ContactList", data.getReturnValue());
                           });
         $A.enqueueAction(ConList);
}
})
--------------------------------------------------JS------------------------------------------------------

A pencil symbol will appear by hovering our mouse and you will be able to edit any field by clicking
on that pencil icon/symbol.


Wait wait kid …..I am not done yet.

We can just change in the values in UI (Box) but we now need to update these values from our controller so that changes can be saved directly on the same page. Correct ?

- Quickly Create a new attribute in our component to add updated values.

<aura:attribute name="UpdatedList" type="Contact[]"/>

- Now we have to create a method in apex from where we can update the contact.

Add this method snippet in our existing Apex controller:-

--------------------------------------------------Apex Class------------------------------------------------------

public with sharing class AjinkyaTestLightningAccController 
{
@AuraEnabled
public static list<Contact> getRelatedList(Id recordId)
{
        
List<Contact> Conlist = [Select id,firstname,lastname from Contact where AccountId =: recordId ];
return Conlist;
}
    
@AuraEnabled
public static void updateRelatedList(List<Contact> Conlist)
     {
         if(Conlist!= null && Conlist.size()>0)
         {
             update Conlist;
         }
        
}

--------------------------------------------------Apex Class------------------------------------------------------

- After creating the above method lets update our Component First then we can make some small changes in JS:

- Draftvalues is a parameter in the datatable from where we can get updated values from our component
directly.

- Assign the attribute “UpdatedList” to “draftValues” parameter. As shown below.

--------------------------------------------------Cmp-------------------------------------------------------

<aura:component controller = "AjinkyaTestLightningAccController" implements="flexipage:availableForRecordHome,force:hasRecordId" access="global" >
    <aura:attribute name="recordId" type="Id" />
    <aura:attribute name="ContactList" type="Contact[]"/>
    <aura:attribute name="columns" type="List"/>
    <aura:attribute name="UpdatedList" type="Contact[]"/>
    
    <aura:handler name="init" value="{!this}" action="{!c.myAction}" />
    <lightning:card iconName="standard:work_capacity_usage" title="Related Contacts">
        <aura:if isTrue="{!not(empty(v.ContactList))}">
            <lightning:datatable data="{!v.ContactList }" 
                         columns="{!v.columns }" 
                         keyField="Id"
                         draftValues= "{!v.UpdatedList}"
                         hideCheckboxColumn="true"/>
            <aura:set attribute="else">
                <div Style="text-align : center"> " There are no related contacts " </div>
            </aura:set>
        </aura:if>
    </lightning:card>
</aura:component>

--------------------------------------------------Cmp-------------------------------------------------------

- Now it's time to modify our JS controller of Component.

- Create a new Function. (In our example we are using the function name as SaveUpdatedContacts)

- Create a variable to store the draftValues(Updated values). ==( UpdatedList)

- After that create another variable to call the apex class method.  == (UpdateContacts)

- We have parameter for this method (UpdateContacts) which in that method which will take
our updated values. So set the parameter == (Conlist : UpdatedList)
And in callback recall the previous method again so that values will get refreshred :
($A.enqueueAction(component.get('c.myAction'))).

- This time in callback we are using response parameter. .setCallback(this,
function(response) so that we can recognize if the status is SUCCESS or Error and can
handle the errors while updating values.

Below is the updated snippet of JS.
--------------------------------------------------JS------------------------------------------------------

({
myAction : function(component, event, helper) 
    {
        component.set('v.columns', [
            {label: 'First Name', fieldName: 'FirstName', type: 'text' ,  editable: true},
            {label: 'Last Name', fieldName: 'LastName', type: 'text' ,  editable: true}
        ]);

        var ConList = component.get("c.getRelatedList");
        ConList.setParams
        ({
            recordId: component.get("v.recordId")
        });
        
        ConList.setCallback(this, function(data) 
                           {
                               component.set("v.ContactList", data.getReturnValue());
                           });
        $A.enqueueAction(ConList);
},
    
    SaveUpdatedContacts : function(component,event,helper) 
    {
        var UpdatedList = event.getParam('draftValues');        
        var UpdateContacts = component.get("c.updateRelatedList");
        
        UpdateContacts.setParams
        ({
            Conlist : UpdatedList
        });
        UpdateContacts.setCallback(this, function(response) 
                           {
                                var state = response.getState();
                                if (state === 'SUCCESS')
                                {
                                    $A.enqueueAction(component.get('c.myAction'));
  $A.get('e.force:refreshView').fire();
                               }
                                else{
                                   //error handling
                               }
                           });
        $A.enqueueAction(UpdateContacts);
    }
})
--------------------------------------------------JS------------------------------------------------------ 

The last thing we have to do is in ou datatable call this new function (“SaveUpdatedContacts”) using parameter “onsave”.
--------------------------------------------------Cmp-------------------------------------------------------

<aura:component controller = "AjinkyaTestLightningAccController" implements="flexipage:availableForRecordHome,force:hasRecordId" access="global" >
    <aura:attribute name="recordId" type="Id" />
    <aura:attribute name="ContactList" type="Contact[]"/>
    <aura:attribute name="columns" type="List"/>
    <aura:attribute name="UpdatedList" type="Contact[]"/>
    
    <aura:handler name="init" value="{!this}" action="{!c.myAction}" />
    <lightning:card iconName="standard:work_capacity_usage" title="Related Contacts">
        <aura:if isTrue="{!not(empty(v.ContactList))}">
            <lightning:datatable data="{!v.ContactList }" 
                         columns="{!v.columns }" 
                         keyField="Id"
                         draftValues= "{!v.UpdatedList}"
                         onsave="{!c.SaveUpdatedContacts}"
                         hideCheckboxColumn="true"/>
            <aura:set attribute="else">
                <div Style="text-align : center"> " There are no related contacts " </div>
            </aura:set>
        </aura:if>
    </lightning:card>
</aura:component>

--------------------------------------------------Cmp-------------------------------------------------------

Finally, we created our first Advanced Lightning Component.


Step 8: Final Output and testing

- Open any account page which has related contacts.
- Click on pencil button of any field you want to edit.


- Press “Enter” key on the keyboard. (Automatically Save and cancel button will appear).

- You can press “Cancel” and changes will be reverted. And you want the changes to be saved then click on “Save”.




After you click on Save Automatically page will get refreshed and you will get the final values:



SPECIAL THANKS TO YATISH PATIL FOR THIS BLOG CONTRIBUTION


WOHOOO !! YOU HAVE JUST CREATED ADVANCED LIGHTNING COMPONENT
If you like this salesforcekid learning platform please let me know in the Comment section...Also, Share with your salesforce folks wish you 
Happy learning ☁️⚡️ (Learn. Help. Share.)

Lightning Component To Display Contacts Related To Particular Account | Salesforce Lightning Lightning Component To Display Contacts Related To Particular Account | Salesforce Lightning Reviewed by on Rating: 5

1 comment:

  1. Thanks Yatish Patil, this step by step explanation is awesome. Love to see more like this. Again Thank you so much.

    ReplyDelete

HELP !! SHARE !! SUGGEST !!

Powered by Blogger.