Skip to main content

Build Custom Add to Favorites functionality in Salesforce



In this blog we will see how we can build a functionality to add different records from different Object as favorite records.

Use Case:

We have a requirement where we have a custom Page or an Application where we cannot see the standard Favorites button and we need to add the records to favorite list may be to visit it later. To meet this we can build our own button and an Object to meet the requirements to add the records as favorites.

Approach:

We need to configure Custom Object as below. 
Object :- Add Favourites
API Name :- Add_Favourites__c

FIELDS

Type

API Name

Favourites

Formula (Text)

HYPERLINK("/"& Object_RecordId__c , Object_Record_Name__c) 

Favourites__c

Object Name

Text

Object_Name__c

Object Record Name

Text

Object_Record_Name__c

Object RecordId

Text

Object_RecordId__c 



Now let us create a simple Lightning Component to display records from different objects. We will also add a button to it to add the record as Favorite.

This is the controller class to fetch the records as needed.Here we have created a simple Wrapper Class to store and return the records in Json format.

AddToFavouritesController.cls
 
public class AddToFavouritesController {
    public AddToFavouritesController() {

    }
    public class RecordWrapper {
        @AuraEnabled
        public  List<ContactcontactList   { getset; }
        @AuraEnabled
        public List<AccountaccountList    { getset; }
        @AuraEnabled
        public List<OpportunityoppList    { getset; }
    }

    @AuraEnabled
    public static String fetchRecords(){
        try {
           RecordWrapper  recWrap = new RecordWrapper();

           List<ContactcontactList = new List<Contact>();
           contactList = [Select id,Name,Phone from Contact Order By Name DESC LIMIT 10 ];
           recWrap.contactList = contactList;

           List<AccountaccountList = new List<Account>();
           accountList = [Select id,Name,Phone from Account Order By Name LIMIT 10];
           recWrap.accountList = accountList;

           List<OpportunityoppList = new List<Opportunity>();
           oppList = [Select id,Name from Opportunity Order By Name LIMIT 10];
           recWrap.oppList = oppList;

           System.debug('recWrap '+recWrap );
           return JSON.serialize(recWrap);

        } catch (Exception ex) {
         return JSON.serialize(ex);
        }
    }

    @AuraEnabled
    public static String addTofavourite(String recorIdValString recordName )
    {
        String objectName = '';
        String keyPrefix = recorIdVal.substring(0,3);
        forSchema.SObjectType obj : Schema.getGlobalDescribe().Values() ){
             String prefix = obj.getDescribe().getKeyPrefix();
              if(prefix == keyPrefix){
                        objectName = obj.getDescribe().getName();
                         break;
               }
        }
        List<Add_Favourites__caddfavRecordsnew List<Add_Favourites__c>();
        addfavRecords = [Select id,Object_RecordId__c FROM Add_Favourites__c WHERE Object_RecordId__c =:recorIdVal] ;
        Add_Favourites__c addfav = new Add_Favourites__c();
        List<Add_Favourites__caddfavlist = new List<Add_Favourites__c>();
        System.debug('addfavRecords '+addfavRecords);
      if (addfavRecords.isEmpty() ){   
        addfav.Object_Name__c = objectName ;
        addfav.Object_Record_Name__c = recordName ;
        addfav.Object_RecordId__c = recorIdVal;
        addfavlist.add(addfav);
        insert addfavlist;
        return addfavlist[0].id ;
      }
      else{
        delete addfavRecords ;
        return 'Record Removed from Favourites';
     }
    }
}


addToFavorites is a parent component to see the list of records.

addToFavourites.html
<template>
    <lightning-layout class="slds-m-right_medium">
        <lightning-layout-item class="slds-m-right_small" size="4">
            <div class="slds-p-around_small slds-page-header slds-page-header_object-home">
                <p class="slds-text-title_caps slds-line-height_reset">Contacts</p>
            </div>
            <div>
                <template for:each={contactList} for:item="item">
                    <div class="slds-p-around_small" key={item.Id}>
                        <c-record-tile record={item} onaddfav={addTofav}></c-record-tile>
                    </div>
                </template>
            </div>
        </lightning-layout-item>
        <lightning-layout-item class="slds-m-right_small" size="4">
            <div class="slds-p-around_small slds-page-header slds-page-header_object-home">
                <p class="slds-text-title_caps slds-line-height_reset">Accounts</p>
            </div>
            <div>
                <template for:each={accountList} for:item="item">
                    <div class="slds-p-around_small" key={item.Id}>
                        <c-record-tile record={item} onaddfav={addTofav}></c-record-tile>
                    </div>
                </template>
            </div>
        </lightning-layout-item>
        <lightning-layout-item class="slds-m-right_small" size="4">
            <div class="slds-p-around_small slds-page-header slds-page-header_object-home">
                <p class="slds-text-title_caps slds-line-height_reset">Opportunity</p>
            </div>
            <div>
                <template for:each={oppList} for:item="item">
                    <div class="slds-p-around_small" key={item.Id}>
                        <c-record-tile record={item} onaddfav={addTofav}></c-record-tile>
                    </div>
                </template>
            </div>
        </lightning-layout-item>
    </lightning-layout>
</template>

In the JS file as soon as this component loads we are fetching and displaying the records on UI. We are using Imperative method to fetch records.

addToFavourites.js
import { LightningElement } from 'lwc';
import fetchRecords from '@salesforce/apex/AddToFavouritesController.fetchRecords';
import addTofavourite from '@salesforce/apex/AddToFavouritesController.addTofavourite';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';

export default class AddToFavourites extends LightningElement {

    contactList;
    accountList;
    oppList;
    error;

    connectedCallback(){
        this.fetchRecords();
    } 

    fetchRecords() {
        fetchRecords()        
        .then(data => {
             const wrapper = JSON.parse(data);
             if(wrapper){
                 this.contactList = wrapper.contactList;
                 this.accountList = wrapper.accountList;
                 this.oppList = wrapper.oppList;
                 this.error = undefined ;
             }
        })
        .catch(error => {
            this.contactList = undefined;
            this.accountList = undefined;
            this.oppList = undefined;
            console.log(error);
        });
    }

    addTofav(event){   
        const recorIdVal = event.detail.recordId;
        const recordName = event.detail.recordName;
        
        addTofavourite({
            recorIdVal : recorIdVal,
            recordName : recordName,
        })
        .then(data => {
            console.log(' Add To Fav 'data);
            if(data == 'Record Removed from Favourites'){
                const toast = new ShowToastEvent({
                    'title' : 'Success',
                    "message" : recordName + ' Removed from Favourites',
                    "variant" : "Success"
                });
                this.dispatchEvent(toast);
            }else{
            const toast = new ShowToastEvent({
                'title' : 'Success',
                "message" : recordName +' Added To Favourites!',
                "variant" : "success"
            });
            this.dispatchEvent(toast);
        }
        })
        .catch(error => {
            console.log(error);
            const toast = new ShowToastEvent({
                'title' : 'Error!!',
                "message" : JSON.stringify(error),
                "variant" : "error"
            });
            this.dispatchEvent(toast);
        });

    }
}

addToFavourites.js-meta.xml
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>51.0</apiVersion>
    <isExposed>true</isExposed>
    <masterLabel>Add To Favorites</masterLabel>
    <targets>
        <target>lightning__AppPage</target>
        <target>lightning__HomePage</target>
        <target>lightning__RecordPage</target>
    </targets>
</LightningComponentBundle>

This is recordTile component. A child component to display each record. In this component we have a handleChange method to handle add functionality. We will fire an event and handle it out in parent component addToFavourites.html

recordTile.html
 <template>
    <template if:true={record}>
        <lightning-card variant="Narrow" title={record.Name} icon-name="standard:story">
            <div slot="actions">
                    <div>
                        <div title="Add to Favorites" onclick={handleChange} class={buttonColor}
                            style="height: 20px;width: 20px;border: 1px solid black;margin-right : 5px; "></div>
                        <span class="slds-assistive-text">Add to Favorites</span>
                    </div>
            </div>
            <div slot="footer">
                <lightning-button variant="base" label="Details" title="View Details" onclick={handleClick} class="slds-m-left_x-small">
                </lightning-button>
            </div>
            <p class="slds-p-horizontal_small"> 
                {record.Name}
            </p>
        </lightning-card>
    </template>
    <template if:false={record}>
        No Records available to show here.
    </template>
</template>

recordTile.js
import { LightningElement ,apifrom 'lwc';

export default class RecordTile extends LightningElement {
    @api record;
    changeStyle = false;
    get buttonColor(){
        return this.changeStyle ? 'bgcolor''btcolor';
    }
    handleChange(){
        this.changeStyle = !this.changeStyle;
            const addToFav = new CustomEvent(
                'addfav',
                {
                    detail : {
                       recordId : this.record.Id,
                       recordName : this.record.Name,
                    }
                }
            );
            this.dispatchEvent(addToFav);
    }
}

recordTile.css
.bgcolor
{
    background-colorred;
    color:red;
}

.btcolor{
    background-colorwhite;
    color:white;
}

recordTile.js-meta.xml

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>51.0</apiVersion>
    <isExposed>false</isExposed>
</LightningComponentBundle>

Actual Output:



We can also add a new DataTable Component on the same page see the List of Favorites records at the same time or as per the different use case.

Thanks for reading . :)
#HappyCoding

Comments

Popular posts from this blog

How to create custom polymorphic field using LWC ?

How to create custom polymorphic field using LWC ? In this blog we will see how we can make polymorphic lookup field using LWC. What is Polymorphic field? A polymorphic field is one where related object might be one of the several different types of objects. There can be a use case where a customer wants to connect one object with multiple objects- i.e, relationships between objects or relate a child object to multiple parents's ojects. For example, in task Object we have three such polymorphic fields. The WhoId(Name) relationship of Task can be with Contact or a Lead. Assigned To field can be a User or a Queue. Similarly, a WhatId(Related To) relationship field of Task can be with many other objects like Accounts, Opportunities etc. In Salesforce, currently we do not have any OOTB option or may be we can say we do not have a datatype for polymorphic field which we can create but if required we can create a custom component to facilitate the same functionality. So let's get

How to update Field Level Security in bulk ?

Assign Field Level Security(FLS) in Salesforce Demo:- In this blog we will see the easy way to update Field Level Security(FLS) for Permission sets/Profiles in bulk. I have created a tool to make the Admins job a little easier. Before jumping to tool let us see the different standard approach we follow to update FLS in Salesforce.                     As an admin we usually update FLS from salesforce setup/UI. If we are working on a new Application with many Permission sets and Objects with 100+ fields it can be very time consuming task. Using this tool we can assign FLS in just few mins. Let us take an example. Suppose we have a new application and we have created 20 Permission sets and 8 Profiles . Now there are 10 Objects in all and in each object we have 15 fields for which we need to update FLS for above Permission sets and Profiles. Let us first see the different approach to assign FLS in Salesforce. We have two ways in which we can update FLS for a particular field.  1 .To upd

How to use Hyperlink in Custom Toast Notification message using LWC

  Use Hyperlink in Custom Toast Notification message using LWC   We all know that a component can send a toast notification that pops up to alert users of a success, error, or warning. A toast can also simply provide information to the user. But what if we need a hyperlink on the message to navigate to the records on the message body. Yes, we can put Links as well on the message body as we can see in Standard Notification Toasts. This is very simple just we need to remember few things. We should know how to use Navigation Services by using NavigationMixin.GenerateUrl method. Let us see the functionality in this blog. To display a toast notification in Lightning Experience or Experience Builder sites we import ShowToastEvent from the lightning/platformShowToastEvent module. We use this ShowToastEvent to provide feedback to a user following an action, such as after a record is created. Now in this blog we will see how to add hyperlink in the message of the Show Toast event and navig