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!