16.5.2.2.2 Substituting Client-Side Data in Dialog URL

Following the technique covered in Providing App-Wide Helper Functions, you can add additional ones to your application's app.js JavaScript file in Static Application Files to simplify substituting client-side data in dialog URLs.

The makeDialogURL function below replaces Unicode strings like \u00e9 by their corresponding character and all occurrences of $Pnn_SOMENAME$ with the value of the Pnn_SOMENAME page item. Since the page defaults the URL template string with APEX_PAGE.GET_URL, the dollar sign will appear in its "URL-encoded" form as %24. So, the regular expression that looks for the page item name placeholders uses this variant of the name delimiter:
function makeDialogURL(url) {
    // replace unicode escapes like \u00e9
    url = url.replace(/\\u([0-9a-fA-F]{4})/g, (_, h) =>
        String.fromCharCode(parseInt(h, 16))
    );

    // Replace %24Pnn_SOMENAME%24 with encodeURIComponent($v('Pnn_SOMENAME'))
    // Regex finds %24<identifier>%24 where identifier = letters, digits, underscore
    url = url.replace(/%24([A-Za-z0-9_]+)%24/g, function (_, p1) {
        const val = $v(p1);
        return encodeURIComponent(val != null ? val : "");
    });

    return url;
}

The openDialogURLWithClientPageItemPlaceholders function calls the private makeDialogURL function above, then opens the dialog using the openDialogURL function explained in Opening Dialog URL Passing Client Data.

Tip:

The openDialogURLWithClientPageItemPlaceholders function uses a handy JavaScript feature to accept "destructured" arguments. This lets you specify default values for different optional parameters. It also lets a caller pass parameters using a named notation. Default values assigned in the function get automatically used if the caller omits those optional parameters.

// In app.js static application file
//----------------------------------------------------
// Substitute $PNN_NAME$ placeholders and open modal dialog
//----------------------------------------------------
function openDialogURLWithClientPageItemPlaceholders({
    urlTemplate,
    title,
    width = 400,
    maxWidth = 1000,
    triggeringElement = $('body')[0]
}) {
    openDialogURL({
        url : makeDialogURL(urlTemplate),
        title: title,
        height: height,
        width: width,
        maxWidth: maxWidth,
        triggeringElement : triggeringElement
    });
}
The openDrawerURLWithClientPageItemPlaceholders function is similar but calls openDrawerURL instead passing fewer parameters:
// In app.js static application file
//----------------------------------------------------
// Substitute $PNN_NAME$ placeholders and open drawer
//----------------------------------------------------
function openDrawerURLWithClientPageItemPlaceholders({
    urlTemplate,
    title,
    width = 400,
    triggeringElement = $('body')[0]
}) {
    openDrawerURL({
        url : makeDialogURL(urlTemplate);
        title: title,
        width: width,
        triggeringElement : triggeringElement
    });
}

The full source of the Woods HR application's app.js file appears below. It's included in the File URLs setting on the JavaScript tab of the Shared Components > User Interface Attributes using its reference string #APP_FILES#app#MIN#.js from the Static Application Files list page.

// Export single global symbol "app" to keep code clean
const app = (function ($) {

    // --- Private Functions ---

    function makeDialogURL(url) {
        // replace unicode escapes like \u00e9
        url = url.replace(/\\u([0-9a-fA-F]{4})/g, (_, h) =>
            String.fromCharCode(parseInt(h, 16))
        );

        // Replace %24Pnn_SOMENAME%24 with encodeURIComponent($v('Pnn_SOMENAME'))
        // Regex finds %24<identifier>%24 where identifier = letters, digits, underscore
        url = url.replace(/%24([A-Za-z0-9_]+)%24/g, function (_, p1) {
            const val = $v(p1);
            return encodeURIComponent(val != null ? val : "");
        });

        return url;
    }

    // --- Public Functions (returned below!) ---

    //----------------------------------------------------
    // Set the title of the current dialog window 
    //----------------------------------------------------
    function setDialogTitle(title) {
        apex.util.getTopApex()
        .jQuery(".ui-dialog-content")
        .dialog("option", "title", title);
    }

    //----------------------------------------------------
    // Return true if x and y are different, treating null
    // and empty string as equivalent in the comparison 
    //----------------------------------------------------
    function areDifferent(x, y) {
        return (x || '') !== (y || '');
    }

    //----------------------------------------------------
    // Open modal dialog
    //----------------------------------------------------
    function openDialogURL({
        url,
        title,
        width = 400,
        maxWidth = 1000,
        triggeringElement = $('body')[0]
    }) {
        apex.navigation.dialog(
        url,
        {
            title: title,
            height: "auto",
            width: width,
            maxWidth: maxWidth,
            modal: true,
            resizable: true
        },
        "t-Dialog-page--standard",
        triggeringElement
        );
    }

    //----------------------------------------------------
    // Open Drawer URL
    //----------------------------------------------------
    function openDrawerURL({
        url,
        title,
        width = 400,
        triggeringElement = $('body')[0]
    }) {
        apex.navigation.dialog(
        url,
        {
            title: title,
            width: width,
            modal: true
        },
        "t-Drawer-page--standard t-Drawer--pullOutEnd",
        triggeringElement
        );
    }

    //----------------------------------------------------
    // Substitute $PNN_NAME$ placeholders and open modal dialog
    //----------------------------------------------------
    function openDialogURLWithClientPageItemPlaceholders({
        urlTemplate,
        title,
        width = 400,
        maxWidth = 1000,
        triggeringElement = $('body')[0]
    }) {
        openDialogURL({
            url : makeDialogURL(urlTemplate),
            title: title,
            height: height,
            width: width,
            maxWidth: maxWidth,
            triggeringElement : triggeringElement
        });
    }

    //----------------------------------------------------
    // Substitute $PNN_NAME$ placeholders and open drawer
    //----------------------------------------------------
    function openDrawerURLWithClientPageItemPlaceholders({
        urlTemplate,
        title,
        width = 400,
        triggeringElement = $('body')[0]
    }) {
         openDrawerURL({
            url : makeDialogURL(urlTemplate),
            title: title,
            width: width,
            triggeringElement : triggeringElement
        });
    }

    // Only these functions are exposed to JavaScript code
    // in APEX pages; everything else stays private.
    return {
        setDialogTitle,
        areDifferent,
        openDialogURL,
        openDrawerURL,
        openDrawerURLWithClientPageItemPlaceholders,
        openDialogURLWithClientPageItemPlaceholders
    };

  // Ensure $ in app namespace resolves to correct jQuery
})(apex.jQuery);