Incerteza
Incerteza

Reputation: 34884

Handle the events of the beginning and end of an ajax request sent by a third-party library

I'm using a third-party library in my project which sends some ajax requests. It's a quite complex library and it sends them to the urls which have a random GUID so I can't predict what the GUIDs would be and thus what the exact url would be.

I want to be able to handle the beginning and end of the ajax requests it sends so I can show an ajax spinner or something - to inform the user that there's something going on. Especially when the page is getting loaded for the first time.

I tried this for the even when it's already done but it didn't work:

$(document).ajaxStop(function () {
  alert('done');
});

And document.ready didn't work the way I needed either because the responses from the ajax request came back after it.

Again, I'm not sending those ajax request, the library sends them. For the sake of simplicity we can assume there's only one ajax request, not many. And I can't change the source code of the library.

Is there any way?

UPDATE:

Isn't not using jquery. And it creates a script dynamically by

    var s = document.createElement('script');
    s.src = url;
    s.async = true;
    s.onreadystatechange = s.onload = function(){
     //.... some stuff

Upvotes: 2

Views: 377

Answers (2)

deostroll
deostroll

Reputation: 11975

This looks like a jsonp callback.

The JSONP works in a fashion similar to how you written code in the post update. But for a more formal understanding see this.

Assuming that your library isn't written in a way to allow you to invoke some routines (functions) at critical stages like before the jsonp request, and, after jsonp request completes...you can override the appendChild routine as mentioned here.

Your focus is to extend the functionality of appendChild. Intercept the insertion of a script element; attach the handlers to it. And you are done...I hope...

Of course, this is a bad idea to put it to production.

http://plnkr.co/edit/ijElm8bQ5u895TMsYJ6D?p=preview

var f = Element.prototype.appendChild;
var precb = function() {
  console.log('precb called');
};

var postcb = function() {
  console.log('postcb called');
};

Element.prototype.appendChild = function() {
  var args = arguments;
  var el = args[0];

  if(el.tagName && el.tagName.toString().toLowerCase() === 'script') {
    precb();
    el.addEventListener('load', postcb, false);
  }
  f.apply(this, args);
};

Upvotes: 1

Chris Baker
Chris Baker

Reputation: 50592

There are no native global events related to AJAX requests. This is partially because there is not a complete cross-browser standard for implementation. Most browsers use XMLHttpRequest, IE uses ActiveXObject.

As noted in comments, jQuery implements Global Ajax Event Handlers, specifically ajaxStart() and ajaxStop(). These give you a place to hook in to all ajax events, and since jQuery provides a unified API for these you don't have to worry about the differences in implementation between browsers.

The jQuery events only help with requests that also use jQuery. For requests initiated without using the library, before OR after the library is included, these events won't be fired by jQuery because jQuery simply has no idea the requests occurred -- no global events for you, no global events for jQuery.

That leaves you with one last, somewhat drastic option -- interfere with the prototype. Depending on what you need to do, this could be accomplished in two ways. To simply stop all requests, you can replace the objects other code will rely on with nothing. The scripts that try to make an AJAX request will simply fail. You can later restore the objects. Here's a non-cross-browser mock-up:

<head>
    <script>
        var oldXMLHttpRequest = XMLHttpRequest;
        XMLHttpRequest = false; // now all ajax requests fail
    </script>

    <!-- include the problematic library here -->

    <script>
        XMLHttpRequest = oldXMLHttpRequest; // now they work again!
        oldXMLHttpRequest = null;
    </script>

Here is a proof-of-concept (not tested for IE, but should work): http://jsfiddle.net/GRMule/wk0f7oeq/

If the goal is not to stop the request, but to take some action beforehand, you could write an object that behaves like XMLHttpRequest/ActiveXObject, but lets you hook in to the request. Replace XMLHttpRequest (or the IE counterpart) with your shimmed object, then optionally restore the original when your work is done. This is a little more involved, but not too tough. Instead of making XMLHttpRequest be false, make it be your functional replacement object.

Some browsers might not like you tampering with native objects, though, so be sure to test either approach on all target platforms.

Upvotes: 1

Related Questions