Saturday, September 24, 2022

How to connect to your salesforce org with postman?

 What is Postman?

Postman is an API platform that is used for building and testing API's. This is very special tool for salesforce developer to test the api request and response.

Now, let us setup salesforce first.

Firstly we need to create a connected app in salesforce.

What is "Connected App" in salesforce?

For an external application that needs to authenticate with Salesforce we need to create a connected app so as to inform Salesforce about the new authentication entry point. Connected app uses standard OAuth 2.0 protocol to authenticate.

Go to setup > click app manager > "New Connected App" button.

Enter "Connected App Name", "API Name" and "Contact Email".

Click "Enable OAuth Settings".

Enter "Callback URL".

Select "Selected OAuth Scopes" as Manage user data via APIs (api)

Callback URL:

A callback URL is the URL that is invoked after OAuth authorization for the consumer (connected app). In some contexts, the URL must be a real URL that the client’s web browser is redirected to. In others, the URL isn’t actually used, but the value between your client app and the server (the connected app definition) must be the same. 

In our case as we are using postman the callback URL will not impact us and we can write anything here, in our case we will use https://www.salesforce.com.

How to connect to your salesforce org with postman?


Now, click on the "Consumer Key and Secret" --> "Manage Consumer Details" button.

Note down the "Consumer Key" and "Consumer Secret".

How to connect to your salesforce org with postman?


Now, let us setup postman.

Once you download the postman app, install it.

We are using "username password flow" to connect to salesforce org.

First step is to get access token. 

If we are using production org we need to call the below URL to get access token with POST method.

https://login.salesforce.com/services/oauth2/token

If we are using sandbox org we need to call the below URL to get access token with POST method.

https://test.salesforce.com/services/oauth2/token

How to connect to your salesforce org with postman?

grant_type       --> Must be the keyword "password" for this authentication flow.

client_id        --> The Consumer Key from the connected app definition.

client_secret    --> The Consumer Secret from the connected app definition.

username         --> End-user’s username.

password         --> End-user password +  Security token

As an example, if password is YYYYY and security token is ZZZZZ then the value that will be

passed under password is YYYYYZZZZZ .

Once you click the "Send" button you will receive the response as shown below.

{
    "access_token""",
    "instance_url""https://myknowndomain-dev-ed.my.salesforce.com",
    "id""",
    "token_type""Bearer",
    "issued_at""",
    "signature"""
}

Now, copy the "access_token" and "instance_url" as this will be required to make further api calls.

Now, let us try to do a GET call to get the account information.

In "Headers" block specify the Authorization as "Bearer accesstokenValue".

Ensure to provide space between Bearer and access token value.

The part of the URL "https://myknowndomain-dev-ed.lightning.force.com" shown in below image on which we are doing GET call is nothing but "instance_url" obtained during POST call.

The complete URL looks like below,

https://myknowndomain-dev-ed.lightning.force.com/services/data/v50.0/query/?q=SELECT+Name,Description+From+Account

How to connect to your salesforce org with postman?


In this way we have successfully integrated postman and salesforce.

Sunday, September 18, 2022

How to create a record using lightning-record-form in LWC?

 We use the lightning-record-form to create forms to add, view, or update a record.

It is easier to build forms using lightning-record-form as compared to lightning-record-view-form and lightning-record-edit-form however lightning-record-form is less customizable. To customize the form layout or to provide custom rendering of data use lightning-record-view-form(view a record) and lightning-record-edit-form(add or update).  lightning-record-form implements Lightning Data Service and hence it doesn't require additional Apex controllers to create or edit record and it also takes care of field-level security and sharing, so users see only the data that they have access to. 

Sample syntax:

<lightning-record-form

    record-id="IdOfParticularRecord"

    object-api-name="Account"

    layout-type="Compact"

    columns="1"

    mode="readonly">

</lightning-record-form>


Important points to note:

  • The object-api-name attribute is always required, and the record-id is required only when you’re editing or viewing a record.

  • We use fields attribute to pass record field as an array of string. The fields are displayed in the order we list them.

  • We use layoutType attribute to specify a Full or Compact layout. If we use this then the field available on the layout are displayed in the form.
  • To specify the field order, we use fields without the layout-type attribute. It is not recommended to use the fields attribute with the layout-type attribute as the display order of the fields can vary.
  •  layout-type="Full"- The full layout corresponds to the fields on the record detail page.              
  •  layout-type="Compact" - The compact layout corresponds to the fields on the highlights panel at the top of the record. 
  • Not all standard object are supported.
           For ex: Event and task are not supported. External objects are also not supported.

  •       Modes:

         The value for mode can be one of the following mentioned below and it determines the user             interaction allowed for the form.

        1) edit - Creates an editable form to add a record or update an existing one.

        2) view - Creates a form to display a record that the user can also edit.

        3) readonly - Creates a form to display a record. In this case the form doesn't display any                      buttons.

If you do not specify the mode attribute, its default value is edit but if you specify the record-id
the default value of mode is view.

Let us create a lightning web component using lightning-record-form to create a record which we will place on Account detail page.

recordDetailCheckComp.html

<template>

    <lightning-card title="Lightning Record Form to create a record">

    <lightning-record-form object-api-name="Account"

         columns="2" mode="edit" layout-type="Full" onsubmit={handleSubmit}>

    </lightning-record-form>

    </lightning-card>

</template>


recordDetailCheckComp.js

import { LightningElement, api } from 'lwc';

import {ShowToastEvent} from 'lightning/platformShowToastEvent';

export default class LightningRecordFormEditExampleLWC extends LightningElement {

    @api recordId;

    handleSubmit(event){

        const evt = new ShowToastEvent({

            title: 'Success Message',

            message: 'Record Created successfully ',

            variant: 'success',

            mode:'dismissible'

        });

        this.dispatchEvent(evt);

    }

}


recordDetailCheckComp.js-meta.xml

<?xml version="1.0" encoding="UTF-8"?>

<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">

    <apiVersion>50.0</apiVersion>

    <isExposed>true</isExposed>

    <targets>

        <target>lightning__RecordPage</target>

    </targets>

</LightningComponentBundle>


OUTPUT:

 
How to create a record using lightning-record-form in LWC?

Saturday, September 17, 2022

How to edit a record using lightning-record-form in LWC?

 We use the lightning-record-form to create forms to add, view, or update a record.

It is easier to build forms using lightning-record-form as compared to lightning-record-view-form and lightning-record-edit-form however lightning-record-form is less customizable. To customize the form layout or to provide custom rendering of data use lightning-record-view-form(view a record) and lightning-record-edit-form(add or update).  lightning-record-form implements Lightning Data Service and hence it doesn't require additional Apex controllers to create or edit record and it also takes care of field-level security and sharing, so users see only the data that they have access to. 

Sample syntax:

<lightning-record-form

    record-id="IdOfParticularRecord"

    object-api-name="Account"

    layout-type="Compact"

    columns="1"

    mode="readonly">

</lightning-record-form>


Important points to note:

  • The object-api-name attribute is always required, and the record-id is required only when you’re editing or viewing a record.

  • We use fields attribute to pass record field as an array of string. The fields are displayed in the order we list them.

  • We use layoutType attribute to specify a Full or Compact layout. If we use this then the field available on the layout are displayed in the form.
  • To specify the field order, we use fields without the layout-type attribute. It is not recommended to use the fields attribute with the layout-type attribute as the display order of the fields can vary.
  •  layout-type="Full"- The full layout corresponds to the fields on the record detail page.              
  •  layout-type="Compact" - The compact layout corresponds to the fields on the highlights panel at the top of the record. 
  • Not all standard object are supported.
           For ex: Event and task are not supported. External objects are also not supported.

  •       Modes:

         The value for mode can be one of the following mentioned below and it determines the user             interaction allowed for the form.

        1) edit - Creates an editable form to add a record or update an existing one.

        2) view - Creates a form to display a record that the user can also edit.

        3) readonly - Creates a form to display a record. In this case the form doesn't display any                      buttons.

If you do not specify the mode attribute, its default value is edit but if you specify the record-id
the default value of mode is view.

Let us create a lightning web component using lightning-record-form to edit a record which we will place on Account detail page.

recordDetailCheckComp.html

<template>

    <lightning-card>

    <lightning-record-form record-id={recordId} object-api-name="Account"

        fields={fields} columns="2" mode="edit" onsubmit={handleSubmit}>

    </lightning-record-form>

    </lightning-card>

</template>


recordDetailCheckComp.js

import { LightningElement, api } from 'lwc';

import Account_Name from '@salesforce/schema/Account.Name';

import Account_Description from '@salesforce/schema/Account.Description';

import Account_Industry from '@salesforce/schema/Account.Industry';

import {ShowToastEvent} from 'lightning/platformShowToastEvent';

export default class LightningRecordFormEditExampleLWC extends LightningElement {

    @api recordId;

    fields = [Account_Name, Account_Description, Account_Industry];

    handleSubmit(event){

        const evt = new ShowToastEvent({

            title: 'Success Message',

            message: 'Record Updated successfully ',

            variant: 'success',

            mode:'dismissible'

        });

        this.dispatchEvent(evt);

    }

}


recordDetailCheckComp.js-meta.xml

<?xml version="1.0" encoding="UTF-8"?>

<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">

    <apiVersion>50.0</apiVersion>

    <isExposed>true</isExposed>

    <targets>

        <target>lightning__RecordPage</target>

    </targets>

</LightningComponentBundle>


OUTPUT:

How to edit a record using lightning-record-form in LWC?

Saturday, September 10, 2022

Trigger Handler Framework Salesforce

 Apex triggers are used to manage records in Salesforce. It enables us to perform operations before or after the event is completed. In the “before event” we generally perform validations to prevent wrong entry into the database. In the “after event” we perform operations such as creating or updating a related record. The trigger is a very powerful mechanism using which we can do operations such as executing SOQL, executing DML operations, calling apex class methods.


A trigger is Apex code that executes before or after the following types of operations:

insert
update
delete
merge
upsert
undelete

New developer generally make mistake of writing multiple trigger on same object and later realize that they cannot control order of execution.

The best practice is to write 1 trigger per object.

Let's now look at how "Trigger Handler Framework" help us in making our job easy.

Trigger Handler Interface:

An interface is a class where we create method signatures but body of the method is not
defined.

If we want to use an interface in another class, the other class need to implement it by providing
the body for all of the methods contained in the interface.


We had already learn about the availability of TRIGGER.NEW, TRIGGER.OLD, TRIGGER.NEWMAP, TRIGGER.OLDMAP with different events  in article shown below
and accordingly we are creating the method signature in below interface.







public interface TriggerHandler {

    void beforeInsert(List<SObject> newRecordsList);

    void beforeUpdate(List<SObject> oldRecordsList, List<SObject> newRecordsList, Map<ID, SObject> oldRecordsMap, Map<ID, SObject> newRecordsMap);

    void beforeDelete(List<SObject> oldRecordsList, Map<ID, SObject> oldRecordsMap);

    void afterDelete(List<SObject> oldRecordsList, Map<ID, SObject> oldRecordsMap);

    void afterInsert(List<SObject> newRecordsList, Map<ID, SObject> newRecordsMap);

    void afterUpdate(List<SObject> oldRecordsList, List<SObject> newRecordsList, Map<ID, SObject> oldRecordsMap, Map<ID, SObject> newRecordsMap);

    void afterUndelete(List<SObject> newRecordsList, Map<ID, SObject> newRecordsMap);

}



The handler class will implement the above interface.


Trigger Handler Class:

public without sharing class OpportunityTriggerHandler implements TriggerHandler {

   OpportunityTriggerHelper helperClass = new OpportunityTriggerHelper();

    public void beforeInsert(List<Opportunity> newOppList) {

        helperClass.methodToHandleBeforeInsert();

    }

    public void beforeUpdate(List<Opportunity> oldOppList, List<Opportunity> newOppList, Map<ID, SObject> oldOppMap, Map<ID, SObject> newOppMap) {

         helperClass.methodToHandleBeforeUpdate();

    }

    public void beforeDelete(List<Opportunity> oldOppList, Map<ID, SObject> oldOppMap) {

        helperClass.methodToHandleBeforeDelete();

    }

    public void afterDelete(List<Opportunity> oldOppList, Map<ID, SObject> oldOppMap) {

        helperClass.methodToHandleAfterDelete();

    }

    public void afterInsert(List<Opportunity> newOppList, Map<ID, SObject> newOppMap) {

        helperClass.methodToHandleAfterInsert();

    }

    public void afterUpdate(List<Opportunity> oldOppList, List<Opportunity> newOppList, Map<ID, SObject> oldOppMap, Map<ID, SObject> newOppMap) {

      helperClass.methodToHandleAfterUpdate();

    }

    public void afterUndelete(List<Opportunity> newOppList, Map<ID, SObject> newOppMap) {

      helperClass.methodToHandleAfterUndelete();

    }

}



Now, Let's define our helper class.

Trigger Helper Class:

public without sharing class OpportunityTriggerHelper {

  

    public void methodToHandleBeforeInsert() {

        System.debug('Inside methodToHandleBeforeInsert');

    }

    public void methodToHandleBeforeUpdate() {

        System.debug('Inside methodToHandleBeforeUpdate');

    }

    public void methodToHandleBeforeDelete() {

        System.debug('Inside methodToHandleBeforeDelete');

    }

    public void methodToHandleAfterDelete() {

        System.debug('Inside methodToHandleAfterDelete');

    }

    public void methodToHandleAfterInsert() {

        System.debug('Inside methodToHandleAfterInsert');

    }

    public void methodToHandleAfterUpdate() {

        System.debug('Inside methodToHandleAfterUpdate');

    }

    public void methodToHandleAfterUndelete() {

        System.debug('Inside methodToHandleAfterUndelete');

    }

   

}


Now, Let's define our trigger on opportunity object.

Note:

operationType:

Returns an enum of type System.TriggerOperation corresponding to the current operation.

Possible values of the System.TriggerOperation enum are: BEFORE_INSERT, BEFORE_UPDATE, BEFORE_DELETE,AFTER_INSERT, AFTER_UPDATE, AFTER_DELETE, and AFTER_UNDELETE. 



trigger OpportunityTrigger on Opportunity(before insert, before update, before delete, after delete, after insert, after update, after undelete) {

           OpportunityTriggerHandler handler = new OpportunityTriggerHandler();

           switch on Trigger.operationType {

            when BEFORE_INSERT {

                handler.beforeInsert(Trigger.new);

            }

            when BEFORE_UPDATE {

                handler.beforeUpdate(Trigger.old, Trigger.new, Trigger.oldMap, Trigger.newMap);

            }

            when BEFORE_DELETE {

                handler.beforeDelete(Trigger.old, Trigger.oldMap);

            }

            when AFTER_DELETE {

                handler.afterDelete(Trigger.old, Trigger.oldMap);

            }

            when AFTER_INSERT {

                handler.afterInsert(Trigger.new, Trigger.newMap);

            }

            when AFTER_UPDATE {

                handler.afterUpdate(Trigger.old, Trigger.new, Trigger.oldMap, Trigger.newMap);

            }

            when AFTER_UNDELETE {

                handler.afterUndelete(Trigger.new, Trigger.newMap);

            }

        }

}



Let's test our code now.

Open the developer console.

A) Create a opportunity record as shown below.

Trigger Handler Framework Salesforce


Now, Check the logs under developer console.

Trigger Handler Framework Salesforce

Now, let's update the opportunity record.

Trigger Handler Framework Salesforce

Friday, September 9, 2022

How to edit a row or a record using row level action in LWC?

  In this blog post we will learn "How to edit a row or a record using row level action in LWC?".


testLWCTableExample.html

<template>

 

    <h1>Account Data Table With Edit Action and Refresh Apex</h1>

 

<template if:true={accList}>

 

    <lightning-datatable

 

        key-field="id"

 

        data={accList}

 

        columns={columns}

 

        onrowaction={handleRowAction}

 

        >

 

    </lightning-datatable>

 

      

 

</template>

 

<template if:true={error}>

 

 Some error occured.

 

</template>

 

<template if:true={isShowModal}>

 

    <section role="dialog" tabindex="-1" aria-labelledby="modal-heading-01" aria-modal="true" aria-describedby="modal-content-id-1" class="slds-modal slds-fade-in-open">

       <div class="slds-modal__container">

 

        <!-- Modal/Popup header-->

          <header class="slds-modal__header">

             <button class="slds-button slds-button_icon slds-modal__close slds-button_icon-inverse" title="Close" onclick={hideModalBox}>

                <lightning-icon icon-name="utility:close"

                   alternative-text="close"

                   variant="inverse"

                   size="small" ></lightning-icon>

                <span class="slds-assistive-text">Close</span>

             </button>

             <h2 id="modal-heading-01" class="slds-text-heading_medium slds-hyphenate">Edit Account</h2>

          </header>

     

          <!-- Modal/Popup body -->

 

          <div class="slds-modal__content slds-p-around_medium" id="modal-content-id-1">

                <template if:true={isEditRecord}>

                    <lightning-record-edit-form record-id={recordIdToEdit} object-api-name="Account" onsubmit={handleSubmit} onsuccess={handleSuccess}>

 

                        <lightning-output-field field-name="Name"></lightning-output-field>

               

                        <lightning-input-field field-name="Description"></lightning-input-field>

               

                        <lightning-input-field field-name="Industry"></lightning-input-field>

               

                        <lightning-button

               

                            class="slds-m-top_small"

               

                            variant="brand"

               

                            type="submit"

               

                            name="update"

               

                            label="Update">

               

                        </lightning-button>

               

                </lightning-record-edit-form>

                </template>

          </div>

 

          <!-- Modal/Popup footer-->

          <footer class="slds-modal__footer">

            <footer class="slds-modal__footer">

                <button class="slds-button slds-button_neutral" onclick={hideModalBox}>Cancel</button>

             </footer>

          </footer>

      

       </div>

    </section>

    <div class="slds-backdrop slds-backdrop_open"></div>

 </template>

 <!-- Modal/Popup end here -->

 

 </template>

Note:

1) We need to import interface refreshApex for refreshing data table once a row is deleted.
2) Row level actions are added in data table using type as action as shown below with typeAttributes.


{

    type: 'action',

    typeAttributes: { rowActions: actions },

}

3) The required actions are defines as below,


const actions = [

    { label: 'Show details', name: 'show_details' },

    { label: 'Delete', name: 'delete' },

    { label: 'View Record', name: 'view' },

    { label: 'Edit', name: 'Edit' },

];


testLWCTableExample.js

import { LightningElement, track, wire } from 'lwc';

 

import getAccountList from '@salesforce/apex/AccountDataController.getAccountList';

import { updateRecord } from 'lightning/uiRecordApi';

import Account_Name from '@salesforce/schema/Account.Name';

import Account_Id from '@salesforce/schema/Account.Id';

import Account_Industry from '@salesforce/schema/Account.Industry';

import Account_Description from '@salesforce/schema/Account.Description';

import {ShowToastEvent} from 'lightning/platformShowToastEvent';

 

import {refreshApex} from '@salesforce/apex';

 

const actions = [

 

    { label: 'Edit', name: 'Edit' },

 

];

 

const columns=[

{label: 'Account Name', fieldName: 'Name'},

{label: 'Account Industry', fieldName: 'Industry',editable: true},

{label: 'Account Description', fieldName: 'Description',editable: true},

{label: 'Parent Account Name', fieldName: 'Parent_Account_Name'},

{

    type: 'action',

    typeAttributes: { rowActions: actions },

},

];

 

export default class TestLWCTableExample extends LightningElement {

 

    @track error;

 

    @track columns = columns;

 

    @track actions = actions;

 

    @track accList;

    @track isShowModal = false;

    @track isEditRecord = false;

    @track recordIdToEdit;

 

 

    @track showLoadingSpinner = false;

    draftValues = [];

 

    refreshTable;

 

    @wire (getAccountList) accList(result)

 

    {

 

        this.refreshTable = result;

 

        if(result.data)

 

        {

            let accParsedData=JSON.parse(JSON.stringify(result.data));

            let baseUrlOfOrg= 'https://'+location.host+'/';

            accParsedData.forEach(acc => {

                if(acc.ParentId){

                acc.Parent_Account_Name=acc.Parent.Name;

               // acc.Account_URL=baseUrlOfOrg+acc.Id;

                }

            });

          //  this.refreshTable = accParsedData;

            this.accList = accParsedData;

        }

        else if(result.error)

        {

            this.error = result.error;

        }

    }

 

    handleRowAction(event) {

 

        const actionName = event.detail.action.name;

 

        const row = event.detail.row;

 

        switch (actionName) {

            case 'Edit':

                this.editRecord(row.Id);

                break;

            default:

        }

 

    }

 

    editRecord(recordIdDetail) {

        this.isShowModal = true;

        this.isEditRecord = true;

        this.recordIdToEdit=recordIdDetail;

 

    }

    hideModalBox() { 

        this.isShowModal = false;

    }

    handleSubmit(event){

     

        this.isShowModal = false;

        const evt = new ShowToastEvent({

            title: 'Success Message',

            message: 'Record Updated successfully ',

            variant: 'success',

            mode:'dismissible'

        });

        this.dispatchEvent(evt);

       

    }

    handleSuccess(event){

        return refreshApex(this.refreshTable); 

    }

 

}


testLWCTableExample.js-meta.xml

<?xml version="1.0" encoding="UTF-8"?>

<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">

    <apiVersion>55.0</apiVersion>

    <isExposed>true</isExposed>

    <targets>

        <target>lightning__AppPage</target>

        <target>lightning__RecordPage</target>

        <target>lightning__HomePage</target>

    </targets>

</LightningComponentBundle>


Now, Let add the component to Account Record detail page to see the output.

Output:

How to edit a row or a record using row level action in LWC?


Now, Click edit on row level action.

How to edit a row or a record using row level action in LWC?

Let's update description to "Test Description-12345678910" and click update button.

How to edit a row or a record using row level action in LWC?