4lackof 4lackof - 3 months ago 15
Javascript Question

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.

Answer

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);
  });
});