Question

My plan is to use contextual pre-loader for all ajax calls without modifying the code. Conventionally, my ajax call would be something like this.

// do some pre-loader for example spinning wheel
$('#submitBnt').on('click', function () {
    $.get('/echo/json', function (data) {
        // after everything is done do some cleanup for the UI
    });
});

However, I would like to build the pre-loader at the global level so any ajax call would attach the spinning wheel to the container and cancel that after everything is done.

Here's my code so far which of course doesn't work.

var s_ajaxListener = new Object();
var target;
s_ajaxListener.tempOpen = XMLHttpRequest.prototype.open;
s_ajaxListener.tempSend = XMLHttpRequest.prototype.send;
s_ajaxListener.callback = function () {
    console.log('last');
    $('.ajaxContainer').removeClass('pre-loader');
}

XMLHttpRequest.prototype.open = function (a, b) {
    console.log('first');
    $(document).on('click', function (e) {
        target = e.target;
        $(target).closest('.ajaxContainer').addClass('pre-loader');
    });
    if (!a) var a = '';
    if (!b) var b = '';
    s_ajaxListener.tempOpen.apply(this, arguments);
    s_ajaxListener.method = a;
    s_ajaxListener.url = b;
    if (a.toLowerCase() == 'get') {
        s_ajaxListener.data = b.split('?');
        s_ajaxListener.data = s_ajaxListener.data[1];
    }
}

XMLHttpRequest.prototype.send = function (a, b) {
    if (!a) var a = '';
    if (!b) var b = '';
    s_ajaxListener.tempSend.apply(this, arguments);
    if (s_ajaxListener.method.toLowerCase() == 'post') s_ajaxListener.data = a;
    s_ajaxListener.callback();
}


$('#submitBnt').on('click', function () {
    $.get('/echo/json', function (data) {
        console.log(data);
    });
});

My question would be 1. why it doesn't work. 2. Is it a good idea to add $(document).on('click') as I thought it would add on click event to the global event would it be too much for mobile website?

Here's my fiddle http://jsfiddle.net/noppanit/xke87/2/

Thanks.

Was it helpful?

Solution

First, you should be careful about extending native object prototypes.

Second, if you're using jQuery, what you're wanting to do is pretty easily achieved using $.ajaxStart() and $.ajaxComplete() to set up a start and end action for all ajax calls. You can read about those here: https://api.jquery.com/ajaxStart/, and here: https://api.jquery.com/ajaxComplete/.

A basic implementation:

$( document )
.ajaxStart(function() {
    $( e.target )closest('.ajaxContainer').addClass('pre-loader');
})
.ajaxComplete(function() {
    $( e.target )closest('.ajaxContainer').removeClass('pre-loader');
});

That would work for any clicks in your document that trigger an ajax request.

Zepto fires a handful of events during the lifecycle of and ajax request, so you can do the same thing as in jQuery using Zepto's ajaxBeforeSend and ajaxComplete:

$(document)
.on('ajaxBeforeSend', function(e, xhr, options) {
    // show your loader
})
.on('ajaxComplete', function(e, xhr, options) {
    // hide your loader
});

According to their documentation, those events are fired on the document object so you can listen for them globally and they'll run for every ajax request you make. ajaxBeforeSend gives you access to your request object, the event that fired the ajax request and the options passed to the request. So you can do a lot with that. You can read more here: http://zeptojs.com/#$.ajax

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top