Skip to content

Lightning Web Component: Dynamic Picklist Rendering via Lightning Data Service Based on Record Type and Field Dependency

Let’s assume a use case where a company sells to two types of clients:

  • Enterprise Clients
  • Retail Clients

Each division uses different Sales Processes, so they require:

  • Different Record Types
  • Different values for both a controlling picklist and a dependent picklist

Opportunity Object Record Types:

  1. Enterprise_Sales
  2. Retail_Sales

Controlling Picklist Field: Solution_Type__c

(Custom picklist to identify the type of solution sold)

๐Ÿ’ก Values per Record Type:

Solution_Type__cEnterprise_SalesRetail_Sales
Cloud Servicesโœ… YesโŒ No
On-Premise Licensingโœ… YesโŒ No
Hardware Bundleโœ… Yesโœ… Yes
Point of Sale SystemsโŒ Noโœ… Yes
SubscriptionsโŒ Noโœ… Yes
Marketing KitsโŒ Noโœ… Yes

Dependent Picklist Field: Product_Type__c

(Dependent on Solution_Type__c)

Solution_Type__cProduct_Type__c Values
Cloud ServicesSaaS, IaaS, PaaS
On-Premise LicensingWindows Server, SQL, Exchange
Hardware BundleLaptops, Servers, Network Gear
Point of Sale SystemsPOS Machines, Thermal Printers, Barcode Scanners
SubscriptionsMonthly Plan, Yearly Plan, Trial
Marketing KitsFlyers, Banners, Swag

Based on the provided setup, the following LWC displays the ‘Solution Type’ picklist values based on the selected record type, and dynamically shows the ‘Product Type’ picklist values based on both the selected record type and the chosen ‘Solution Type’ (controlling field).

LWC Name: opportunityPicker.html

<template>
    <lightning-card title="Opportunity Selection" icon-name="standard:picklist_choice">
        <lightning-layout class="slds-var-m-around_medium" multiple-rows>

            <!-- Row 1: Picklists -->  
                <lightning-layout-item class="slds-p-around_medium" size="4" flexibility="auto">
                    <lightning-combobox
                        label="Record Type"
                        value={selectedRecordType}
                        options={recordTypeOptions}
                        onchange={handleRecordTypeChange}>
                    </lightning-combobox>
                </lightning-layout-item>

                <lightning-layout-item class="slds-p-around_medium" size="4" flexibility="auto">
                    <lightning-combobox
                        label="Solution Type"
                        value={selectedSolutionType}
                        options={solutionTypeOptions}
                        onchange={handleSolutionTypeChange}>
                    </lightning-combobox>
                </lightning-layout-item>

                <lightning-layout-item class="slds-p-around_medium" size="4" flexibility="auto">
                    <lightning-combobox
                        label="Product Type"
                        value={selectedProductType}
                        options={filteredProductTypeOptions}
                        onchange={handleProductTypeChange}>
                    </lightning-combobox>
                </lightning-layout-item>
                
            <!-- Row 2: Selected Values -->
            <lightning-layout class="slds-m-top_medium">
                <lightning-layout-item class="slds-p-around_medium" size="12" flexibility="auto">
                    <p><strong>Selected Record Type:</strong> {selectedRecordType}</p>
                    <br/>
                    <p><strong>Selected Solution Type:</strong> {selectedSolutionType}</p>
                    <br/>
                    <p><strong>Selected Product Type:</strong> {selectedProductType}</p>
                </lightning-layout-item>

            </lightning-layout>

        </lightning-layout>
    </lightning-card>
</template>

LWC JS: opportunityPicker.js

import { LightningElement, wire, api } from 'lwc';
import { getPicklistValues, getPicklistValuesByRecordType } from "lightning/uiObjectInfoApi";

import OPPORTUNITY_OBJECT from "@salesforce/schema/Opportunity";
import SOLUTION_TYPE_FIELD from '@salesforce/schema/Opportunity.Solution_Type__c';
import PRODUCT_TYPE_FIELD from '@salesforce/schema/Opportunity.Product_Type__c';

import { getObjectInfo } from 'lightning/uiObjectInfoApi';

export default class OpportunityPicker extends LightningElement {

    @api recordId; // Opportunity ID
    //Picklist Options
    recordTypeOptions = [];    
    solutionTypeOptions = [];
    allproductTypeMetadata = [];
    productTypeOptions = [];
    filteredProductTypeOptions = [];

    //picklist selected values
    selectedRecordType = '';
    selectedSolutionType = '';
    selectedProductType = '';


    // Fetch Record Types
    @wire(getObjectInfo, { objectApiName: OPPORTUNITY_OBJECT })
    objectInfoHandler({ data, error }) {
        if (data) {
            const rtInfos = data.recordTypeInfos;
            const rtList = Object.values(rtInfos)
                .filter(rt => rt.available && !rt.master) // Exclude Master record type
                .map(rt => ({
                    label: rt.name,
                    value: rt.recordTypeId
                }));
            this.recordTypeOptions = rtList;
        } else if (error) {
            console.error('Error fetching record types: ', error);
        }
    }

    // Fetch Product Families
    @wire(getPicklistValuesByRecordType, {
        objectApiName: OPPORTUNITY_OBJECT,
        recordTypeId: '$selectedRecordType'
    })
    wiredSolutionTypes({ data, error }) {
        if (data) {
            if (data.picklistFieldValues && data.picklistFieldValues.Solution_Type__c) {
                this.solutionTypeOptions = data.picklistFieldValues.Solution_Type__c.values;
            } else {
                console.warn('No picklist values found for Solution_Type__c.');
            }
        } else if (error) {
            console.error('Error fetching picklist values:', error);
        }
    }

    // Get the dependent picklist values for PRODUCT_TYPE_FIELD (dependent picklist) based on selected Solution Type
    @wire(getPicklistValues, { recordTypeId: "$selectedRecordType", fieldApiName: PRODUCT_TYPE_FIELD })
    wiredProductTypePicklist({ data, error }) {
        if (data) {
            this.allproductTypeMetadata = data;
            this.productTypeOptions = data.values;
        } else if (error) {
            console.error('Error fetching picklist values:', error);
        }
    }

    handleRecordTypeChange(event){
        this.selectedRecordType = event.target.value;
        this.selectedSolutionType = '';
        this.selectedProductType = '';
        console.log(this.selectedRecordType);
    }

    handleSolutionTypeChange(event){
        this.selectedSolutionType = event.target.value;

        const selectedSolutionTypeValue = this.allproductTypeMetadata.controllerValues[this.selectedSolutionType];
        this.filteredProductTypeOptions = this.allproductTypeMetadata.values.filter(option =>
            option.validFor.includes(selectedSolutionTypeValue)
        );
   }
   
    handleProductTypeChange(event){
        this.selectedProductType = event.target.value;
    }
}

LWC XML: opportunityPicker.js-meta.xml

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>63.0</apiVersion>
    <isExposed>true</isExposed>
    <masterLabel>Dynamic Picklist values</masterLabel>
    <targets>
        <target>lightning__RecordPage</target>
    </targets>
    <targetConfigs>
        <targetConfig targets="lightning__RecordPage">
            <objects>
                <object>Opportunity</object>
            </objects>
        </targetConfig>
    </targetConfigs>
</LightningComponentBundle>