Friday, February 11, 2022

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 example, we will render an LWC & Standard Page based on Logged In User Profile.

Now let's jump into the steps.

  • Click on the Gear icon and navigate to Salesforce Setup.
  • Select the Object you want to customize the standard button.
  • Now click on the Buttons, Links & Actions.
  • Select New Button & Link.
  • Select the Display type as List Button (i.e Button which is for ListView) along with content Source as URL.
  • Now use the formula given below

{!
IF( $Profile.Name !='System Administrator',
URLFOR("/lightning/cmp/c__SampleLWC", null, null),
URLFOR($Action.Account.New))
}

  • In the above Formula, we are checking for the User Profile When he is not System Administrator. Then we are going to load an LWC component(SampleLwc).
  • If the User is not the administrator then we are going to display the normal standard Salesforce Page.


  • And that's it we are all set to go.

Thanks.


Friday, August 20, 2021

Check Mark animation component in salesforce

Hi,

In this post let's build the typical CHECKMARK we see in Swiggy, PhonePe etc using Lightning Web Components.


Let's use some animation in this post to grab some User attention.


Now let's deep dive into some features we are going to use in this post.


Now let's list down the properties that are used in this post.

HTML Properties:

Scalabe Vector Graphics (svg): This property is used to define the graphics in an XML format. Advantage of using this property is every attribute & element inside the svg tag can be animated.

Circle: This tag is used to create a circle. Few attributes used in creating a circle are cx & cy that defines the x & y co-ordinates of the circle, and r indicates the radius of the circle. stroke-width defines the width of the circle. Fill defines the color to be filled with.

Polyline: A polyline element is tag that is used inside an SVG tag which is used to create points and create a lines between all the points.


CSS Properties:

stroke-dasharray: This is an feature in CSS for creating dashes for an SVG tag. Increasing the number decreases the number of strokes and increasing the space between them.

stroke-dashoffset: This feature in CSS which defines where the dash of an Stroke will begin. 


HTML Code

 <template>  
   <svg>  
     <circle class="path circle" fill="none" stroke="#73AF55" stroke-width="6" stroke-miterlimit="10" cx="65.1"  
       cy="65.1" r="62.1" />  
     <polyline class="path check" fill="none" stroke="#73AF55" stroke-width="6" stroke-linecap="round"  
       stroke-miterlimit="10" points="100.2,40.2 51.5,88.8 29.8,67.5 "></polyline>  
   </svg>  
 </template>  


CSS Code

 .path {  
   stroke-dasharray: 1000;  
   stroke-dashoffset: 100;  
   animation: dash 5s linear alternate infinite;  
 }  
 @keyframes dash {  
   from {  
     stroke-dashoffset: 100;  
   }  
   to {  
     stroke-dashoffset: 2500;  
   }  
 }  




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...