docusignapidocusignconnectdocusign-sdkdocusignapextoolkit

mount() method from the DocusignJS library requires Id attribute, but LWC in Salesforce can't have fixed Id values


I am trying to build an embedded signing experience inside a Salesforce Experience Cloud Site from an LWC, and I tried to follow the documentation to build an LWC that can do the same. Here is the relevant LWC code -

import { LightningElement } from 'lwc';

import sendEnvelope from '@salesforce/apex/DocusignEmbeddedSigningController.sendEnvelope';
import getEmbeddedSigningUrl from '@salesforce/apex/DocusignEmbeddedSigningController.getEmbeddedSigningUrl';

import docusignjs from "@salesforce/resourceUrl/docusignjs";
import { loadScript } from "lightning/platformResourceLoader";

export default class DocusignEmbeddedSigning extends LightningElement {

    template = '2d749f04-1bdb-4b70-9cef-64ab148c6ba0';
    description = 'Embedded Signing';

    renderedCallbackExecuted = false;

    async renderedCallback() {
        if (this.renderedCallbackExecuted) {
            return;
        }
        this.renderedCallbackExecuted = true;

        await Promise.all([
            loadScript(this, docusignjs)
        ]);

        let envelopeId = await sendEnvelope({template: this.template, description: this.description}); 
        let signingUrl = await getEmbeddedSigningUrl({envId: envelopeId, url: window.location.href});

        let docuSignObj = await window.DocuSign.loadDocuSign();
        
        const signing = docuSignObj.signing({
            url: signingUrl,
            displayFormat: 'focused',
            style: {
                /** High-level variables that mirror our existing branding APIs. Reusing the branding name here for familiarity. */
                branding: {
                    primaryButton: {
                        /** Background color of primary button */
                        backgroundColor: '#333',
                        /** Text color of primary button */
                        color: '#fff',
                    }
                },

                /** High-level components we allow specific overrides for */
                signingNavigationButton: {
                    finishText: 'You have finished the document! Hooray!',
                    position: 'bottom-center'
                }
            }
        });

        signing.on('ready', (event) => {
            console.log('UI is rendered');
        });

        signing.on('sessionEnd', (event) => {
            /** The event here denotes what caused the sessionEnd to trigger, such as signing_complete, ttl_expired etc../ **/
            console.log('sessionend', event);
        });

        signing.mount(this.template.querySelector('.docusign-agreement-container'));
    }
}

The problem is with the sigining.mount() method. As per documentation (https://www.docusign.com/blog/developers/15-minutes-to-better-ux-enhancing-embedded-signing-focused-view, and https://developers.docusign.com/docs/esign-rest-api/how-to/request-signature-focused-view/), this method is supposed to receive an Id based selector.

But unfortunately, the LWC framework does not allow developers to provide their values in the ID attribute of HTML elements and will override them with dynamically generated values (which is why I attempted to use this.template.querySelector to use a CSS based selector)

The get the following error with the above approach - [n.template.querySelector is not a function]

I then attempted this - signing.mount('.docusign-agreement-container');, and now the error I get is this in the browser console - [DocuSign JS] Container element not found: ".docusign-agreement-container"

Question - Can the mount() method receive a different argument other than Id attributes? Otherwise, using the DocuSignJS library to embed signing experience within Salesforce Experience Cloud is not possible (or extremely difficult).


Solution

  • iFrames have their own concerns and do need in depth testing. Please read here for issues with iFrames https://www.docusign.com/blog/developers/the-problems-iframes

    If you do want to go ahead with iFrames, then here are steps to allow a redirect in Experience Cloud for Docusign (avoiding the window within a window).

    1. Create a Visualforce page, called for example "docusignRedirect.vfp", with this code:

    <apex:page showHeader="false" sidebar="false" standardStylesheets="false"
        applyHtmlTag="false" applyBodyTag="false" docType="html-5.0" showQuickActionVfHeader="false">
    
    <html>
        
    
        <body onload="redirect()">
            <script>   
                function redirect(){
                    window.top.location.href = '[redirect url]';
                }                    
            </script>
            
        </body>
    </html>
    </apex:page>

    1. in Experience Cloud Site "Builder", add a new Theme, call it "NoHeader" (untick "Show header"): Add theme with no header

    2. Create a new page, call it "redirect". Add the visualforce page "DocusignRedirect" into the body:

    redirect page

    1. Apply the custom "NoHeader" them to this page: Add custom NoHeader theme

    2. Now you have a redirect url that you can place into the Apex controller. eg: 'https://example.my.site.com/s/redirect'. Code example below

    global static String getEmbeddedSigningURL(final String envelopeId, final Id sourceObjectId) {
                
            String myReturnUrl='https://example.my.site.com/s/redirect'; //REPLACE WITH YOUR REDIRECT SITE
             Url mySigningUrl = dfsle.SigningService.getEmbeddedSigningUrl(
                                    dfsle.UUID.parse(envelopeId), // DocuSign envelope ID
                                    new Url(myReturnUrl)); // Where to redirect the user upon signing completion.        
            return mySigningUrl.ToExternalForm();                           
        }