For Everyone

Create a Custom Lightning Component for Alert and Confirm Dialogs

6 min read
CloudAnswers photo
CloudAnswers
Share
TODO

As front-end developers, there can be numerous instances when we need to display a prompt, a confirm dialog, or a confirm dialog with some input control to accept some value from the user. If you happen to be a Salesforce developer reading this article, you must have had such a requirement while writing lightning components.

There are a couple of components available in the Lightning Components Library that can be used to render dialogs.

lightning:lightning:overlayLib

This component is quite extensive and offers good flexibility for rendering the dialog header, body, etc. However, this component lacks:

  1. Ability to accept input from the user
  2. Support for Lightning Out

lightning:alert and lightning:confirm

This component is supported in both Lightning Experience and Lightning Out but lacks

  1. Ability to accept input from a user
  2. Ability to override header, body, etc to render HTML markup

Workaround

As a workaround for the missing features in the above components, I have put together a custom Lightning component that supports

  1. Accepting input from a user
  2. Rendering HTML markup in modal body
  3. Both Lightning Experience and Lightning Out

<aura:component >

    <aura:attribute name="title" type="String" />
    <aura:attribute name="message" type="String" />
    <aura:attribute name="showConfirmButton" type="Boolean" default="true" />
    <aura:attribute name="showCancelButton" type="Boolean" default="false" />
    <aura:attribute name="confirmButtonLabel" type="String" default="OK" />
    <aura:attribute name="cancelButtonLabel" type="String" default="Cancel" />
    <!-- accepting user input -->
    <aura:attribute name="inputType" type="String" />
    <aura:attribute name="inputLabel" type="String" />
    <aura:attribute name="inputValue" type="String" />
    <aura:attribute name="inputPlaceholder" type="String" default="Enter a value" />

    <aura:attribute name="promptClass" type="String" access="private" />
    <aura:attribute name="isOpen" type="Boolean" access="private" />
    <aura:attribute name="config" type="Object" access="private" />

    <aura:method name="open" action="{!c.openAlert}" description="Method used to open alert">
        <aura:attribute name="config" type="Object" />
    </aura:method>

    <aura:if isTrue="{!v.isOpen}">
        <div>
            <section role="dialog" tabindex="0" aria-modal="true" aria-labelledby="alert-heading-id" aria-describedby="alert-message-wrapper" class="slds-modal slds-fade-in-open slds-modal_prompt">
                <div class="slds-modal__container">
                    <div class="{!'slds-modal__header slds-theme_alert-texture ' + v.promptClass}">
                        <h1 class="slds-text-heading_medium" id="alert-heading-id">{!v.title}</h1>
                    </div>
                    <div class="slds-modal__content slds-p-around_medium" id="alert-message-wrapper">
                        <aura:if isTrue="{!v.inputType == null}">
                            <lightning:formattedRichText value="{!v.message}"></lightning:formattedRichText>
                        </aura:if>
                        <aura:if isTrue="{!v.inputType == 'text'}">
                            <lightning:input aura:id="text-input" type="{!v.inputType}" label="{!v.inputLabel}" value="{!v.inputValue}" placeholder="{!v.inputPlaceholder}" />
                        </aura:if>
                    </div>
                    <div class="slds-modal__footer slds-theme_default">
                        <aura:if isTrue="{!v.showCancelButton}">
                            <lightning:button label="{!v.cancelButtonLabel}" title="{!v.cancelButtonLabel}" onclick="{! c.handleCancel }" />
                        </aura:if>
                        <aura:if isTrue="{!v.showConfirmButton}">
                            <lightning:button variant="brand" label="{!v.confirmButtonLabel}" title="{!v.confirmButtonLabel}" onclick="{! c.handleConfirm }" />
                        </aura:if>
                    </div>
                </div>
            </section>
            <div class="slds-backdrop slds-backdrop_open" role="presentation"></div>
        </div>
    </aura:if>
</aura:component>

({
    openAlert: function(component, event, helper) {
        // close existing alert
        helper.closeAlert(component);
        // get params
        var args = event.getParam('arguments');
        var config = args.config;
        helper.setConfiguration(component, config);
        // open alert
        helper.openAlert(component);
    },
    handleConfirm: function(component, event, helper) {
        helper.callbackAndClose(component, true);
    },
    handleCancel: function(component, event, helper) {
        helper.callbackAndClose(component, false);
    }
})


({
    getPromptClass: function(promptType) {
        var promptClass = null;
        if (promptType == 'success') {
            promptClass = 'slds-theme_success';
        } else if (promptType == 'warning') {
            promptClass = 'slds-theme_warning';
        } else if (promptType == 'error') {
            promptClass = 'slds-theme_error';
        } else {
            // default
            promptClass = 'slds-theme_info';
        }
        return promptClass;
    },
    setConfiguration: function(component, config) {
        var helper = this;
        component.set('v.title', config.title);
        component.set('v.message', config.message);
        component.set('v.confirmButtonLabel', config.confirmButtonLabel);
        component.set('v.cancelButtonLabel', config.cancelButtonLabel);
        component.set('v.showConfirmButton', config.showConfirmButton || component.get('v.showConfirmButton'));
        component.set('v.showCancelButton', config.showCancelButton);
        component.set('v.inputType', config.inputType);
        component.set('v.inputLabel', config.inputLabel);
        component.set('v.inputValue', config.inputValue);
        component.set('v.inputPlaceholder', config.inputPlaceholder || component.get('v.inputPlaceholder'));
        component.set('v.promptClass', helper.getPromptClass(config.promptType));
        component.set('v.config', config);
    },
    openAlert: function(component) {
        component.set('v.isOpen', true);
    },
    closeAlert: function(component) {
        component.set('v.isOpen', false);
    },
    callbackAndClose: function(component, result) {
        var helper = this;
        helper.closeAlert(component);
        var config = component.get('v.config');
        if (config && config.callbackFn) {
            var inputType = component.get('v.inputType');
            var value = null;
            if (inputType == 'text') {
                value = component.find('text-input').get('v.value');
            }
            config.callbackFn(result, value);
        }
    }
})

Let us understand the basics of this component. This component exposes an aura:method that accepts a configuration object. We can pass various configuration attributes to make the behave as:

  1. Alert dialog

  2. Confirm dialog (Yes / No)

  3. Confirm dialog with text input

    Let us look into the configuration for some popular use cases.

Add CustomAlert Component

The first step is to add this component to our Lightning component. We can do that by adding the following line of code to our lightning component.


<c:CustomAlert aura:id=”custom-alert” />


Display an info message

There are numerous instances where we just want to display an info message and also want the user to take note of it by blocking the user interface. Instead of using the standard JavaScript alert dialog, we can use this component to display an alert dialog matching the Lightning Experience UI. Plus, this component offers the ability to render markup in the message body.

var customAlert = component.find('custom-alert');
customAlert.open({
    title: 'Info!',
    message: 'This modal contains some info message',
    confirmButtonLabel: 'OK',
    showConfirmButton: true,
    showCancelButton: false,
    promptType: 'info',
    callbackFn: function(result, userInput) {
        console.log(result, userInput);
    }
});

Prompt the user to confirm an action

Many times, we need the user to confirm the action which is going to take place to make sure the user hasn’t initiated the action accidentally. The most common place for such confirmation dialogs is when the delete button is clicked. Here is the configuration for that scenario:

var customAlert = component.find('custom-alert');
customAlert.open({
    title: 'Confirm Delete',
    message: 'Do you want to delete selected record?',
    confirmButtonLabel: 'Yes',
    cancelButtonLabel: 'No',
    showCancelButton: true,
    promptType: 'warning',
    callbackFn: function(result, userInput) {
        console.log(result, userInput);
        if (result == true) {
            // perform desired action
        }
    }
});

The key thing to note here is the callbackFn function attribute. This function accepts two parameters.

  1. result: The value of this parameter is used to identify whether the user has confirmed the action or not. If its value is true, then it means the user has confirmed the action, any other value means the user cancelled the action.
  2. userInput: We will see how this parameter is used in the next use case. Accept input from the user Sometimes, we come across a scenario where we need some input from the user before completing an action. In such cases, we can make use of this component to display a prompt with an input field. The user enters a value, clicks the confirm action button, and proceeds to complete the action. Here is how we can display such a confirm dialog:

Accept input from the user

Sometimes, we come across a scenario where we need some input from the user before completing an action. In such cases, we can make use of this component to display a prompt with an input field. The user enters a value, clicks the confirm action button, and proceeds to complete the action. Here is how we can display such a confirm dialog:


var customAlert = component.find('custom-alert');
customAlert.open({
    title: 'Success',
    confirmButtonLabel: 'Confirm',
    cancelButtonLabel: 'Cancel',
    showCancelButton: true,
    inputType: 'text',
    inputLabel: 'Enter Name',
    inputPlaceholder: 'Please enter your name',
    promptType: 'success',
    callbackFn: function(result, inputValue) {
        console.log(result, inputValue);
        if (result == true) {
            // proceed with desired action with input from user
        }
    }
});

In the previous use case, we saw that the callbackFn function accepts two parameters. We saw the first param is used to denote whether the confirm or cancel button was clicked. The second param comes into play when we are accepting input from the user, whatever user enters, is passed into this param.

Conclusion

The main reason for building the CustomAlert component was to overcome the limitations in the standard alert/confirm Lightning components. Hopefully, Salesforce will release updates to the standard components to add the missing features. Until then, we can use this component as a workaround.

If you found this helpful, please don’t hold back your upvotes, and you can follow me on Medium or Twitter for more tips and tricks related to Apex, Visualforce, Aura, Lightning Web Components, and the Salesforce platform.

If you need any help with Salesforce or have something a little more complex that might require some advanced developer knowledge, you can chat with us at https://cloudanswers.com


CloudAnswers photo
CloudAnswers
Share

About CloudAnswers

Salesforce apps, powerful components, custom development, and consulting. Our experienced team helps you to create and modify workflow processes in salesforce.

Related Articles

For Everyone

Product Launch: CloudAnswers Shop Builder

Are you looking for an easy way to launch an ecommerce shop? Our new app, Shop Builder, is now in public beta! We’re looking for companies that want to build an online shop but don’t want to spend thousands building it out.

April 12, 2024

5 Min Read

For Everyone

A Day in the Life of a Project Manager at CloudAnswers

I'm Emily, and I've been a project manager at CloudAnswers for the last two years. It can be a nebulous role, but I like to say I act as a bridge between the product vision and tangible results, whether that is building a custom app for a client or one of our own Salesforce products. My typical day revolves around managing tasks, ensuring progress, and maintaining standards while adhering to project timelines.

March 22, 2024

5 Min Read

For Everyone

5 Northeast Dreamin’ Sessions Admins You Don’t Want to Miss

Northeast Dreamin’ is the premier Salesforce User conference in the Northeastern United States and happens annually in New Hampshire. If you’re not familiar, Dreamin’ events are small regional Salesforce conferences that take place around the world. So you would expect informative sessions, but I wa

November 10, 2023

5 Min Read