Click here to Skip to main content
Click here to Skip to main content

An Example to Use jQuery Global AJAX Event Handlers

, 2 Apr 2013 CPOL
Rate this:
Please Sign up or sign in to vote.
This article presents an example to use jQuery global AJAX event handlers.

Introduction 

This article presents an example to use jQuery global AJAX event handlers.

Background  

jQuery provides a list of global AJAX event handlers. These global events are fired on each AJAX request if the global property in jQuery.ajaxSetup() is true, which it is by default.

  • .ajaxStart - Register a handler to be called when the first AJAX request begins; 
  • .ajaxSend - Attach a function to be executed before an AJAX request is sent;
  • .ajaxError - Register a handler to be called when AJAX requests complete with an error;
  • .ajaxSuccess - Attach a function to be executed whenever an AJAX request completes successfully; 
  • .ajaxComplete - Register a handler to be called when AJAX requests complete;
  • .ajaxStop - Register a handler to be called when all AJAX requests have completed.

It is ideal to put some operations that are common to all AJAX requests in these event handlers to simplify the implementation of each request. In this article, I will show you how to use these event handlers to achieve the following:

  • Display a busy icon and block the UI whenever an AJAX request is in process;
  • Display an error message whenever an AJAX error is encountered;
  • Re-direct the user to the login page if the web session expires when an AJAX request is made.

The attached project is an MVC 3 application developed in Visual Studio 2010. 

This example application uses the following JavaScript libraries:

  • jquery-1.7.2.min.js - The latest version of jQuery when the example was developed.
  • jquery.blockUI-2.39.js - The jQuery BlockUI plugin. This plug-in is used to display the busy icon and block the UI while an AJAX request is in process.
  • jquery.colorbox-min.js - The "ColorBox" plug-in. This plugin is used to display a message when an AJAX error is encountered.

Besides these JavaScript libraries, the example application has the following major components:

  • The AjaxGlobalHandler.js file is the place where the jQuery global event handlers are used;
  • The Login\Index.cshtml file is the web page where users can log in to the web application;
  • The Home\Index.cshtml file is the web page where the functions implemented in the AjaxGlobalHandler.js file are used;
  • The ActionFilters\AjaxSessionActionFilter.cs file implements an Action Filter. It will be used to check the user's log-in session. If the session expires, it will either re-direct the web page to the log-in page or send the predefined status code to the caller depending on whether the controller action is accessed by an AJAX request.
  • The LoginController.cs and HomeController.cs files are the controller for the two web pages.

I will first introduce the AjaxGlobalHandler.js file and the Action Filter implemented in the ActionFilters\AjaxSessionActionFilter.cs file. I will then show you how to use them in the web pages.

The "AjaxGlobalHandler.js" File  

The AjaxGlobalHandler.js file is a very simple JavaScript file, which is implemented as the follows: 

var AjaxGlobalHandler = {
    Initiate: function (options) {
        $.ajaxSetup({ cache: false });
    
        // Ajax events fire in following order
        $(document).ajaxStart(function () {
            $.blockUI({
                message: options.AjaxWait.AjaxWaitMessage,
                css: options.AjaxWait.AjaxWaitMessageCss
            });
        }).ajaxSend(function (e, xhr, opts) {
        }).ajaxError(function (e, xhr, opts) {
            if (options.SessionOut.StatusCode == xhr.status) {
                document.location.replace(options.SessionOut.RedirectUrl);
                return;
            }
    
            $.colorbox({ html: options.AjaxErrorMessage });
        }).ajaxSuccess(function (e, xhr, opts) {
        }).ajaxComplete(function (e, xhr, opts) {
        }).ajaxStop(function () {
            $.unblockUI();
        });
    }
};

Although jQuery has six global AJAX events, to achieve the goals of this example, I only used the .ajaxStart, .ajaxError, and .ajaxStop events. In this example, I provided an empty handler for each of the rest of the events. The purpose of the empty handlers is simply keeping a record here, in case we may need to use them in some other projects later.

  • In the .ajaxSetup event, the BlockUI is initiated to show the user that an AJAX request is in process. It also blocks the possible user interactions.
  • In the .ajaxError event, the code checks if the error is because of the web session is expired. If it is, it re-directs the page to the log in page. Otherwise, an error message is shown in the ColorBox.
  • In the .ajaxStop event, the BlockUI is removed to tell the user that the AJAX request has completed. 

Before showing you how to use this small JavaScript file, I will introduce to you the Action Filter first. 

The "AjaxSessionActionFilter.cs" File 

The AjaxSessionActionFilter.cs file implements an Action Filter

using System.Web.Mvc;
using AjaxGlobalEventExample.Constants;
    
namespace AjaxGlobalEventExample.ActionFilters
{
    public class AjaxSessionActionFilter : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            var request = filterContext.HttpContext.Request;
            var response = filterContext.HttpContext.Response;
            var session = filterContext.HttpContext.Session;
    
            if (session[SessionVariables.IsLoggedIn] == null)
            {
                if (request.IsAjaxRequest())
                {
                    response.StatusCode = 590;
                }
                else
                {
                    var url = new UrlHelper(filterContext.HttpContext.Request.RequestContext);
                    response.Redirect(url.Action("Index", "Login"));
                }
    
                filterContext.Result = new EmptyResult();
            }
    
            base.OnActionExecuting(filterContext);
        }
    }
}

When configured properly, this Action Filter will be executed before the controller actions. If the web session does not exist and,

  • If the request is an AJAX request, it will send the status code 590 to the client;
  • If the request is a regular web request, it will re-direct the page to the login page. 

The status code 590 is a custom defined status code. By sending this code to the client, the client will recognize that the web session does not exist. 

The Login Page and the Controller  

The Login\Index.cshtml file is implemented as follows:

@{ Layout = null; }
    
<!DOCTYPE html>
    
<html>
<head>
    <title>Login</title>
    <link href="@Url.Content("~/Content/Site.css")" 
              rel="stylesheet" type="text/css" />
    
    <style type="text/css">
        .outerdiv {width: 100%;}
        .innerdiv {width: 250px; margin-left: auto; margin-right: auto;}
    </style>
        
    <script type="text/javascript">
        function Login() {
            document.location.replace('@Url.Action("LoginAction", "Login")');
        }
    </script>
</head>
<body>
    <div class="outerdiv">
        <div class="innerdiv">
            <table style="margin: 0px">
                <tr><td style="text-align: center">Everyone is welcome to login</td></tr>
                <tr>
                    <td style="text-align: center">
                        <a href="#" class="CoolButton" style="width: 200px"
                           onclick="return Login()">Click to log in</a>
                    </td>
                </tr>
            </table>
        </div>
    </div>
</body>
</html>

This cshtml page has only one button. Clicking on this button will call the LoginAction action method implemented in the LoginController.cs file:

using System.Web.Mvc;
using AjaxGlobalEventExample.Constants;
	
namespace AjaxGlobalEventExample.Controllers
{
    public class LoginController : Controller
    {
        public ActionResult Index()
        {
            return View();
        }
	
        public ActionResult LoginAction()
        {
            // Any request to login is granted and session is set
            Session[SessionVariables.IsLoggedIn] = true;
            return new RedirectResult(Url.Action("Index", "Home"));
        }
    }
}

For simplicity, the LoginAction method does not require any user credential. It simply initiates the web session. This means that any one will be able to log in to the web application. Once the web session is established, the user is re-directed to the Home\Index.cshtml page.  

The "Home\Index.cshtml" Page and the Controller 

The Home\Index.cshtml page is implemented as follows:  

@{ Layout = null; }
    
<!DOCTYPE html>
    
<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>Global Ajax Event Handler</title>
            
        <link href="@Url.Content("~/Content/Site.css")"
            rel="stylesheet" type="text/css" />
        <link href="@Url.Content("~/Content/ColorBox/colorbox.css")"
            rel="stylesheet" type="text/css" />
            
        <script src="@Url.Content("~/Scripts/jquery/jquery-1.7.2.min.js")"
            type="text/javascript"></script>
        <script src="@Url.Content("~/Scripts/ColorBox/jquery.colorbox-min.js")"
            type="text/javascript"></script>
        <script src="@Url.Content("~/Scripts/jquery/jquery.blockUI-2.39.js")"
            type="text/javascript"></script>
        <script src="@Url.Content("~/Scripts/AjaxGlobalHandler.js")"
            type="text/javascript"></script>
    
        <script type="text/javascript">
            var waitimageUrl = '@Url.Content("~/Content/images/Wait.gif")';
            var sessionoutRedirect = '@Url.Action("Index", "Login")';
            $(document).ready(function () {
                var options = {
                    AjaxWait: {
                        AjaxWaitMessage: "<img style='height: 40px' src='"
                            + waitimageUrl + "' />",
                        AjaxWaitMessageCss: { width: "50px", left: "45%" }
                    },
                    AjaxErrorMessage: "<h6>Error! please contact the monkey!</h6>",
                    SessionOut: {
                        StatusCode: 590,
                        RedirectUrl: sessionoutRedirect
                    }
                };
    
                AjaxGlobalHandler.Initiate(options);
            });
        </script>
            
        <script type="text/javascript">
            var urlSuccess = '@Url.Action("ExampleAjaxAction", "Home")';
            var urlError = '@Url.Action("ExampleAjaxError", "Home")';
            var urlClearSession = '@Url.Action("ExampleAjaxClearSession", "Home")';
    
            $(document).ready(function () {
                $("#btnSuccessAjax").click(function () {
                    $.ajax({
                        url: urlSuccess,
                        success: function (data) {
                            $("#divMessage").html(data.Message);
                        }
                    });
                });
    
                $("#btnErrorAjax").click(function () {
                    $.ajax({ url: urlError });
                });
    
                $("#btnClearSession").click(function () {
                    $.ajax({
                        url: urlClearSession,
                        success: function (data) {
                            $("#divMessage").html(data.Message);
                        }
                    });
                });
    
            });
        </script>
    </head>
    
    <body>
        <div id="divMessage" style="font-weight: bold; color: green"></div>
        <div style="margin-top: 5px">
            <a href="#" class="CoolButton" id="btnSuccessAjax">Success Call</a>
            <a href="#" class="CoolButton" id="btnErrorAjax">Error Call</a>
            <a href="#" class="CoolButton" id="btnClearSession">Clear Session</a>
        </div>
    </body>
</html> 

This page references the AjaxGlobalHandler.js file. The jQuery global event handlers are initiated in the $(document).ready() event. The handlers are initiated with the following information:

  • What image we want to show when an AJAX request is in process;
  • What message we want to display when an error occurs during an AJAX call;
  • Which page to re-direct the user to when the web session expires.

This page also has three buttons. Clicking on each button will make an AJAX call to the corresponding action method implemented in the HomeController.cs class:

using System;
using System.Threading;
using System.Web.Mvc;
using AjaxGlobalEventExample.ActionFilters;
    
namespace AjaxGlobalEventExample.Controllers
{
    [AjaxSessionActionFilter]
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            return View();
        }
    
        public ActionResult ExampleAjaxAction()
        {
            Thread.Sleep(500);
            string msg = "Ajax call succeeded @ " + DateTime.Now.ToLongTimeString();
            return Json(new { Message = msg }, JsonRequestBehavior.AllowGet);
        }
    
        public ActionResult ExampleAjaxError()
        {
            Thread.Sleep(500);
            // Return the famous 500 staus to create an artificial error
            Response.StatusCode = 500;
            Response.End();
            return new EmptyResult();
        }
    
        public ActionResult ExampleAjaxClearSession()
        {
            Thread.Sleep(500);
            Session.Clear();
            string msg = "Web session cleared @ " + DateTime.Now.ToLongTimeString();
            return Json(new { Message = msg }, JsonRequestBehavior.AllowGet);
        }
    }
}
  • The ExampleAjaxAction method simply returns a JSON object telling that the AJAX request is successful;
  • The ExampleAjaxError method sends the famous status code 500 to the client indicating an AJAX error;
  • The ExampleAjaxClearSession method clears the web session.

I artificially added a half second delay in each action method so that the web application can better show us the AJAX request process. You should also have noticed that this controller class is annotated with the AjaxSessionActionFilter Action Filter that has been implemented earlier. 

Run the Application 

Now we complete this example web application and we can test run it. 

When the application starts, since no web session exists, the user is re-directed to the log-in page. If we click on the "Click to log in" button, the web session is established and we come to the application's main page. 

If we click on the "Success Call" button, an AJAX call is made and we can see the UI is blocked and the busy icon is shown.

If we click on the "Error Call" button, an artificial AJAX error occurs, and the error message is shown up.  

We can click on the "Clear Session" button to clear the web session.  

Since we have cleared the web session, clicking on any of the buttons will re-direct us to the log-in page.  

Points of Interest    

  • This article presents an example to use jQuery global AJAX event handlers. 
  • You can use these global event handlers in many ways. In this example, I only show a very simple usage to address some of the very common issues to simplify AJAX calls.
  • If you have time, you can well extend the AjaxGlobalHandler.js file into a jQuery plugin. In this article, I did not worry about this extension, and we have already had a lot of jQuery plugins anyway.
  • This example also shows us how to use Action Filters to simplify MVC programming.
  • Ideally you should reference and initiate AjaxGlobalHandler.js in the master page so its functionalities are available to every page in your application. In this example, I simply put it into the web page itself to avoid the complexity involved in master pages.
  • In your application, you may find cases when you do not want these global events to fire. In these cases, you can simply set "global: false" in your implementation of AJAX requests.
  • I hope you like my postings and I hope this article can help you one way or the other. 

History

  • First revision - 5/11/2012.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Dr. Song Li

United States United States
I have been working in the IT industry for some time. It is still exciting and I am still learning. I am a happy and honest person, and I want to be your friend.

Comments and Discussions

 
QuestionGood Article and well documented PinmemberMember 1137654114-Jan-15 21:31 
GeneralNice article and well explained Pinmemberphani krishna reddy v18-Jun-14 7:55 
GeneralMy vote of 5 PinprofessionalAhmed Bensaid26-Feb-14 0:38 
GeneralNice article Pinprofessionalsatish.kotha22-May-13 22:00 
GeneralMy vote of 5 Pinmemberrahuluttarkar12-Jul-12 18:46 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.150326.1 | Last Updated 2 Apr 2013
Article Copyright 2012 by Dr. Song Li
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid