Friday, June 4, 2021

Lookup LWC



It's always taken a challenge by the Salesforce developers whenever a lookup component is needed to be added inside a component.

I have built a custom, easy solution on LWC that can be used anywhere.

LookupCMP.html

<template>
    <div class="slds-m-bottom_small slds-m-top_x-large">
        <lightning-card>
            <div class="slds-align_absolute-center">
                <lightning-layout>
                    <lightning-layout-item class="slds-p-left_small">
                        <lightning-icon icon-name="utility:salesforce1">
                        </lightning-icon>
                    </lightning-layout-item>
                    <lightning-layout-item>
                        <p class="slds-p-horizontal_small">
                            <b>Lookup to Account</b>
                        </p>
                    </lightning-layout-item>
                </lightning-layout>
            </div>
        </lightning-card>
    </div>

    <div class="slds-align_absolute-center">
        <lightning-card>
            <lightning-layout>
                <lightning-layout-item class="slds-m-around_small">
                    <lightning-input value={nameVar}
                                        variant="label-hidden"
                                        type="text" 
                                        placeholder="Account Name"
                                        autocomplete="none"
                                        data-field="accountLookup"
                                        onchange={handleAccNameChange}>
                    </lightning-input>
                    <template for:each={accounts} for:item="account" 
                             if:true={isAccountFound}>
                        <div key={account.value} id={account.value}
                            onclick={handleAccountSelection}>
                            <h3 title={account.value}
                                class="slds-border_bottom">
                                    {account.label}
                            </h3>
                        </div>
                    </template>
                </lightning-layout-item> 
                
                <lightning-layout-item class="slds-m-around_small"
                                       if:true={isAccountSelected}>
                    <table>
                        <tbody>
                            <tr>
                                <td><b>Selected Account Name : &nbsp;&nbsp;</b></td>
                                <td>{accountName}</td>
                            </tr>
                            <tr>
                                <td><b>Selected Account Id : &nbsp;&nbsp;</b></td>
                                <td>{accountId}</td>
                            </tr>
                        </tbody>
                    </table>
                </lightning-layout-item>
            </lightning-layout>
        </lightning-card>
    </div>
</template>

LookupCMP.js

import { LightningElementapi } from 'lwc';
import getAccounts from '@salesforce/apex/LookupController.fetchAccounts';

export default class LookupCMP extends LightningElement {
    nameVar = '';
    accounts = [];
    isAccountFound = false;
    accountName = '';
    accountId = '';
    isAccountSelected = false;

    //Onchange handler when Account name is entered by a user
    handleAccNameChange(event) {
        this.isAccountSelected = false;
        this.nameVar = event.target.value;
        this.getAccountsWithName();
    }
    
    //Imperatiev Apex method call for displaying the list of Account with the value entered
    getAccountsWithName() {
        getAccounts( { searchString : this.nameVar } )
        .then(result => {
            this.accounts = [];
            if(result.length > 0) {
                result.forEach(elem => {
                    let accVar = {
                        label : elem.Name,
                        value : elem.Id
                    };
                    this.accounts.push(accVar);
                });
            }
            this.isAccountFound = true;
        })
        .catch(error => {
            this.isAccountFound = false;
        });
    }

    //Handler method when an Account is selected
    handleAccountSelection(event) {
        let accountId = event.target.title;
        this.accounts.forEach(elem => {
            if(elem.value == accountId) {
                this.nameVar = elem.label;
            }
        });
        this.isAccountFound = false;
        this.accountName = this.nameVar;
        this.accountId = accountId;
        this.isAccountSelected = true;
        //Fire a custom event to send the data to a parent component
    }
}

LookupController.cls

//Method for fetching Accounts per the searchString provided
@AuraEnabled
public static List<AccountfetchAccounts(String searchString) {
    List<Accountaccounts = new List<Account>();
    try{
        String keyStr = '';
        if(!String.isBlank(searchString)) {
            keyStr = searchString + '%';
        }
        accounts = [SELECT IdName
                    FROM Account
                    WHERE Name LIKE :keyStr
                    ORDER BY Name
                    LIMIT 10];
        return accounts;
    }catch(exception exc) {
        return accounts;
    }
}

Thursday, February 11, 2021

Counter LWC - Lightning Design System


There are many awesome component blueprints defined in SLDS which are not available in LWC library, one such is Counter, full article here.


I have created a generic custom LWC component, code below, to use it across orgs - 

customCounter.html

<template>
    <div class="slds-form-element">

        <div class="slds-form-element__control">
            <button class="slds-button slds-button_icon 
slds-button_icon-small slds-input__button_decrement" 
                    title="Decrement counter">
                <lightning-icon icon-name="utility:ban" 
                                alternative-text="" 
                                size="xx-small" 
                                title="" 
                                variant="error"
                                onclick={setDecrementCounter}>
                </lightning-icon>
              <span class="slds-assistive-text">Decrement counter</span>
            </button>
            <input type="number" id="default1" placeholder={qtyVal} 
class="slds-input slds-input_counter" />
            <button class="slds-button slds-button_icon 
slds-button_icon-small 
slds-input__button_increment" 
                    title="Increment counter">
                <lightning-icon icon-name="utility:new" 
                                alternative-text="" 
                                size="xx-small" 
                                title="" 
                                variant="success"
                                onclick={setIncrementCounter}>
                </lightning-icon>
              <span class="slds-assistive-text">Increment counter</span>
            </button>
          </div>

      </div>
</template>

customCounter.js

import { LightningElementapi } from 'lwc';

export default class CustomCounter extends LightningElement {
    
    qty = 0;
    qtyVal = '';

    setDecrementCounter(event) {
        if(this.qty == 0)   this.qty = 0;
        else    this.qty = this.qty - 1;
        let quantity = this.qty.toString();
        this.qtyVal = quantity + ' ' + this.qtyMeasure;
        const decrementEvent = new CustomEvent(
'decrement'
detail: this.qty }
);
        this.dispatchEvent(decrementEvent);
    }

    setIncrementCounter(event) {
        this.qty = this.qty + 1;
        let quantity = this.qty.toString();
        this.qtyVal = quantity + ' ' + this.qtyMeasure;
        const incrementEvent = new CustomEvent(
'increment'
detail: this.qty }
);
        this.dispatchEvent(incrementEvent);
    }

    @api 
    get qtyMeasure() {
        return this._qtyMeasure;
    }

    set qtyMeasure(value) {
        if (value) {
            this._qtyMeasure = value;
            let qty = this.qty.toString();
            this.qtyVal = qty + ' ' + this.qtyMeasure;
        }else{
            this.qtyVal = '';
        }
    }
}

Call "customCounter" from other LWCs - 

parent.html

<template>
    <lightning-card >
        <lightning-layout>
            <lightning-layout-item class="slds-p-left_small">
                <lightning-icon icon-name="utility:trailhead" 
size="large"></lightning-icon>
            </lightning-layout-item>
            <lightning-layout-item>
                <p class="slds-p-horizontal_small">
                    <b>SLDS COUNTER</b>
                </p>
            </lightning-layout-item>
        </lightning-layout>
        
        <lightning-layout multiple-rows class="slds-m-around_xx-large">
                <lightning-layout-item class="slds-size_1-of-4">
</lightning-layout-item>    
                <lightning-layout-item class="slds-size_1-of-4 slds-box">
                    <lightning-icon icon-name="utility:product_workspace" 
size="small"></lightning-icon>
                    &nbsp;&nbsp;&nbsp;&nbsp;Paracetamol
                </lightning-layout-item>
                <lightning-layout-item class="slds-size_1-of-4 slds-box">
                    <c-custom-counter 
                                qty-measure='Strips'
                                ondecrement={quantityCtrl}
                                onincrement={quantityCtrl}>
                    </c-custom-counter>
                </lightning-layout-item>
                <lightning-layout-item class="slds-size_1-of-4">
</lightning-layout-item>
                <lightning-layout-item class="slds-size_1-of-4">
</lightning-layout-item>  
  
                <lightning-layout-item class="slds-size_1-of-4 slds-box">
                    <lightning-icon icon-name="utility:product_workspace" 
size="small"></lightning-icon>
                    &nbsp;&nbsp;&nbsp;&nbsp;Hand Sanitizer
                </lightning-layout-item>
                <lightning-layout-item class="slds-size_1-of-4 slds-box">
                    <c-custom-counter
                                qty-measure='Pieces'
                                ondecrement={quantityCtrl}
                                onincrement={quantityCtrl}>
                    </c-custom-counter>
                </lightning-layout-item>
                <lightning-layout-item class="slds-size_1-of-4">
</lightning-layout-item>

                <lightning-layout-item class="slds-size_1-of-4">
</lightning-layout-item>    
                <lightning-layout-item class="slds-size_1-of-4 slds-box">
                    <lightning-icon icon-name="utility:product_workspace" 
size="small"></lightning-icon>
                    &nbsp;&nbsp;&nbsp;&nbsp;Water Bottle
                </lightning-layout-item>
                <lightning-layout-item class="slds-size_1-of-4 slds-box">
                    <c-custom-counter 
                                qty-measure='Litres'
                                ondecrement={quantityCtrl}
                                onincrement={quantityCtrl}>
                    </c-custom-counter>
                </lightning-layout-item>
                <lightning-layout-item class="slds-size_1-of-4">
</lightning-layout-item>    

                <lightning-layout-item class="slds-size_1-of-4">
</lightning-layout-item>    
                <lightning-layout-item class="slds-size_1-of-4 slds-box">
                    <lightning-icon icon-name="utility:product_workspace" 
size="small"></lightning-icon>
                    &nbsp;&nbsp;&nbsp;&nbsp;Sugar
                </lightning-layout-item>
                <lightning-layout-item class="slds-size_1-of-4 slds-box">
                    <c-custom-counter 
                                qty-measure='Kilograms'
                                ondecrement={quantityCtrl}
                                onincrement={quantityCtrl}>
                    </c-custom-counter>
                </lightning-layout-item>
                <lightning-layout-item class="slds-size_1-of-4">
</lightning-layout-item>    
        </lightning-layout>

   </lightning-card>
        
</template>

parent.js

import { LightningElement } from 'lwc';

export default class Parent extends LightningElement {
    qty = 0;
    
    quantityCtrl(event) {
        this.qty = event.detail;
    }

}