Creating a Loading Panel in Dynamics CRM Forms

On many occasions, I had to create ribbon button to perform business logic that sometimes takes time to complete and/or execute. One of the comment that I always get in these situations is that it’s annoying from an end user’s perspective not to know what is happening. This is true, the UI kind of freezes for a few seconds and then everything comes back to normal, users are never sure what to do during this time and it sometimes results on them trying to refresh the page or click on the button multiple times. Here I am sharing one way to build a modal loading panel on top of a CRM form that I use very often. It’s a fairly simple thing to do if you are opened to using jQuery.

The idea is to use jQuery to add a hidden HTML block (the loading panel) to the CRM form, this is done in the function called InitializeLoadingPanel. Then you add 2 methods, one to show the HTML block and another one to hide it. You can refer to the Jscript code below for the 3 functions.

function InitializeLoadingPanel() {

    if ($("body").find("#panel").length > 0) {
        return;
    }

    var displayText = "Working...";

    // Loading Panel
    $('body').append('<div id="panel"></div>');

    // Loading Panel Content Div
    $('body').append('<div id="contentDiv"></div>');

    $("#panel").hide()
               .css({ 'position': 'absolute', 'top': '0', 'left': '0', 'width': '100%', 'height': '100%', 'background-color': '#FFFFFF' });

     $("#contentDiv").append('<p id="loadingText">' + displayText + '</p>')
                    .hide()
                    .css({ 'background-color': '#DDDDDD', 'height': '100px', 'width': '300px' });

    // Setup your text css
    $("#loadingText").css({ "text-align": "center", "margin-top": "50px", "font": "12px bold" });

}

// Open the Loading Panel
function OpenLoadingPanel(callback) {

    // Make sure you Initialize the loading panel
    if ($("body").find("#panel").length <= 0) {
        InitializeLoadingPanel();
    }

    var panel = $("#panel");
    var panelContent = $("#contentDiv");
    var pageHeight = $(document).height();
    var pageWidth = $(window).width();

    panelContent.css("position", "absolute");
    panelContent.css("top", ((pageHeight - panelContent.outerHeight()) / 2) + $(document).scrollTop() + "px");
    panelContent.css("left", ((pageWidth - panelContent.outerWidth()) / 2) + $(window).scrollLeft() + "px");

    panel.css({ "z-index": 1000 });
    panelContent.css("z-index", 1001);

    if (callback != null) {
        panel.fadeTo("fast", 0.8, function () {
            panelContent.fadeIn(10, function () {
                setTimeout(callback, 10);
            });
        });
    }
    else {
        panel.fadeTo("fast", 0.8, function () {
            panelContent.fadeIn(10);
        });
    }
}

// Close the Loading Panel by hiding it
function CloseLoadingPanel() {

    $("#contentDiv").fadeOut("fast", function () {
        $("#panel").fadeOut(0, function () {
            ("#contentDiv").hide();
            });
    });
}

That’s good for starters. Now in order to test this, I have written a very simple function that simple opens the loading panel and sleeps for a few seconds in order for us to see the loading panel on the screen.

// In this example, I call this method on the OnChange event of a custom field in order
// to display the loading panel. In the past, I've had to use this in different cases
// from ribbon button to on change of field value. It really depends on what you are doing in your
// Javascript code.
function DisplayLoadingPanel() {

    OpenLoadingPanel();
    window.setTimeout(CloseLoadingPanel, 6000);
}

And now let’s take a look at the result. As I am mentioning in the comments on the code block above, in this example I set the DisplayLoadingPanel method to be called on the On Change event of a field on my form. Typically, you can have the loading panel displayed whenever you need. Here is what it looks like:

You can play around with the css to add an image to the loading block and do all sorts of things with the look and feel. This is all supported in theory (my example is running in CRM Online). Note that in order for this to work, you need to have a Jscript web resource with jQuery registered in the form before the script in which the loading panel is initialized, displayed and hidden.

Hope this helps!

Advertisements

9 thoughts on “Creating a Loading Panel in Dynamics CRM Forms

  1. Hi ;
    good blog but there is one problem when i click the button (which is custom doing update of the field)the loading panel does not come immediately it comes when the the process as finished …

      • Hi ;

        here is the code it is Running on the custom button click

        function get_values()
        {
        OpenLoadingPanel();

        var bol=true;
        var authenticationHeader = GenerateAuthenticationHeader();
        var xml = “”+
        “”+
        authenticationHeader+
        “”+
        “”+
        “”+
        “”+bol+””+

        “”+Xrm.Page.data.entity.getId()+””+
        “”+
        “”+
        “”+
        “”;
        // Prepare the xmlHttpObject and send the request.
        var xHReq = new ActiveXObject(“Msxml2.XMLHTTP”);
        xHReq.Open(“POST”, “/mscrmservices/2007/CrmService.asmx”, false);
        xHReq.setRequestHeader(“SOAPAction”,”http://schemas.microsoft.com/crm/2007/WebServices/Update”);
        xHReq.setRequestHeader(“Content-Type”, “text/xml; charset=utf-8”);
        xHReq.setRequestHeader(“Content-Length”, xml.length);
        xHReq.send(xml);
        // Capture the result
        var resultXml = xHReq.responseXML;

        // Check for errors.
        var errorCount = resultXml.selectNodes(‘//error’).length;
        if (errorCount != 0)
        {
        var msg = resultXml.selectSingleNode(‘//description’).nodeTypedValue;
        alert(“description”+” “+msg);
        }

        }

        function InitializeLoadingPanel() {

        if ($(“body”).find(“#panel”).length > 0) {
        return;
        }

        var displayText = “Working…”;

        // Loading Panel
        $(‘body’).append(”);

        // Loading Panel Content Div
        $(‘body’).append(”);

        $(“#panel”).hide()
        .css({ ‘position’: ‘absolute’, ‘top’: ‘0’, ‘left’: ‘0’, ‘width’: ‘100%’, ‘height’: ‘100%’, ‘background-color’: ‘#FFFFFF’ });

        $(“#contentDiv”).append(” + displayText + ”)
        .hide()
        .css({ ‘background-color’: ‘#DDDDDD’, ‘height’: ‘100px’, ‘width’: ‘300px’ });

        // Setup your text css
        $(“#loadingText”).css({ “text-align”: “center”, “margin-top”: “50px”, “font”: “12px bold” });

        }

        // Open the Loading Panel
        function OpenLoadingPanel(callback) {

        // Make sure you Initialize the loading panel
        if ($(“body”).find(“#panel”).length <= 0) {
        InitializeLoadingPanel();
        }

        var panel = $("#panel");
        var panelContent = $("#contentDiv");
        var pageHeight = $(document).height();
        var pageWidth = $(window).width();

        panelContent.css("position", "absolute");
        panelContent.css("top", ((pageHeight – panelContent.outerHeight()) / 2) + $(document).scrollTop() + "px");
        panelContent.css("left", ((pageWidth – panelContent.outerWidth()) / 2) + $(window).scrollLeft() + "px");

        panel.css({ "z-index": 1000 });
        panelContent.css("z-index", 1001);

        if (callback != null) {
        panel.fadeTo("fast", 0.8, function () {
        panelContent.fadeIn(10, function () {
        setTimeout(callback, 10);
        });
        });
        }
        else {
        panel.fadeTo("fast", 0.8, function () {
        panelContent.fadeIn(10);
        });
        }
        }

        // Close the Loading Panel by hiding it
        function CloseLoadingPanel() {

        $("#contentDiv").fadeOut("fast", function () {
        $("#panel").fadeOut(0, function () {
        ("#contentDiv").hide();
        });
        });
        }

      • I see what’s happening here… In order for this to work in your case, you should make your web service request asynchronously. You can use the $.ajax jQuery method instead of the xHReq.send(xml).

      • Here is my script:
        function StartMetadataDropDown() {
        OpenLoadingPanel();
        var iframeObjId = “IFRAME_MetadataDropDown”,
        iframeObject = window.Xrm.Page.ui != null ? window.Xrm.Page.getControl(iframeObjId) : window.parent.Xrm.Page.getControl(iframeObjId);
        var serverUrl = window.Xrm.Page.ui != null ? window.Xrm.Page.context.getClientUrl() : window.parent.Xrm.Page.context.getClientUrl();
        var strUrl = serverUrl + “/WebResources/MetaDataDropDown”;
        iframeObject.setSrc(strUrl);
        CloseLoadingPanel();
        }
        Found this http://blogs.msdn.com/b/crm/archive/2015/04/29/microsoft-dynamics-crm-online-2015-update-1-new-form-rendering-engine.aspx
        Examples of things that will break: Creating a new HTML content in the parent window for persistent content (and assumed that the parent window was the main CRM iframe).

        So I moved loading panel to html page “MetaDataDropDown” and now it works perfect, while in previous crm versions, if I use loading panel not in script but in html page, it starts when the process is finished ( as in previous comment).

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s