OmniStudio: How to Show RecordType and Controlling field-Based Values in OmniScript Select Element
Table of contents
Introduction
Hey there, friend! ๐ So, I was having a blast playing around with Omniscript and expanding its capabilities using LWC when I came across something super cool. I just can't wait to share this discovery with you! You know, when you're working with OmniStudio, sometimes you might want to display picklist values based on specific record types and a controlling field. Well, guess what? We've totally got your back! By harnessing the power of the amazing Salesforce Lightning Web Component (LWC) framework and the ever-useful OmniScript, you can achieve this with ease. In this post, I'll guide you through the process of extending omniscriptSelect with a Custom LWC. Let's dive in!
Demo Org Setup
I have an object named "DependentTest__c" and one RecordType under this called "Record1".
Two Fields: ControllingField__c and DependentField__c
ControllingField__c with values as below image:
DependentField__c with values as below image:
And below is the dependency between ControllingField__c and DependentField__c.
Also in RecordType Record1, I have excluded "D0", to make show an example of the dependent field being dependent on the RecordType + Controlling field.
So when a user selects "M0" on the Controlling picklist, he should only see "D1" and "D5" in the Dependent picklist field on OmniScript select element. But if you try using the OOTB SELECT element and configure it like shown below.
For Controlling Field :
For Controlling Field:
The preview will start showing all dependent picklist values regardless of whether it's part of the record type or not as the OOTB SELECT element cannot filter picklist based on RecordType.
Thus showing all values from dependency.
Solution
The solution is to extend "OmniscriptSelect" and do some custom logic here.
Now I created a LWC named as "customSelect".
As we don't need to override html hence leaving html as it is.
<template>
</template>
We need to do some custom logic only for the Select element. Thus overriding connectedCallback()
and combinedWatch()
connectedCallback()
: This lifecycle method runs when the component is inserted into the DOM. Here, we set the recordTypeIdFromOS
and identify if the label is "DependentPicklist" to set the dependentSourceSelect
. This is to make sure our custom logic only runs on targeted elements.
combinedWatch()
: This acts as a listener to the omniscript element changes and updates the _realtimeOptions
of the select element based on the value of the controlling field. This ensures that when a user selects a controlling value, the select element displays the corresponding dependent values.
NOTE: Below is not a PROD-ready code, please modify accordingly.
import OmniscriptSelect from 'omnistudio/omniscriptSelect';
import { getPicklistValues} from 'lightning/uiObjectInfoApi';
import { getElementValue } from 'omnistudio/omniscriptInternalUtils';
import {wire} from "lwc";
export default class CustomSelect extends OmniscriptSelect {
mapControllingWithDependentList = {};
dependentSourceSelect;
recordTypeIdFromOS;
@wire(getPicklistValues, {
recordTypeId: '$recordTypeIdFromOS',
fieldApiName: '$dependentSourceSelect'
})
wiredValues({ error, data }) {
if (data) {
let root = data;
let mapControllingValueWithIndex = {};
let result = {};
if (root.controllerValues) {
let controllingValues = root.controllerValues;
for (let cValue in controllingValues) {
mapControllingValueWithIndex[controllingValues[cValue]] = cValue;
}
}
if (!root.values) {
console.log(this.mapControllingWithDependentList);
return;
}
let pValues = root.values;
for (let pValue of pValues) {
result[pValue.value] = pValue.label;
for (let validfor of pValue.validFor) {
if (mapControllingValueWithIndex[validfor]) {
if (!this.mapControllingWithDependentList[mapControllingValueWithIndex[validfor]]) {
this.mapControllingWithDependentList[mapControllingValueWithIndex[validfor]] = [{
value: '',
label: '-- Clear --'
}];
}
this.mapControllingWithDependentList[mapControllingValueWithIndex[validfor]].push({
value: pValue.value,
label: pValue.label
});
}
}
}
}
}
connectedCallback(){
super.connectedCallback();
this.recordTypeIdFromOS = '0122w000002MvJnAAK';// This record type id can be passed from omniscript
if(this._propSetMap.label === "DependentPicklist") {
this.dependentSourceSelect = this._propSetMap.optionSource.source;
}
}
combinedWatch(){
super.combinedWatch();
if(this._propSetMap.label === "DependentPicklist") {
let controllingElement = this._propSetMap.controllingField.element;
let controllingFieldValue = getElementValue(controllingElement, this.jsonData, this.scriptHeaderDef.labelMap, this.jsonDef.JSONPath || null);
if (controllingFieldValue !== null) {
this._realtimeOptions = this.mapControllingWithDependentList[controllingFieldValue];
}
}
}
}
getPicklistValues
: Salesforce function to retrieve picklist values based on RecordType Id.
And your XML goes like this :
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>58.0</apiVersion>
<description>Custom Select</description>
<isExposed>true</isExposed>
<masterLabel>Custom Select</masterLabel>
<runtimeNamespace>omnistudio</runtimeNamespace> <!--May not be required if LWS is turned ON-->
</LightningComponentBundle>
After this, you can override this customSelect with the base element on Setup like shown below.
Now when you preview, you can see it only shows up data that is relevant to the record type also maintaining the mapping between the Controlling field too.
And as we are just extending the OmniscriptSelect, no need to worry about updating the Omniscript JSON as it internally gets taken care of by the framework.
Demo
OOTB Demo:
After overriding Select with customSelect LWC component.
Subscribe to my newsletter
Read articles from Nagendra Singh directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Nagendra Singh
Nagendra Singh
Allow me to introduce myself, the Salesforce Technical Architect who's got more game than a seasoned poker player! With a decade of experience under my belt, I've been designing tailor-made solutions that drive business growth like a rocket launching into space. ๐ When it comes to programming languages like JavaScript and Python, I wield them like a skilled chef with a set of knives, slicing and dicing my way to seamless integrations and robust applications. ๐ฝ๏ธ As a fervent advocate for automation, I've whipped up efficient DevOps pipelines with Jenkins, and even crafted a deployment app using AngularJS that's as sleek as a luxury sports car. ๐๏ธ Not one to rest on my laurels, I keep my finger on the pulse of industry trends, share my wisdom on technical blogs, and actively participate in the Salesforce Stackexchange community. In fact, this year I've climbed my way to the top 3% of the rankings! ๐งโโ๏ธ So, here's to me โ your humor-loving, ultra-professional Salesforce Technical Architect! ๐ฅณ