OmniStudio: Enriching Fundamental Elements with LWC

Unleashing the Power of Extending Lightning Web Components

ยท

5 min read

Hey there tech friends! I'm so glad to have you back for another exciting post in my blog series all about Salesforce's amazing OmniStudio. I bet you've already gotten to know the fantastic features it offers, which help businesses run smoothly and connect with customers in new and exciting ways. Today, I'm going to explore the heart of OmniStudio: Lightning Web Components (LWCs) and how we can customize them to suit our specific needs.

Decoding OmniStudio Lightning Web Components

Before we jump into customizing these awesome LWCs, let's take a moment to understand what they are and how they play a big part in the amazing OmniStudio ecosystem. Salesforce brings us a super easy 'clicks, not code' approach with OmniStudio, making building and tweaking applications a breeze. When we work with OmniStudio LWCs, we get to use good ol' JavaScript and HTML to modify and expand OmniStudio products. Now, let's dive in!

Power of Extending Lightning Web Components

When working with prebuilt components, you may come across situations where the default behavior doesn't meet your specific needs. Here, extending LWCs becomes crucial. Customizing the behavior and styling of an application by extending LWCs gives us the flexibility to override properties, add other components, or even insert our HTML.

Let's check out an example together.

Imagine you need to create a disclosure element with two buttons, "Submit" and "Cancel". The cool part is, the "Submit" button only becomes active when the checkbox is checked. Otherwise, it stays disabled.

Now to achieve this we will extend "OmniscriptIpAction" and "OmniscriptCheckbox"

Extending "OmniscriptCheckbox"

customCheckbox.html

<template>
</template>

customCheckbox.js

import OmniscriptCheckbox from 'omnistudio/omniscriptCheckbox';

export default class CustomCheckbox extends OmniscriptCheckbox {

    handleChange(event){
        super.handleChange(event);
        let contextId = JSON.parse(this.jsonDataStr).ContextId;

        const checkBoxEvent = new CustomEvent('checked_' + contextId, {
            detail: {
                checked : event.target.checked
            },
        });
        window.dispatchEvent(checkBoxEvent)
    }
}

customCheckbox.js-meta.xml

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>58.0</apiVersion>
    <description>Custom Checkbox</description>
    <isExposed>true</isExposed>
    <masterLabel>Custom Checkbox</masterLabel>
    <runtimeNamespace>omnistudio</runtimeNamespace>
</LightningComponentBundle>

In this case, we're not modifying the HTML since we don't need to alter the user interface. Our goal is simply to trigger an event when the checkbox is checked or unchecked.

We're using CustomEvent to achieve this, which allows us to raise a record-specific event. This way, only the button on the form will be listening for the checkbox event.

Extending "OmniscriptIpAction"

This will act as our Submit button.

Here we do need to override HTML as we need to add a custom disabled logic. But the amazing thing is. We don't need to write the whole code. Just take the base element's HTML and just add the "disabled" attribute.

Just go down the latest base elements list from this link. After you download the base elements you need to just copy and paste the whole html from omni-base-templates > omniscriptBaseAction > omniscriptBaseAction.html

customIpAction.html

<template>
    <slot>
        <template if:true={_isBtn}>
            <div class="slds-is-relative slds-p-top_xx-small">
                <omnistudio-button type="button"
                                   variant="brand"
                                   onclick={execute}
                                   disabled={_disabled}
                                   theme={_theme}
                                   label={_propSetMap.label}
                                   extraclass={extraclass}>
                </omnistudio-button>
                <template if:true={isBtnLoading}>
                    <omnistudio-spinner variant="brand"
                                        alternative-text="Loading..."
                                        theme={_theme}
                                        size="small">
                    </omnistudio-spinner>
                </template>
            </div>
            <template if:true={_isDesignMode}>
                <template if:true={_isActionBlock}>
                    <p>{allCustomLabelsUtil.ODCActionBlockDrop4ElementsBelow}</p>
                    <div class="slds-m-top_small slds-p-around_small omni-designer-action-container">
                        <slot name="actionBlockDesignTimeChildren"></slot>
                    </div>
                </template>
            </template>
        </template>
        <template if:true={isPageLoading}>
            <omnistudio-spinner variant="brand"
                                alternative-text="Loading..."
                                theme={_theme}
                                message={spinnerActionMessage}
                                size="medium">
            </omnistudio-spinner>
        </template>
    </slot>
</template>

If you look carefully, I only added "disabled={_disabled}" attribute from the original omniscriptBaseAction.html.

customIpAction.js

import OmniscriptIpAction from 'omnistudio/omniscriptIpAction';
import tmpl from './customIpAction.html';
import { OmniscriptActionCommonUtil } from 'omnistudio/omniscriptActionUtils';

export default class CustomIpAction extends OmniscriptIpAction {

    _disabled = false;
    _actionUtilClass;
    render(){
        return tmpl;
    }

    connectedCallback(){
        super.connectedCallback();
        this._actionUtilClass = new OmniscriptActionCommonUtil();
        this._disabled = true;
        let contextId = JSON.parse(this.jsonDataStr).ContextId;
        window.addEventListener('checked_' + contextId, (event) => {
            if(event && event.detail){
                this._disabled = !event.detail.checked;
            }
        })
    }

    execute(){
        this.isPageLoading = true;
        const options = {
            chainable: true, //Use chainable when an Integration Procedure exceeds the Salesforce CPU Governor limit.
            useFuture: false,
        };
        const params = {
            input: //input for IP,
            sClassName: 'omnistudio.IntegrationProcedureService',
            sMethodName: 'OrderDetails_SaveAndUpdate', //this will need to match the VIP -> type_subtype
            options: JSON.stringify(options),
        };
        this._actionUtilClass
        .executeAction(params, null, this, null, null)
        .then(resp => {
            this.isPageLoading = false;
            if(!resp.error){
                //Do your logic after successful response from Ip Action
            }
        })
        .catch(error => {
            this.isPageLoading = false;
            window.console.log(error, 'error');
        });
    }
}

In this code, we'll be overriding three methods to make things work smoothly:

1. render(): We'll override this method to pass our custom UI to the Omniscript engine. This way, it'll use our HTML instead of the base HTML.

2. connectedCallback(): We'll override this method to register custom events for listening and to initialize OmniscriptActionCommonUtil. This will help us call IP or any remote action later on.

3. execute(): We'll override this method to call the IP.

Just a heads up: When overriding OmniscriptIpAction, it's crucial to override execute(). Otherwise, you might run into an exception.

The listener here will do its magic and listen to the checked event and enable and disable the button when the checkbox is checked and unchecked.

Just a friendly reminder: make sure to place these components in the LWC component override section of the respective OmniStudio component. This will help everything run smoothly. Have fun working on it!

Demo

Summary

In this blog post, we explore the customization of OmniStudio Lightning Web Components (LWCs) to suit specific needs. We discuss extending LWCs, using an example of creating a disclosure element with "Submit" and "Cancel" buttons. We also cover the process of extending "OmniscriptIpAction" and "OmniscriptCheckbox" and provide code snippets for each. Finally, we highlight the importance of placing these components in the LWC component override section for smooth functionality.

Did you find this article valuable?

Support Nagendra Singh's blog by becoming a sponsor. Any amount is appreciated!

ย