Wednesday, 5 August 2020

Custom Chevron component using lightning web component(LWC)

Use case :

we can use sales force standard "Path" component to build chevron on record page showed as below.


                                                                                                                                                                           
But there is an problem 😟   with this approach . As you can see once stage is completed it shows the chevron with right check mark and not displaying the status  and also i don't want user to manually change the status by using "Mark Stage Completed"  button on  right which should not be available to end user.

To achieve this we have to use custom LWC component. Let's get into the code..!

Code:

Chevron.js

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
/**
 * @File Name          : chevron.js
 * @Description        : 
 * @Author             : Swarup Satpti
 * @Group              : 
 * @Last Modified By   : Swarup satpati
 * @Last Modified On   : 8/3/2020, 5:30:00 PM
**/
import { LightningElement, api, wire, track } from 'lwc';
import { getObjectInfo, getPicklistValues} from 'lightning/uiObjectInfoApi';
import { getFieldValue } from 'lightning/uiRecordApi';
import {getRecord} from 'lightning/uiRecordApi';

export default class Chevron extends LightningElement {
    @api objectName = 'Opportunity';
    @api fieldName = 'StageName';
    /*component with a recordId property is used on a Lightning record page, 
    the page sets the property to the ID of the current record.*/
    @api recordId; 

    @track picklistvalues;
    @track record;
    @track error;
    @track chevrondata=[];
    @track itemList;
    @track fieldValue;
    @track fieldArray;

    recordtypeId;
    index=0;
    isFound=false;
    isfoundindex=0;
    fieldapi;


  connectedCallback(){
    this.fieldArray = [`${this.objectName}.${this.fieldName}`,`${this.objectName}.RecordTypeId`];
    this.fieldapi=`${this.objectName}.${this.fieldName}` ;
    }
    
    /*Use this wire adapter to get a record’s data : 
       Recordtype ID and value of status field pass through API
    */
    @wire(getRecord, { recordId: '$recordId', fields:'$fieldArray'})
    wiredAccount({ error, data }) {
        if (data) {
            this.record = data;
            console.log(JSON.stringify(data));
            this.fieldvalue=getFieldValue(data,`${this.objectName}.${this.fieldName}`);
            this.recordtypeId=this.record.fields.RecordTypeId.value;
            this.error = undefined;
            console.log('selected value..'+this.fieldvalue);
        } else if (error) {
            console.log('error..');

            this.error = error;
            this.record = undefined;
        }
    }

   /*Use this wire adapter to get the picklist values for a specified field.*/

    @wire(getPicklistValues, {
        fieldApiName: '$fieldapi',
        recordTypeId: '$recordtypeId'
    })
    fetchRecordTypeInfo({ data, error }) {
        if (data) {
            console.log('data..'+JSON.stringify(data.values));

           // this.picklistvalues = data.picklistFieldValues.Status_EI__c.values;
              this.picklistvalues = data.values ;

            this.picklistvalues.forEach(item=>{
               // console.log('rec..'+item.value);
                let classType;
                if(this.fieldvalue==item.value){
                    classType = 'slds-path__item slds-is-current slds-is-active';
                    this.isFound=true;
                    this.isfoundindex=this.index;
                }
                else{ 
                   classType='slds-path__item slds-is-incomplete';
                   this.index ++; 
                }
                this.chevrondata.push({
                 stages :item,
                 classType:classType
                });


            });
            if(this.isFound){
                for(let i=0;i<this.isfoundindex;i++){
                   this.chevrondata[i].classType='slds-path__item slds-is-complete';
                }

            }
           
             console.log('chevron data..'+JSON.stringify(this.chevrondata));
           
            //console.log(JSON.stringify(this.picklistvalues));
        }
        else if (error) {
            console.log(" Error  ---> " + JSON.stringify(error));
        }
    }
    
}

chevron.html

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<template>
    <div class="slds-path">
        <div class="slds-grid slds-path__track">
          <div class="slds-grid slds-path__scroller-container">
            <div class="slds-path__scroller" role="application">
              <div class="slds-path__scroller_inner">
                <ul class="slds-path__nav" role="listbox" aria-orientation="horizontal">
                  <template for:each={chevrondata} for:item="stageIs" for:index="index">
                    <li key={stageIs} class={stageIs.classType} style="margin-left: 0em !important;" role="presentation">
                        <a aria-selected="flase" class="slds-path__link" href="javascript:void(0);"  role="option" tabindex="0">
                          <span class="slds-path__stage">
                            <!--<svg class="slds-icon slds-icon_x-small" aria-hidden="true">
                              <use xlink:href="/assets/icons/utility-sprite/svg/symbols.svg#check"></use>
                            </svg>
                          -->
                           {stageIs.stages.label}
                            <span class="slds-assistive-text">{stageIs.stages.label}</span>
                          </span>
                          <span class="slds-path__title">{stageIs.stages.label}</span>
                        </a>
                    </li>
                  </template>
                </ul>
            </div>
          </div>
        </div>
        </div>
    </div>
</template>

Metadata

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>48.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
        <target>lightning__AppPage</target>
        <target>lightning__RecordPage</target>
        <target>lightning__HomePage</target>
        <target>lightningCommunity__Page</target>
        <target>lightning__Tab</target>
    </targets>
</LightningComponentBundle>


Code Explanation:

Within js controller we are using two wire adapters.

getRecord() : by using this method we are  retrieving the present stage value and record type Id for  the current record

getPicklistValues() : dynamically fetching pick list values for the given field Api 
and recordtype.

Have created custom property called 'ClassType' and 'stage' to display 
the chevron in html.

Main tricky part is to set the claastype conditionally based on the current stage.

'slds-path__item slds-is-current slds-is-active' :   for current Stage
'slds-path__item slds-is-incomplete': for all incomplete stages
'slds-path__item slds-is-complete' : for all completed stages


Hope you get it right !

Output :



5 comments:

  1. Hi Swarup,

    How do I achieve this using AURA as I am not familiar with LWC and having urgent requirement by client.
    I tried using lightning:progressIndicator lightning;ProgressStep, but completed stage gets a tick mark and label is hidden.. I dont want tick mark and want label to be visible

    ReplyDelete
  2. Hi Swarup,

    How do I handle onclick event on the selected path element

    ReplyDelete
  3. how to change chevron in red color when the opportunity become close loss

    ReplyDelete
  4. Great and that i have a tremendous give: Where Do You Get The Money To Renovate A House house renovation contractors

    ReplyDelete

Getting started with Heroku

I am familiar with the heroku for quite long time, have seen lots of people are interested with it but not sure from where its need to Start...