I'm trying to reproduce jQuery's functions ajaxComplete and ajaxStart without jQuery so that they could be used in any environment with no library dependencies (it's a special use case). These functions allow for an event listener to be called before and after any ajax request. In my example, I call them preAjaxListener and postAjaxListener.
I'm trying to accomplish it by hooking into the XMLHttpRequest object and overwriting/decorating open and send. Yes, I know this is dirty. 
XMLHttpRequest.prototype.open = (function(orig){
    return function(a,b,c){
        this._HREF = b; // store target url
        return orig.apply(this, arguments); // call original 'open' function
    };
})(XMLHttpRequest.prototype.open);
XMLHttpRequest.prototype.send = (function(orig){
    return function(){
        var xhr = this;
        _core._fireAjaxEvents('pre', xhr._HREF); // preAjaxListener fires
        var rsc = xhr.onreadystatechange || function(){}; // store the original onreadystatechange if it exists
        xhr.onreadystatechange = function(){ // overwrite with custom function
            try {
                if (xhr.readyState == 4){
                    _core._fireAjaxEvents('post', xhr._HREF); // postAjaxListneer should fire
                    this.onreadystatechange = rsc;
                } 
            } catch (e){ }
            return rsc.apply(this, arguments); // call original readystatechange function
        };
        return orig.apply(this, arguments); // call original 'send' function
    };
})(XMLHttpRequest.prototype.send);
I do not want to write wrapper functions to make ajax requests. I want to be able to hook into any ajax request made by any library (or with vanilla js) on the page.
So far, only the preAjaxListener function works. I can't seem to figure out why, but it seems that onreadystatechange is never being called. Any guidance would be greatly appreciated.
Working demo: http://jsfiddle.net/_nderscore/QTQ5s/
Using .onreadystatechange wasn't working because I was testing with jQuery and jQuery's ajax methods manipulate and removes the onreadystatechange property. 
However, adding an event listener for loadend works just fine everywhere but IE. For IE, I set up an interval instead - not the optimal solution, but it works for my needs. I only intended this script to work on IE8+ and modern browsers.
XMLHttpRequest.prototype.send = (function(orig){
    return function(){
        _core._fireAjaxEvents('pre', this._HREF);
        if (!/MSIE/.test(navigator.userAgent)){
            this.addEventListener("loadend", function(){
                _core._fireAjaxEvents('post', this._HREF);
            }, false);
        } else {
            var xhr = this,
            waiter = setInterval(function(){
                if(xhr.readyState && xhr.readyState == 4){
                    _core._fireAjaxEvents('post', xhr._HREF);
                    clearInterval(waiter);
                }
            }, 50);
        }
        return orig.apply(this, arguments);
    };
})(XMLHttpRequest.prototype.send);
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With