DEV Community

Debajyoti Das
Debajyoti Das

Posted on • Edited on

Custom Salesforce LWC modal with navigation

We are using Salesforce's 'lightning/modal' component to build modals as it has all standard functionalitites with the additional functionalities which will always make is scalable.

The modal component file:
js file:

import { api } from 'lwc';
import LightningModal from 'lightning/modal';

export default class LwcModal extends LightningModal {
    @api content;
    @api header;
    @api navigateToLead=false;
    @api leadId;

    handleClose() {
        this.close('okay');
        console.log("myModal onnavigatetoLead is called");
        this.navigateToLead=false;
    }

    //navigation cannot be done from here it needs to be done through an event and a child component
}

Enter fullscreen mode Exit fullscreen mode

html file:

<template>
    <lightning-modal-header label={header}></lightning-modal-header>
    <lightning-modal-body> {content} 

    </lightning-modal-body>
    <lightning-modal-footer>
        <lightning-button variant="destructive-text" label="Close" class="slds-var-m-around_medium" onclick={handleClose}></lightning-button>

        <template lwc:if={navigateToLead}>
            <c-nav-to-lead-modal onnavigatetolead={handleClose} lead-id={leadId}></c-nav-to-lead-modal>
        </template>
    </lightning-modal-footer>
</template>
Enter fullscreen mode Exit fullscreen mode

As per my use case I required a button which when clicked will the modal should close and the page should navigate to the supplied lead detail page.

The navigation works differntly on a modal when compared to a normal lwc page, the navigation requires an event to be fired and also requires a child component which makes the navigation work, you can find more on it here:

Below is the child compoenent which contains the navigation settings:
js file:

import { LightningElement, api } from 'lwc';

export default class NavToLeadModal extends LightningElement {
    @api leadId;

    navigateToLead()
    {
        const pageRef = {
            type: "standard__recordPage",
            attributes: {
                recordId: this.leadId,
                objectApiName: "Lead",
                actionName: "view",
            },
        };

        const evt = new CustomEvent("navigatetolead", {
            bubbles: true,
            composed: true,
            detail: pageRef
        });

        this.dispatchEvent(evt);
    }
}
Enter fullscreen mode Exit fullscreen mode

html file:

<template>
    <lightning-button
        variant="brand"
        label="Go To Lead"
        class="slds-var-m-around_medium"
        onclick={navigateToLead}
    ></lightning-button>
</template>
Enter fullscreen mode Exit fullscreen mode

I had to use a Platform event which when received, triggerred the modal as it was part of a notification system. So the following code is of the parent component which subscribes to the empApi when the matching Platform event is received. Attaching the parent component's code below:

js file:

import { LightningElement, wire, track } from 'lwc';
import LwcModal from 'c/lwcModal';
import USER_ID from '@salesforce/user/Id';
import { subscribe as empSubscribe, unsubscribe as empUnsubscribe, onError } from 'lightning/empApi';
import { NavigationMixin } from "lightning/navigation";

export default class LeadNotifier extends NavigationMixin(LightningElement) {
    result;
    showModal = false;
    message = '';
    leadId;
    currentUserId = USER_ID;
    subscription = {};
    channelName = '/event/LeadAssignment_PlatformEvent__e';


    connectedCallback() 
    {
        console.log('LeadNotifier component connected');
        this.registerErrorListener();
        this.subscribeToEvent();
    }

    subscribeToEvent() {
        empSubscribe(this.channelName, -1, (response) => {
            const payload = response.data.payload;
            console.log('Received PE:', JSON.stringify(payload));

            const userId = payload.User__c;
            const leadId = payload.Lead__c;
            const msg = payload.Message__c;

            if (userId === this.currentUserId) {
                this.message = msg;
                this.leadId = leadId;
                this.showModal = true;
                this.handleClick(this.message, this.leadId);
            }
        }).then((response) => {
            console.log('Subscribed to channel ', response.channel);
            this.subscription = response;

        });
    }

    registerErrorListener() {
        onError((error) => {
            console.error('EMP API error:', JSON.stringify(error));
        });
    }

    async handleClick(mssg, leadId) {

        console.log('In handleClick method, mssg: ', mssg);
        const result = await LwcModal.open({
            // `label` is not included here in this example.
            // it is set on lightning-modal-header instead
            size: 'small',
            description: 'Accessible description of modal\'s purpose',
            content: mssg,
            header: 'Lead Notification - Round Robin',
            navigateToLead: true,
            leadId: leadId,
            onnavigatetolead : (e) => {
                this[NavigationMixin.Navigate](e.detail);
            },
        });
        //onnavigatetolead event needs to be called to make the navigation to lead detail page happen

        // if modal closed with X button, promise returns result = 'undefined'
        // if modal closed with OK button, promise returns result = 'okay'
        console.log(result);
        this.result = result;
    }
}
Enter fullscreen mode Exit fullscreen mode

html file:

<template>
    <template lwc:if={showModal}>
        <p>RR notif showed up!</p>
    </template>    
</template>
Enter fullscreen mode Exit fullscreen mode

meta file:

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>64.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
        <target>lightning__UtilityBar</target>
        <target>lightning__RecordPage</target>
        <target>lightning__RecordAction</target>
    </targets>
</LightningComponentBundle>
Enter fullscreen mode Exit fullscreen mode

Below is the image of the component:

Top comments (0)