Saturday, June 11, 2022

Lightning Modal/Popup Lightning Web Component(LWC)

Hello Guys, In this post I'll create lightning Modal/Popup in Lightning Web component Salesforce(LWC).

Modals are used to display content in a layer above the app. This paradigm is used in cases such as the creation or editing of a record, as well as various types of messaging and wizards.

Check below example

lightningModalLWC.html

<template>
    <!--Lightning Button which will open Modal on the click of it -->
    <lightning-button variant="brand" label="Open Modal" onclick={openModal}></lightning-button>

    <!--isModalOpen property will be used to hide/show for modal -->
    <template if:true={isModalOpen}>
        <!-- lightning modal Starts here -->
        <section role="dialog" tabindex="-1" aria-modal="true" aria-labelledby="modal-heading-01" class="slds-modal slds-fade-in-open">
            <div class="slds-modal__container">
                <lightning-button-icon icon-name="utility:close"
                                              onclick={closeModal}                                              
                                              variant="bare-inverse"
                                              class="slds-modal__close">
                </lightning-button-icon>
                <div class="slds-modal__header">
                    <h1 id="modal-heading-01" class="slds-modal__title slds-hyphenate">Modal/Popup header LWC</h1>
                </div>
                <div class="slds-modal__content slds-p-around_medium" id="modal-content-id-1">
                    <p>Modal Content would come here</p>
                </div>
                <div class="slds-modal__footer">
                    <button class="slds-button slds-button_neutral" aria-label="Cancel and close" onclick={closeModal}>Cancel</button>
                    <button class="slds-button slds-button_brand" onclick={submit}>Submit</button>
                </div>
            </div>
        </section>
        <div class="slds-backdrop slds-backdrop_open" role="presentation"></div>
        <!-- lightning modal Ends here -->
    </template>
</template>
lightningModalLWC.js

import { LightningElement } from 'lwc';

export default class LightningModalLWC extends LightningElement {
    isModalOpen = false;//property that will be use to hide/show of Lightning Modal

    openModal(){
        this.isModalOpen = true;
    }
    closeModal(){
        this.isModalOpen = false;
    }
    submit(){
        //write some logic
        this.isModalOpen = false;
    }
}
lightningModalLWC.js-meta.xml

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>54.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
        <target>lightning__HomePage</target>
        <target>lightning__AppPage</target>
        <target>lightning__RecordPage</target>
    </targets>
</LightningComponentBundle>
output

Related Post : Lightning Modal/Popup Lightning Aura Component Salesforce

Lightning Modal/Popup Lightning Aura Component Salesforce

Hello Guys, In this post I'll create lightning Modal in Lightning Aura component Salesforce.

Modals are used to display content in a layer above the app. This paradigm is used in cases such as the creation or editing of a record, as well as various types of messaging and wizards.

Check below example

LightningModalAura.cmp

<aura:component implements="flexipage:availableForAllPageTypes" access="global" >
    <!--Attributes -->
    <aura:attribute name="isModalOpen" type="boolean" default="false"></aura:attribute> 
    
    <!--Lightning Button which will open Modal on the click of it -->
    <lightning:button variant="brand" label="Open Modal" onclick="{!c.openModal}"></lightning:button>
    
    <!--isModalOpen Attribute will be used to hide/show for modal -->
    <aura:if isTrue="{!v.isModalOpen}">
        <!-- lightning modal Starts here -->
        <section role="dialog" tabindex="-1" aria-modal="true" aria-labelledby="modal-heading-01" class="slds-modal slds-fade-in-open">
            <div class="slds-modal__container">
                <lightning:buttonIcon iconName="utility:close"
                                              onclick="{!c.closeModal}"
                                              alternativeText="close"
                                              variant="bare-inverse"
                                              class="slds-modal__close"/>
                <div class="slds-modal__header">
                    <h1 id="modal-heading-01" class="slds-modal__title slds-hyphenate">Modal header</h1>
                </div>
                <div class="slds-modal__content slds-p-around_medium" id="modal-content-id-1">
                    <p>Modal Content would come here</p>
                </div>
                <div class="slds-modal__footer">
                    <button class="slds-button slds-button_neutral" aria-label="Cancel and close" onclick="{!c.closeModal}">Cancel</button>
                    <button class="slds-button slds-button_brand" onclick="{!c.submit}">Submit</button>
                </div>
            </div>
        </section>
        <div class="slds-backdrop slds-backdrop_open" role="presentation"></div>
        <!-- lightning modal Ends here -->
    </aura:if>
</aura:component>
LightningModalAuraController.js

({
	openModal : function(component, event, helper) {
		component.set("v.isModalOpen", true);
	},
    closeModal : function(component, event, helper) {
        component.set("v.isModalOpen", false);		
	},
    submit : function(component, event, helper) {
        //write some logic
		component.set("v.isModalOpen", false);	
	},
})
output

Related Post : Lightning Modal/Popup Lightning Web Component(LWC)

Wednesday, June 8, 2022

Lightning combobox to display State and City in LWC also load with Default value

Hello Guys, In this post we would learn how can we populate State values in Lightning Combobox and on the selection of State, Cities should be populated in another combobox.

To Understand this scenario, I have created two master objects in Salesforce 1. State ( having States records) 2. City which has master detail to State object and having cities records. I have created two text field State and City on Contact object to store the values.

Our stateCity component has been placed on Contact Detail page it has one update button so whenever user select States, automatically cities belong to that state would come up in City Combobox and after the selection of City, once user clicks on Update button both State and City values will be saved in Contact object in State and City fields respectivily.

If user comes on the detail page later and State and City fields on the Contact object are already has values so on load of the component the default values would be shown to the user.

See the full code below

Apex Class


public class StateCityController {
    @AuraEnabled
    public static ContactStateCityWrapper getStateCities(String recordId){  
        ContactStateCityWrapper obj = new ContactStateCityWrapper();
        List<State__c> stateList = [select Name, (select Name from cities__r order by Name) from state__c order by Name ];
        Contact con = [SELECT State__c, City__c FROM Contact WHERE Id =: recordId];
        
        obj.stateCityList = stateList;
        obj.contact = con;
        return obj;
    }
    public Class ContactStateCityWrapper{
        @AuraEnabled public Contact contact;
        @AuraEnabled public List<State__c> stateCityList;
    }
    @AuraEnabled
    public static String handleUpdate(String contactDetails){
        Contact conObj = (Contact) JSON.deserialize(contactDetails, Contact.class);
        
        update conObj;
        return conObj.Id;
    }
}

stateCity.html


<template>
    <lightning-card title="Update State and City">
        <div class="slds-grid slds-no-flex slds-var-p-around_medium	">
            <div class="slds-col slds-size_2-of-12">State</div>
            <div class="slds-col slds-size_2-of-12">
                <lightning-combobox variant="label-hidden"
                                name="state"                                                                                
                                placeholder="Select State"
                                options={states}
                                onchange={onStateChange} 
                                data-id="state">
                </lightning-combobox>                   
            </div>
            <div class="slds-col slds-size_1-of-12"></div>
            <div class="slds-col slds-size_2-of-12">City</div>
            <div class="slds-col slds-size_2-of-12">
                <lightning-combobox variant="label-hidden"
                            name="city"                                                                        
                            placeholder="Select City"
                            options={cities}
                            onchange={onCityChange}
                            data-id="city" >
                </lightning-combobox>
            </div>
        </div> 
    
    <div class="slds-grid slds-no-flex slds-var-p-around_medium	">
        <div class="slds-col slds-size_12-of-12 slds-align_absolute-center">
            <lightning-button variant="brand" style="width: 6rem;" label="Update" title="Update" onclick={handleUpdate} class=""></lightning-button>            
        </div>
    </div>
</lightning-card>
</template>

stateCity.js


import { LightningElement, api } from 'lwc';
import getStateCities from '@salesforce/apex/StateCityController.getStateCities';
import handleUpdate from '@salesforce/apex/StateCityController.handleUpdate';

export default class StateCity extends LightningElement {
    @api recordId;
    error;
    states;
    cities;
    stateCityMap = {};
    stateIdNameMap = {};
    cityIdNameMap = {};
    selectedStateName
    selectedCityName
    connectedCallback(){
        console.log('## '+this.recordId)
        getStateCities({
            recordId : this.recordId
        })
        .then(result =>{
            let stateOptions = [];                        
            let cityMapLocal = {}; 
            let stateIdNameMapLocal = {};
            let cityIdNameMapLocal = {};
            
            let stateNameIdMapLocal = {};
            let cityNameIdMapLocal = {};

            console.log('## '+JSON.stringify(result))
            //Population of State and City List
            result.stateCityList.forEach(function(index,value){
                if(index.Cities__r){
                    let cities = index.Cities__r.map(function(data){  
                        cityIdNameMapLocal[data.Id] = data.Name;
                        cityNameIdMapLocal[data.Name] = data.Id;                                              
                        return data;
                    });
                    cityMapLocal[index.Id] = cities;
                }else{
                    cityMapLocal[index.Id] = [];
                } 
                stateIdNameMapLocal[index.Id] = index.Name.toUpperCase(); 
                stateNameIdMapLocal[index.Name.toUpperCase()] = index.Id;              
                stateOptions.push({label:index.Name.toUpperCase(), value:index.Id});                
            }) 
            this.stateIdNameMap = stateIdNameMapLocal;
            this.cityIdNameMap = cityIdNameMapLocal;
            
            this.states = stateOptions;
            this.stateCityMap = cityMapLocal;
            console.log('## 2')
            if(result.contact.State__c != null && result.contact.City__c != null){
                this.template.querySelector('lightning-combobox[data-id="state"]').value = stateNameIdMapLocal[result.contact.State__c];
                this.template.querySelector('lightning-combobox[data-id="city"]').value = cityNameIdMapLocal[result.contact.City__c];
            
                //to populate the City Dropdown based on the State
                let cityOptions = [];
                let stateCityMap = JSON.parse(JSON.stringify(this.stateCityMap));
                let cityList = stateCityMap[stateNameIdMapLocal[result.contact.State__c]];
                if(cityList.length > 0){
                    cityList.forEach(function(index,value){
                        cityOptions.push({label: index.Name, value: index.Id});
                    })
                }
                this.cities = cityOptions;
            }
            console.log('##22')
        })
        .catch(error =>{
            this.error = error;
        })
    }
    onStateChange(event){
        let cityOptions = [];        
        let selectedStateId = event.target.value;
        let stateCityMap = JSON.parse(JSON.stringify(this.stateCityMap));
        let cityList = stateCityMap[selectedStateId];
        if(cityList.length > 0){
            cityList.forEach(function(index,value){
                cityOptions.push({label: index.Name, value: index.Id});
            })
        }
        this.cities = cityOptions;        
        this.selectedStateName = this.stateIdNameMap[selectedStateId];
    }
    onCityChange(event){        
        this.selectedCityName = this.cityIdNameMap[event.target.value];
    }
    handleUpdate(){
        let contact = {
            Id : this.recordId,
            State__c: this.selectedStateName,
            City__c : this.selectedCityName
        }

        handleUpdate({
            contactDetails : JSON.stringify(contact)
        })
        .then(result =>{
            alert('Successfully Updated!')
        })
        .catch(error =>{
            this.error = error
        })
    }
}

stateCity.js-meta.xml


<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>54.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
        <target>lightning__AppPage</target>
        <target>lightning__HomePage</target>
        <target>lightning__RecordPage</target>
    </targets>
</LightningComponentBundle>

Output

Below image shows the State and City values populating as default on page load from Contact record.

Please comment below, if you guys have any quesiton. I'll be happy to answer. Thanks!