4lackof
4lackof

Reputation: 1390

Writing a jQuery AJAX request using a plain JS promise

I am currently moving my webpage over to a SPA (single page application) and in doing so I am now working with only one html page, which gets populated using JS (as a normal SPA should do). As such, that means (for convenience sake) I am cutting down my JS files to one (maybe a good idea, maybe a bad one - we'll see, but that's not the point). I have decided to make a "black box" AJAX request handler, so as to minimize code. This is where I ran into a problem I was not expecting. The code is (the example click is for my login screen):

function ajaxCall(type, url, data, dataType) {
  $.ajax({
    type: type,
    url: url,
    data: data,
    dataType: dataType,
  })
  .done(function(xhr) {
    return xhr;
  })
  .fail(function(xhr, status, errorThrown) {
    console.log('AJAX call error: ' + errorThrown);
    console.dir(xhr);
  })
  .always(function(xhr, status) {
    console.log('AJAX call status: ' + status);
  });
}

var res;
//this is inside $(document).ready - I just skipped some lines
$(document).on('click', '#submit', function(e) {
  res = ajaxCall('POST', '/Login', { 'username': $('#username').val(), 'password': $('#password').val() }, 'json');

  console.log('res =', res); // this is where the problem was discovered
});

(some of you are already groaning) Of course, when I tested this, what I got in my console is res = undefined.

I have spent hours researching this problem, and have figured out why it happens. These are some of the pages I researched in trying to solve this: 1 2 3

To cut to the chase: The problem is that I am not using a Promise. I got that. I can fix that. What I cannot seem to fix is using a plain JS Promise with a jQuery AJAX request.

I have gotten this far:

function ajaxCall(type, url, data, dataType) {
  return Promise.resolve($.ajax({
    type: type,
    url: url,
    data: data,
    dataType: dataType,
  }));
}

but I cannot figure out how to incorporate the other features/functions of a promise, which are: .then() and .reject(). As far as I understand, the above Promise will automatically resolve, but what if it needs to be rejected? Maybe I am still thinking with jQuery's .done(), .fail() and .always().

But for the life of me, despite all the Googling I do, I cannot find how to fully incorporate all the functions of a plain JS Promise with a jQuery AJAX request.

Thus, I am asking the stackoverflow community for insight into this problem.

Thank you.

Upvotes: 0

Views: 125

Answers (1)

sakai
sakai

Reputation: 163

So Promise isn't really your savior here. The issue you have is that you need to call the console.log('res =', res); after the AJAX request is done using the .done() and .fail() methods.

function ajaxCall(type, url, data, dataType) {
  return $.ajax({
    type: type,
    url: url,
    data: data,
    dataType: dataType,
  });
}

//this is inside $(document).ready - I just skipped some lines
$(document).on('click', '#submit', function(e) {
  var res = ajaxCall('POST', '/Login', { 'username': $('#username').val(), 'password': $('#password').val() }, 'json');
  res.done(function (data) {
    console.log('res =', data);
  });
});

If you really want to use a real Promise, you can do something like

function ajaxCall(type, url, data, dataType) {
  return new Promise(function (resolve, reject) {
    $.ajax({
      type: type,
      url: url,
      data: data,
      dataType: dataType,
    }).done(function (data) {
      resolve(data);
    }).fail(function (jqXHR, textStatus, errorThrown) {
      reject(errorThrown);
    });
  });
}

//this is inside $(document).ready - I just skipped some lines
$(document).on('click', '#submit', function(e) {
  var res = ajaxCall('POST', '/Login', { 'username': $('#username').val(), 'password': $('#password').val() }, 'json');
  res.then(function (data) {
    console.log('res = ', data);
  }).catch(function (err) {
    console.error(err);
  });
});

Upvotes: 2

Related Questions