Friday, May 14, 2021

Custom Multi-Select Picklist using LWC

Hello everyone,

In this blog we will see how to create a Generic Multi Select picklist which is better than standard Multi Select Picklist.


Lets create two Components here

1. passMultiSelectValues

2. multiPickListGenericComponent

Where passMultiSelectValues is Parent Component and multiPickListGenericComponent is Child Component.


PreRequisities :

1. Picklist field API Name

2. Picklist selected value to highlight the record.

3. Picklist Values.


Now create Child Component multiPickListGenericComponent and replace the HTML and JS replace the code given below respectively

HTML Code

<template>
  <div class="slds-box slds-col slds-scrollable" style="height: 7rem; padding: initial; background-color: white;">
    <ul role="menu" style="min-width: 100%; width: fit-content;">
      <template for:each={pickListValues} for:item="eachPickList" for:index="index">
        <div key={eachPickList}>
          <li onclick={handleSelection} data-value={eachPickList} data-selected={eachPickList} class="highlightRow">
            <div role="option">
              <span class="slds-media__figure" style="margin-right: 0.25rem;">
                <lightning-icon name="checkIcon" variant="inverse" icon-name="utility:check" size="xx-small"
                  class="addOrRemoveCheck slds-p-left_xx-small"></lightning-icon>
              </span>

              <span class="slds-media__body">
                <span class="slds-truncate" title={eachPickList}>{eachPickList}</span>
              </span>
            </div>
          </li>
        </div>
      </template>
    </ul>
  </div>
</template>

JS Code

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

export default class MultiPickListGenericComponent extends LightningElement {

    @api receivedPickListValues; //Picklist values sent by parent component
    @api selectedValues; //Values that has been selected
    @api fieldApiName; //API Name which makes component to be generic
    @track pickListValues = [];
    @track fieldName;

    selectedPickListValues = [];

    connectedCallback() {
        var i;
        let pickListValues = [];
        if (this.receivedPickListValues !== undefined) {
            this.receivedPickListValues.forEach(eachPicklistValue => {
                if(eachPicklistValue.hasOwnProperty('value')){
                    pickListValues.push(eachPicklistValue.value);
                    this.pickListValues = [...pickListValues];
                }
            });
        }
    }

    renderedCallback() {
        var i;
        if (this.receivedPickListValues !== null && this.receivedPickListValues !== undefined) {
            for (i = 0; i < this.receivedPickListValues.length; i++) {
                if(this.selectedValues !== undefined && this.selectedValues.includes(this.receivedPickListValues[i].value)) {
                    if (this.template.querySelectorAll('.highlightRow')[i].style !== undefined) {
                        this.template.querySelectorAll('.highlightRow')[i].style = 'background-color: rgba(9, 106, 189, 0.85); color : white;cursor: pointer;';
                        this.selectedPickListValues.push(this.receivedPickListValues[i].value);
                    }
                } else {
                    if (this.template.querySelectorAll('.highlightRow')[i].style !== undefined) {
                        this.template.querySelectorAll('.highlightRow')[i].style = 'background-color: white; cursor: pointer;';
                        this.template.querySelectorAll('.addOrRemoveCheck')[i].style = 'opacity :0;';
                    }
                }
            }
        }
    }

    handleSelection(event) {
        var item = event.currentTarget;
        var valueChoosen;
        var options;
        var i, j, k;
        let pickListValues = [];
        let selectedPickListValues1 = [];
        let found = false;
        if (item && item.dataset) {
            valueChoosen = item.dataset.value;
            pickListValues = this.selectedPickListValues;
            options = pickListValues;

            for (i = 0; i < options.length; i++) {
                if (options[i] === valueChoosen) {
                    found = true;
                    for (k = 0; k < this.receivedPickListValues.length; k++) {
                        if (this.receivedPickListValues[k].hasOwnProperty('value')) {
                            if (this.receivedPickListValues[k].value.indexOf(valueChoosen) > -1) {
                                this.template.querySelectorAll('.highlightRow')[k].style = 'background-color: white; cursor: pointer;';
                                this.template.querySelectorAll('.addOrRemoveCheck')[k].style = 'opacity :0;';
                            }
                        }
                    }
                    delete pickListValues[i];
                }
            }

            if (!found) {
                pickListValues.push(valueChoosen);
                for (i = 0; i < this.receivedPickListValues.length; i++) {
                    if (this.receivedPickListValues[i].hasOwnProperty('value')) {
                        if (this.receivedPickListValues[i].value.indexOf(valueChoosen) > -1) {
                            this.template.querySelectorAll('.highlightRow')[i].style = 'background-color: rgba(9, 106, 189, 0.85); color : white; cursor: pointer;';
                            this.template.querySelectorAll('.addOrRemoveCheck')[i].style = 'opacity :1;';
                        }
                    }
                }
            }
        }
        this.selectedPickListValues = pickListValues;
        
        const picklistEvent = new CustomEvent("multipicklistgenericevent", {
            detail: {fieldName: this.fieldApiName, value : this.selectedPickListValues}

        });

        this.dispatchEvent(picklistEvent);
    }

}


Now create a parent component and pass the values that are required to child component passMultiSelectValues

Now replace the code of passMultiSelectValues HTML and JS with the code given below

HTML code

<template>
    <template if:true={pickListValues}>
        <c-multi-pick-list-generic-component received-pick-list-values={pickListValues}
            onmultipicklistgenericevent={multipicklistgenericevent}
            selected-values={fieldValue} field-api-name="Company_Category__c">
        </c-multi-pick-list-generic-component>
    </template>
    <p> Selected Values:  {fieldValue}</p>
</template>


JS Code


import { LightningElement } from 'lwc';

export default class PassMultiSelectValues extends LightningElement {
    fieldValue = 'eCommerce,Retailer,Investor';

    get pickListValues(){
        return[
            {label: 'eCommerce', value: 'eCommerce'},
            {label: 'Health Care', value: 'Health Care'},
            {label: 'Education', value: 'Education'},
            {label: 'Retailer', value: 'Retailer'},
            {label: 'Manufacturer', value: 'Manufacturer'},
            {label: 'Food Service', value: 'Food Service'},
            {label: 'Investor', value: 'Investor'},
        ]
    }

    multipicklistgenericevent(event){
        this.fieldValue = event.detail.value;
    }
}






Tuesday, May 11, 2021

Integrating One Salesforce Org to Another Salesforce

In this post we will learn about how to integrate one salesforce org to another salesforce org using REST service. 

Let's suppose we have 2 different Salesforce Org's and call it Source(where we create record) and Destination(create a record here when a record is created in Source).


Now let's divide this process into 3 steps.


  1.  Creating Connected App
            In this step, let us create a connected app in destination org which is required to connect from Source.
  • Go to Setup and search for App Manager  and click on it

          
  • Click on New Connected App
  • Fill out Basic Information

  • Next Fill API (Enable OAuth Settings)

        For now Call Back URL is not required. So just give some dummy value.

  • Click on Save.
  • Once you save, it takes 2 minutes to host a connected application 
  • Consumer Key and Consumer Secret will be generated after 2 minutes.

    2.  Create a Trigger and Helper Class in Source Org

          Now let's jump into Source Org and create a connection between 2 Salesforce Org's.
          Click on the Gear Icon and Open Developer Console.
  • Click on File then New and Choose Apex Trigger and give your Trigger Class Name and select the object you want to Create a Trigger on.
  • In this example, we will write a trigger on Account and Name Trigger as accountTrigger and invoke it after the record is inserted.
  • Now create a field in Account Object in Source Org to store the record ID that has been created in Target Org and label it External Id.
  • Now we will create a helper class(sendAccountDetails) which receives data from Trigger Class(accountTrigger).
public class sendAccountDetails {
    private final String clientId = 'consumerKey'; //Consumer Key from Connected App created in Target Org
    private final String clientSecret = 'customerSecret'; //Consumer Secret from Connected App created in Target Org
    private final String username = 'test@gmail.com';
    private final String password = 'password&SecurityToken'; //Replace your Target Org Password and securityToken
    
    public class deserializeResponse{
        public String id;
        public String access_token;
    }
    
    public String ReturnAccessToken (sendAccountDetails account){
        String reqbody = 'grant_type=password&client_id='+clientId+'&client_secret='+clientSecret+'&username='+username+'&password='+password;
        Http h = new Http();
        HttpRequest req = new HttpRequest();
        req.setBody(reqbody);
        req.setMethod('POST');
        req.setEndpoint('https://targetOrgDomain.my.salesforce.com/services/oauth2/token');
        HttpResponse res = h.send(req);
        deserializeResponse resp1 = (deserializeResponse)JSON.deserialize(res.getbody(),deserializeResponse.class);
        return resp1.access_token;
    }
    
    @future(callout=true)
    public static void createAccount(String accName, String accId){
        sendAccountDetails account = new sendAccountDetails();
        String accessToken = account.ReturnAccessToken(account);
        System.debug('accessToken '+accessToken);
        if(accessToken != null){
            String endPoint = 'https://targetOrgDomain.my.salesforce.com/services/data/v32.0/sobjects/Account/';
            String jsonstr = '{"Name" : "' + accName + '"}';
            Http h2 = new Http();
            HttpRequest req1 = new HttpRequest();
            req1.setHeader('Authorization','Bearer ' + accessToken);
            req1.setHeader('Content-Type','application/json');
            req1.setHeader('accept','application/json');
            req1.setBody(jsonstr);
            req1.setMethod('POST');
            req1.setEndpoint(endPoint);
            HttpResponse res1 = h2.send(req1);
            deserializeResponse resp2 = (deserializeResponse)JSON.deserialize(res1.getbody(),deserializeResponse.class);
            Account a = [SELECT Id FROM Account WHERE Id = :accId];
            a.External_Id__c = resp2.id;
            update a;
        }
    }
}

  • Invoke the helper class created above from Trigger that was created on Account (accountTrigger)

trigger accountTrigger on Account (after insert) {
    for(Account a : Trigger.new){
        sendAccountDetails.createAccount(a.Name, a.Id);
    }
}
    3.  Creating a class in Target org and Exposing it as REST Service

  • Click on the Gear Icon and Open Developer Console.
  • Click on File then New and Choose Apex Class and give your Class Name as createAccountFromOtherSystem
  • Enter the code given below.
@RestResource(urlMapping='/v1/createAccountFromOtherSystem/*')
global with sharing class createAccountFromOtherSystem {
    @HttpPost
    global static String createAccount(String AccName)
    {
        Account a = new Account();
        a.Name = AccName;
        insert a;
        String returnResponse = JSON.serialize(a);
        return returnResponse;
    }
}


Saturday, April 17, 2021

Callback Methods in Lightning Web Components(LWC)

Callback methods are triggered at a specific phase of a component instance lifecycle.


Callback Methods in Lighting Web Components(lwc)

1. constructor()
2. connectedCallback()
3. disconnectedCallback()
4. render()
5. renderedCallback()
6. errorCallback(error, stack)


constructor()

  • This callback method called when the component created.
  • This method lifecycle flows from Parent to Child component.
  • You can access the host element with this.template.
  • we can’t access child elements in the component body because they don’t exist yet.

connectedCallback()

  • This callback method called when the element is inserted into a document.
  • This method lifecycle flows from Parent to Child Component.
  • we can’t access child elements in the component body because they don’t exist yet.
  • You can access the host element with this.template.

disconnectedCallback()

  • This callback method called when the element is removed from a document.
  • This method lifecycle flows from Parent to Child Component.

render()

  • This callback method used to conditionally rendering a template or importing a custom one, use render() to override standard rendering functionality. 
  • This function gets invoked after connectedCallback() and must return a valid HTML template.

renderedCallback()

  • This Method called after every render of the component.
  • This callback method is specific to Lightning Web Components, it isn’t from the HTML custom elements specification.
  • This method flows from child to parent.

 errorCallback(error, stack)

  • This method called when a descendant component throws an error in one of its callback.
  •  The error argument is a JavaScript native error object, and the stack argument is a string.
  •  This callback method is specific to Lightning Web Components, it isn’t from the HTML custom elements specification.

Apex Data Types and Variables

 Apex uses data types, variables, and related language constructs such as enums, constants, expressions, operators, and assignment statements.


1. Data Types

2. Primitive Data Types

3. Collections

4. Enums

5. Variables

6. Constants

7. Expressions and Operators

8. Assignment Statements

9. Rules of Conversion

Conditional Rendering Standard New Page and LWC

 Hello everyone, In this post, we will see how to conditionally render an LWC component & a Standard New Page from a ListView. In this e...