Saturday, August 7, 2010

The jQuery formula - Blocking UI and showing progress dialog across Ajax calls with Asp.Net MVC

This post in in continuation to my previous post where I create a progress dialog blocking the UI across asynchronous postbacks for WebForms. I will do the same thing here using Asp.Net MVC, except for the fact that there no such thing as postback in MVC, It’s all Get - Post -Put – Delete (a true web framework) . Much of the initial content will be common not identical.

The goal here is to not allow user to interact with the application, at the same time showing the user a dialog saying “Wait, let me first finish what you just asked me to do!”

The version of jQuery that I’m using is 1.4.1 (downloadable here) and the version of jQuery UI I’m using is 1.8.2(downloadable here). I’ll be using ASP.NET MVC 2.0 but this demo is valid for any web framework which allows making Ajax calls using jQuery.

The source code for this demo can be downloaded here.

Plugging in jQuery UI in to a new ASP.NET web application:

Well start with creating a new web application using Visual Studio 2010:

The application template by default contains the jQuery scripts in the /Scripts folder (I deleted the files non-relevant to this demo to minimize solution size).  jQueryUI scripts and CSS is required to be downloaded and include it in the solution via the following entries in the master page:

    <script src="../../Scripts/jquery-1.4.1.min.js" type="text/javascript"></script>    
    <script src="../../Scripts/jquery-ui-1.8.2.custom.min.js" type="text/javascript"></script>
    <link href="../../Content/jQueryUI/redmond/jquery-ui-1.8.2.custom.css" rel="stylesheet" type="text/css" />

Creating a jQuery UI dialog with the content to show

We need to create two methods one to open the jQuery dialog and the other to close it. With the intention to keep all related javascript in one place and out of the .aspx pages, I created a new JScript file called jqueryProgressDialog.js, placed it in the Scripts folder and create two methods in it:

function showProgressDialog() {

    $("#progressDialog").dialog({
        autoOpen: false,
        modal: true,
        bgiframe: true
    });

    $('#progressDialog').dialog('open');

}

function hideProgressDialog() {

    if ($('#progressDialog').dialog('isOpen')) {

        $('#progressDialog').dialog('close');
    }
}

And include this script file in our master page -

    <script src="../../Scripts/jqueryProgressDialog.js" type="text/javascript"></script>

What will be shown in the dialog box will be defines using a DIV tag with id = “progressDialog”. We will put this in the Master Page so that it is available to the while application.

    <div id="progressDialog" title="Welcome to my demo!" style="display: none;">
        <img src="../../Images/AjaxProgress.gif" alt="Processing"/>
        <p>
            Please wait while your request is processed.
        </p>
    </div>

Obviously this solution will not work for the pages that do not  inherit from this master page.

 

Calling the progress dialog while asynchronous request

To consume this infrastructure, we need to add specify out show and hide dialog functions to the start and end of a request. You can either surpass the framework’s Ajax helpers and go the jquery way making Ajax calls -

The View -

    <p>
        <input type="button" value="Click here to for a 2 seconds long asynch call" onclick="makeAnAjaxCall();" />
    </p>

    <script type="text/javascript">

        function makeAnAjaxCall() {

            $.ajax({
                type: "GET",
                url: '<%= Url.Action("SleepFor2Seconds", "Home") %>',
                data: "{}",
                cache: false,
                beforeSend: showProgressDialog,
                complete: hideProgressDialog
            });
        }
    
    </script>

The Controller:

        public bool SleepFor2Seconds()
        {
            Thread.Sleep(TimeSpan.FromSeconds(2));
            return true;
        }

Or go with the framework infrastructure for secure posting your forms.

The View -

    <div>
        <% using (Ajax.BeginForm(new AjaxOptions()
                                 {
                                     HttpMethod = "post",
                                     OnBegin = "showProgressDialog",
                                     OnComplete = "hideProgressDialog"
                                 }
                     ))
           {%>
        <fieldset>
            <legend>Some form</legend>
            <p>
                FirstName:
                <%= Html.TextBox("FirstName", "FirstName")%>
            </p>
            <p>
                LastName:
                <%= Html.TextBox("LastName", "LasName")%>
            </p>
            <%= Html.AntiForgeryToken()%>
            <p>
                <input type="submit" value="Click here to Asynchronously post this form" />
            </p>
        </fieldset>
        <% } %>
    </div>

NOTE: For the Ajax.BeginForm to work the helper script files MicrosoftAjax.js and MicrosoftMvcAjax.js are required.

    <script src="../../Scripts/MicrosoftAjax.js" type="text/javascript"></script>
    <script src="../../Scripts/MicrosoftMvcAjax.js" type="text/javascript"></script>

The Controller actions:

        [HttpGet]
        public ActionResult Index()
        {
            ViewData["Message"] = "Welcome to ASP.NET MVC!";

            return View();
        }

        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Index(FormCollection formcollection)
        {
            Thread.Sleep(TimeSpan.FromSeconds(1));
            return View();
        }

In either case, here’s the result:

jQueryProgressDialog_MVC

4 comments:

  1. Hi I really appreacite all your articles regarding MVC and jQuery dialog.
    Please continue the good work!

    Sincerely
    Mirza, Denmark

    ReplyDelete
    Replies
    1. Thank you Mirza for your kind words :)
      They are very motivating.

      Delete
  2. Hi I really appreacite all your articles regarding MVC and jQuery dialog.
    Please continue the good work!

    Sincerely
    Abdullah, Denmark

    ReplyDelete