How to Embed SharePoint Document Explorer in a Dynamics 365 Form

Introduction

Integrating SharePoint document libraries into Dynamics 365 allows users to manage files directly from a D365 form without navigating to SharePoint manually. This post provides a step-by-step guide on how to embed SharePoint’s document explorer into a D365 form using an iframe and dynamically set its URL based on the current record.

Key Features of This Solution

  • Retrieves the SharePoint site URL from a D365 environment variable.

  • Extracts the entity name (etn) from the current record's URL.

  • Fetches the document location's relative URL dynamically.

  • Constructs the correct SharePoint document URL, ensuring it works for all records.

  • Encodes special characters (_ to %5F, / to %2F) for compatibility.

  • Sets the iframe source dynamically on form load.

Prerequisites

  1. Enable SharePoint Integration in Dynamics 365.

  2. Ensure a document location record exists for each entity record.

  3. Set up a D365 environment variable to store the SharePoint site URL (e.g., hs_sharepointurl).

  4. Identify the iframe control name in the D365 form (e.g., IFRAME_spfiles).


Implementation Steps

1. Create an Environment Variable for SharePoint Site URL

  • Navigate to Power Apps > Solutions.

  • Click New > Environment Variable.

  • Set Schema Name to hs_sharepointurl.

  • Enter your SharePoint site URL (e.g., https://yourtenant.sharepoint.com/sites/YourSite).

  • Save and Publish.

2. Add an Iframe to Your D365 Form

  • Open Power Apps > Select your table.

  • Go to Forms > Open the desired form.

  • Add a new Iframe control.

  • Set the Name (e.g., IFRAME_spfiles).

  • Leave the URL field blank (it will be set dynamically).

  • Save and Publish.



3. Add JavaScript to Set the Iframe Dynamically

Use the following JavaScript code as a Web Resource and attach it to the OnLoad event of the form.

JavaScript Code to Dynamically Set the SharePoint Iframe

/**
 * Retrieves the value of an environment variable from D365.
 * @param {string} varName - The schema name of the environment variable.
 * @param {function(string):void} successCallback - Invoked with the variable value.
 * @param {function(string):void} errorCallback - Invoked with an error message.
 */
function getEnvironmentVariableValue(varName, successCallback, errorCallback)
{
    var query = "?$select=defaultvalue&$filter=schemaname eq '" + varName + "'";
    Xrm.WebApi.retrieveMultipleRecords("environmentvariabledefinition", query).then(
        function(result)
        {
            if (result.entities.length > 0)
            {
                successCallback(result.entities[0].defaultvalue);
            }
            else
            {
                errorCallback("Environment variable '" + varName + "' not found.");
            }
        },
        function(error)
        {
            errorCallback("Error retrieving environment variable: " + error.message);
        }
    );
}

/**
 * Debugs an environment variable by logging its value to the console.
 * @param {string} envVarName - Schema name of the environment variable.
 */
function debugEnvironmentVariable(envVarName)
{
    getEnvironmentVariableValue(envVarName,
        function(value)
        {
            console.log(envVarName + ":", value);
        },
        function(error)
        {
            console.error("Error retrieving " + envVarName + ":", error);
        }
    );
}

/**
 * Retrieves the full URL of the top-level window in UCI.
 * @returns {string} The top window URL or an empty string if inaccessible.
 */
function getTopWindowUrl()
{
    try
    {
        return window.top.location.href;
    }
    catch (e)
    {
        console.error("Unable to access top window location:", e);
        return "";
    }
}

/**
 * Extracts the 'etn' parameter from the top window's URL.
 * @returns {string|null} Entity logical name or null if not found.
 */
function getEtnFromTopWindowUrl()
{
    var topUrl = getTopWindowUrl();
    if (!topUrl)
    {
        return null;
    }
    try
    {
        var urlObj = new URL(topUrl);
        var etnValue = urlObj.searchParams.get("etn");
        return etnValue ? decodeURIComponent(etnValue) : null;
    }
    catch (e)
    {
        console.error("Error parsing top window URL:", e);
        return null;
    }
}

/**
 * Debugs the top window URL and 'etn' parameter by logging to console.
 */
function debugTopWindowUrlAndEtn()
{
    var topUrl = getTopWindowUrl();
    var etn = getEtnFromTopWindowUrl();
    console.log("Top Window URL:", topUrl);
    console.log("ETN from URL:", etn);
}

/**
 * Sets the SharePoint folder URL in a specified iframe control, using:
 * 1) The 'etn' from the top window URL,
 * 2) A SharePoint site URL from an environment variable (e.g. "hs_sharepointurl"),
 * 3) The current record's document location record.
 * Constructs a final URL of the form:
 *   [spSiteUrl]/[etn]/Forms/AllItems.aspx?id=...
 *
 * @param {ExecutionContext} executionContext - The form execution context.
 * @param {string} iframeName - Name of the iframe control on the form.
 * @param {string} envVarName - Schema name of the environment variable containing the SharePoint URL.
 */
function setCommonSharePointIframeUrl(executionContext, iframeName, envVarName)
{
    var formContext = executionContext.getFormContext();
    var iframeControl = formContext.getControl(iframeName);
    if (!iframeControl)
    {
        return;
    }
   
    var etn = getEtnFromTopWindowUrl();
    if (!etn)
    {
        console.error("No 'etn' found in top window URL. Cannot build final SharePoint URL.");
        return;
    }
   
    var recordId = formContext.data.entity.getId().replace("{", "").replace("}", "");
   
    getEnvironmentVariableValue(envVarName,
        function(spSiteUrl)
        {
            var spSiteUrlNormalized = spSiteUrl.replace(/\/+$/, "");
            var query = "?$select=relativeurl&$filter=_regardingobjectid_value eq '" + recordId + "'";
           
            Xrm.WebApi.retrieveMultipleRecords("sharepointdocumentlocation", query).then(
                function(result)
                {
                    if (result.entities.length === 0)
                    {
                        console.error("No document location found for record:", recordId);
                        return;
                    }
                   
                    var relUrl = result.entities[0].relativeurl || "";
                    // Example final path:
                    //   "/sites/CottonOn/hs_meetingregistration/Forrest3_F029BF..."
                    // Underscores and slashes must be encoded, e.g. "_" -> "%5F", "/" -> "%2F".
                    relUrl = relUrl.replace(/_/g, "%5F").replace(/\//g, "%2F");
                   
                    // Final URL:
                    //   spSiteUrlNormalized + "/" + etn + "/Forms/AllItems.aspx?id=" + relUrl
                    var finalUrl = spSiteUrlNormalized + "/" + etn + "/Forms/AllItems.aspx?id=" + relUrl;
                   
                    iframeControl.setSrc(finalUrl);
                },
                function(error)
                {
                    console.error("Error retrieving document location:", error.message);
                }
            );
        },
        function(errMsg)
        {
            console.error("Error retrieving environment variable:", errMsg);
        }
    );
}


function onLoad(executionContext)
{
    setCommonSharePointIframeUrl(executionContext, "IFRAME_spfiles", "hs_sharepointurl");
}

4. Attach the Script to the Form’s OnLoad Event

  • Navigate to Form Properties.

  • Click + Add under JavaScript Libraries.

  • Upload the Web Resource containing the script.

  • Under Event Handlers, select OnLoad and add the function:

            onLoad
  • Save and Publish.





Final Thoughts

With this setup, your D365 form will now automatically load the correct SharePoint document library based on the current record. This enhances efficiency, allowing users to manage documents seamlessly within Dynamics 365.




No comments:

Post a Comment