OmniStudio : Enhancing Omniscript with Custom LWC Validations: A Comprehensive Guide

Nagendra SinghNagendra Singh
3 min read

Intro

We've all faced situations where we need to either extend Omniscript elements or create brand new LWC components to use inside Omniscripts. Extending or creating these components is not the problem, but there's a lack of clear documentation on how to implement validations for these components so that the standard Omniscript "Next" button checks the component before moving to the next page.

In this blog, we'll dive into exciting examples of how to hook into Omniscript validations from custom LWCs!

Scenario 1 (extends OmniscriptMultiselect)

In this scenario, we'll override the "OmniscriptMultiselect" element and give it a lightning-dual-listbox UI.

From:

To:

By extending "OmniscriptMultiselect," we can utilize the standard required field from Omniscript itself. I've put together a two-step Omniscript form. The first form features a multiselect element, and the second form supports the display of the navigation button on the first page.

Here if you see, I have marked the field as required and then overridden the component with custom LWC.

Below is the code for overrideMultiSelect

<template>
    <lightning-dual-listbox name={jsonDef.name}
                            label={_propSetMap.label}
                            source-label="Available"
                            selected-label="Selected"
                            field-level-help={_handleHelpText}
                            options={_realtimeOptions}
                            required={_propSetMap.required}
                            message-when-value-missing={_messageWhenValueMissing}
                            value={elementValue}
                            onchange={handleChange}
                            data-omni-input>
    </lightning-dual-listbox>
</template>
import tmpl from './overrideMultiSelect.html';
import OmniscriptMultiselect from 'omnistudio/omniscriptMultiselect';

export default class OverrideMultiSelect extends OmniscriptMultiselect {

    render(){
        return tmpl;
    }
}

Here, data-omni-input is the key to utilizing standard validations. The extended LWC component leverages the required field from the Omniscript flow and prevents the user from navigating to the next page until the validation on the current page is successfully completed.

Scenario 2 (extends OmniscriptBaseMixin)

In this scenario, we'll replace the entire Omniscript Multiselect with a custom LWC that extends "OmniscriptBaseMixin(LightningElement)".

Note: It is not recommended to extend OmniscriptBaseMixin(LightningElement) directly. Only use this if extending Omniscript elements does not solve a particular use case.

The form will look like this:

To add the same validation in a custom LWC and ensure the user is not navigated to the next screen until the value is populated in the multiselect, we make the following changes:

<template>
    <abbr class="slds-required customRequired" title="required" aria-label="required">*</abbr>
    <lightning-dual-listbox name="LanguageKnown"
                            label="LanguageKnown"
                            source-label="Available"
                            selected-label="Selected"
                            field-level-help="Select your preferred languages"
                            options={options}
                            value={value}
                            class="customPadding"
                            onchange={handleChange}>
    </lightning-dual-listbox>
    <p class="slds-text-color_error"
       if:true={showValidation}>Error: LanguageKnown is required.</p>
</template>
import {api, LightningElement} from 'lwc';
import {OmniscriptBaseMixin} from 'omnistudio/omniscriptBaseMixin';

export default class CustomMultiSelectLwc extends OmniscriptBaseMixin(LightningElement) {

    _selected = [];
    value = [];

    get componentIsValid(){
     return this._selected.length > 0;
    }

    get options() {
        return [
            { label: 'English', value: 'English' },
            { label: 'Hindi', value: 'Hindi' },
            { label: 'French', value: 'French' },
            { label: 'Spanish', value: 'Spanish' }
        ];
    }

    connectedCallback(){
        let arrayOfPreSelectedValues = null;
        if (this.omniJsonData && this.omniJsonData['Step1'] && this.omniJsonData['Step1']['CustomLWC1']) {
            arrayOfPreSelectedValues = this.omniJsonData['Step1']['CustomLWC1'];
        }
        if (arrayOfPreSelectedValues) {
            this.value.push(...arrayOfPreSelectedValues);
        }
    }

    handleChange(event){
        this._selected = event.detail.value;
        let CustomLWC1Value = {
            "Step1" : {
                "CustomLWC1" : this._selected
            }
        }
        this.omniApplyCallResp(CustomLWC1Value);
        this.omniValidate(false);
    }

    @api checkValidity(){
        return this.componentIsValid;
    }
}

There is also a static resource loaded as part of the Omniscript that overrides the CSS for shifting the "*" mark for the required attribute:

.customPadding .slds-form-element__label {
    margin-left: 0.7rem;
}

.customRequired{
    position: absolute;
    font-weight: bold;
    padding-top: 0.2rem;
}

And the user is now not able to navigate to next screen.

By not using data-omni-input here, we utilize:

@api checkValidity(){
    return this.componentIsValid;
}

When checkValidity is called and returns false, it sets showValidation to true, displaying the error message:

<p class="slds-text-color_error"
   if:true={showValidation}>Error: LanguageKnown is required.</p>

Whenever the user interacts with the component, it's important to call:

this.omniValidate(false);

so that the omni validates the page before moving to the next screen.

Conclusion

Hooking into standard validations from LWCs extending omniscript elements and LWCs extending OmniscriptBaseMixin is totally possible and works seamlessly! This opens up amazing possibilities to build more advanced and complex UIs.

0
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! ๐Ÿฅณ