Pensierinmusica
Pensierinmusica

Reputation: 6950

jQuery: how to make ajaxSend wait for another Ajax response before proceeding?

I'm using jQuery (v.3.0.0) and I need ajaxSend() to check if a value is present in localStorage, to add it in the outgoing request headers.

If the value is not present in localStorage, ajaxSend() should get this value with another Ajax request and then send the original request with the correct value in the headers.

This must be a global handler, that applies to all jQuery Ajax requests that are sent out.

Let's make a code example.

$(document).ajaxSend(function (ev, req, opts) {
  // Before sending any jQuery Ajax request
  var original = req;
  if (localStorage.foo) {
    // If value "foo" is available, add it to the headers
    req.setRequestHeader('foo', localStorage.foo);
  } else {
    // Otherwise get it first, and add it to the headers
    $.get({url: '/foo', global: false})
      .done(function (data, textStatus, req) {
        // "foo" is received and added to the original request headers
        localStorage.foo = data;
        original.setRequestHeader('foo', data);
        // Now the original request is ready to be sent
      });
  }
});

When foo is not available, the problem with the code above is that obviously the original request is sent out before the value of foo is retrieved.

Is there any way to fix this and get it to work properly?

Thanks!!

Upvotes: 4

Views: 3810

Answers (3)

I found a solution that does not need to abort the original request as in Pensierinmusica's answer. Instead the send method of the xhr object of the original AJAX call is overridden, and the original send with arguments can then be invoked later when e.g. another AJAX request completes. See this answer: https://stackoverflow.com/a/30263533

Upvotes: 0

Pensierinmusica
Pensierinmusica

Reputation: 6950

So far, this is the best solution that I could find. It's not perfect, and it does not exactly answer the original question, but it's a good workaround and gets very close to what I was trying to achieve.

The main difference is that instead of making the original request wait, it cancels it, it gets the desired value, and then it creates a new request with the same settings as the original one.

$(document).ajaxSend(function (ev, req, opts) {
  if (localStorage.foo) {
    // If value "foo" is available, add it to the headers
    req.setRequestHeader('foo', localStorage.foo);
  } else {
    // Otherwise cancel the original request, then get "foo",
    // and create a new request with the same settings as the original one
    req.abort();
    $.get({url: '/foo', global: false})
      .done(function (data, textStatus, req) {
        // "foo" is received
        localStorage.foo = data;
      })
      .then(function () {
        $.ajax(opts);
      });
  }
});

It works perfectly. If someone finds out a better solution that allows to directly use the original request I'll be happy to edit this answer and improve it.

Thanks!

Upvotes: 3

Matt Parlane
Matt Parlane

Reputation: 473

I think you need to use the beforeSend option of $.ajax, you can return false from there if the value is present in localStorage in order to stop the request.

This will mean you always have to use the low-level $.ajax method, perhaps you could make your own set of wrappers for $.get, $.post, $.getJSON etc.

Upvotes: 0

Related Questions