Writing a jQuery AJAX request using a plain JS promise - javascript

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.

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

Related

ajax, error is called but it work anyway

I send a post request using ajax, the data is being saved in the database but my success function never run?
If I put the success function in the error function the app is behaving as I would expect. I dont see any error messages in the node terminal. I have built the API myself, but I have noticed any problems before.
I am still on the steep learning curve, is there something wrong I have missed in my code?
$('#newPoiForm').on('submit', function(e) {
e.preventDefault();
let formData = $(this).serialize();
$.ajax({
dataType: 'json',
type: 'POST',
url: '/api/pois/',
data: formData,
success: function(message) {
console.log('success, now run the success function');
// add the new point ajax should go here
},
error: function(data) {
console.log('something went wrong');
$.ajax({
dataType: 'json',
url: 'http://localhost:3000/api/pois/last',
success: function (data) {
$(data.features).each(function (key, data) {
// add last to poi
console.log('last point added');
poi.addData(data);
});
}
});
}
});
first get rid of the nested success function within the error function and replace the error function with this to debug the cause:
error: function(ts) { alert(ts.responseText) }
Then have a look at the url, they differ within your success functions.
Either simply the first url-parameter is wrong, or the response is invalid.

suppress 500 errors in console after REST request

I'm making multiple REST calls via Javascript to determine if a user is in several Sharepoint groups.
If the user is not in the group, the REST request returns a status of 500, along with a message saying "user cannot be found".
When an error is returned, I resolve my promise with "false", so my function works ok.
But - every REST response of 500 puts an error entry in the Javascript console - is it possible to suppress those entries?
I know they don't impact the function, but it clutters up the console.
function IsUserInGroupNumber(permissionRequested,userEmail,groupNumber){
var deferred=$.Deferred();
var url=L_Menu_BaseUrl+"/_api/web/sitegroups("+groupNumber+")/Users/getByEmail('"+userEmail+"')/Email";
$.ajax({
type: 'GET',
url: url,
beforeSend: function (XMLHttpRequest) {
XMLHttpRequest.setRequestHeader("Accept", "application/json; odata=verbose");
},
processData: false,
success: function (data)
{
deferred.resolve({requestedPermission:permissionRequested,groupNumber:groupNumber,hasPermission:true});
},
error: function(data){
//user not found in the group returns a 500 error - but return value of 'false'
deferred.resolve({requestedPermission:permissionRequested,groupNumber:groupNumber,hasPermission:false});
}
});
return deferred.promise();
}
The service shouldn't respond with a 500 status code. That means something on the server is failing. You can't control how the JavaScript console / browser interprets and resolves an error or status.
Also, as of jQuery 1.5, $.ajax already returns a promise: http://api.jquery.com/jquery.ajax/
You could simplify your code a great deal with something like:
function IsUserInGroupNumber(permissionRequested, userEmail, groupNumber){
return new Promise(resolve, reject) {
$.ajax({
type: 'GET',
url: L_Menu_BaseUrl + "/_api/web/sitegroups(" + groupNumber + ")/Users/getByEmail('" + email + "')/Email",
beforeSend: function (xhr) {
xhr.setRequestHeader("Accept", "application/json; odata=verbose");
},
processData: false,
})
.done(function() {
resolve(true)
})
.fail(function() {
resolve(false)
})
}

How to use an API Key for an Ajax call?

I am trying to include an API key for the first time from New York Times API ( http://developer.nytimes.com/) and use ajax to fetch news from it to populate a local website but I'm not seeing any results. I was told to Make sure your API key is set in the URL's query parameters but I'm not sure how to do it.
?api-key=your-key
Here is what I have done:
// Built by LucyBot. www.lucybot.com
var url = "https://api.nytimes.com/svc/search/v2/articlesearch.json";
url += '?' + $.param({
'api-key': "111111111111111111111111111111"
});
$.ajax({
url: url,
method: 'GET',
}).done(function(result) {
console.log(result);
}).fail(function(err) {
throw err;
});
I need to see the url in json format for various stories such as business, technology, etc and use them for an ajax call.
Try this I am getting data from this
var url = "https://api.nytimes.com/svc/search/v2/articlesearch.json";
url += '?' + $.param({
'api-key': "11111111111111111111111"
});
$.ajax({
url: url,
method: 'GET',
dataType: 'JSON',
success: function(data) {
console.log(data)
},
error: function(err) {
console.log('error:' + err)
}
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
you can also try like as follows
var url = "https://api.nytimes.com/svc/search/v2/articlesearch.json";
$.ajax({
url: url,
method: 'GET',
dataType: 'JSON',
data: {
'api-key': '11111111111111111'
},
success: function(data) {
console.log(data)
},
error: function(err) {
console.log('error:' + err)
}
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Its not a good practice expose API Key directly in client-side context.
I strongly recommend to create an abstraction layer between the browser and the API.
The idea is target the AJAX request to one own backend action, like:
var url = "www.mydomain.com/api/articlesearch";
$.ajax({
url: url,
method: 'GET',
}).done(function(result) {
console.log(result);
}).fail(function(err) {
throw err;
});
And inside the backend (/api/articlesearch) we place the request that target to NY Times, using the API Key
This way you get a more suitable code for javascript, keeping the responsibilities correctly distributed.
PS: If you want it even more safe, you can define the API Key using env variables. Here is an example made in Ruby (just for figure it):
# Inside ApisController
def articlesearch
response = RestClient::Request.execute(
method: :get,
url: 'https://api.nytimes.com/svc/search/v2/articlesearch.json',
headers: {api_key: ENV['API_KEY']})
render json: response
end
Using this approach the API Key will also not be present in GIT repository :)
Well, you should try it this way. It should give you a result without cross-origin errors:
$.ajax({
type: 'GET',
url: 'http://api.nytimes.com/svc/search/v2/articlesearch.json',
data: {
'q': queryString,
'response-format': "jsonp",
'api-key': nytApiKey,
},
success: function(data) {
// passed function object for data processing
console.log(data);
},
error: function(err) {
console.log('error:' + err)
}
});

Loader-GIF doesn't move when AJAX is loading

I'm trying to make a GIF-loader, which will be shown as long as my AJAX request is being processed. I'm using the jquery loader plugin.
The problem is, the GIF doesn't move when the browser is busy processing the AJAX request, though it is moving, when setting it to visible for testing purposes.
I've tested it in 3 major browsers.
This is an extract of my code. The real code is, of course, much more complex:
$("#myButton").click(function() {
$.loader({
className: "blue-with-image-2",
content: ''
});
getData();
});
function getData() {
$.ajax({
type: "GET",
url: "https://jsonplaceholder.typicode.com/photos",
success: function(data) {
// do something with data
console.log(data)
$.loader('close'); // close the loader
},
error: function(jqXHR, status, error) {
console.error(status, error);
}
});
}
Here is a fiddle with that example code.
The funny thing is, when testing this particular code in jsFiddle, it does
work. But not my real code, which is almost the same, but just more complex.
Use function 'beforeSend' in ajax call
function getData() {
$.ajax({
type: "GET",
url: "https://jsonplaceholder.typicode.com/photos",
beforeSend: function() {
$('#response').html("<img src='/images/loading.gif' />");
},
success: function(data) {
// do something with data
console.log(data)
$.loader('close'); // close the loader
},
error: function(jqXHR, status, error) {
console.error(status, error);
}
});

How to transform $.post to $.ajax?

I have this $.post peace of code:
$.post("../admin-login",
{
dataName:JSON.stringify({
username:uname,
password:pass,
})
}, function(data,status){
console.log("Data:"+data);
answer = data;
}
);
and I wont to transform it to $.ajax. On the servlet side I am demanding request.getParamter("dataName") but I do not know how to write data: section in $.ajax so that I can get parameters like that(request.getParamter("dataName"))? Also, it seems to be problem with this type of code, I am asuming cause of async, that I cannot do this:
var answer="";
function(data,status){
console.log("Data:"+data);
answer = data;
}
And that answer is keeping empty(""), even though in console is written in deed "true" or "false" as my server answers. What is this about?
Thanks in advance.
I found out that problem is in the click() event. Ajax finishes when click() finishes, so I am not able to get data before event is done. What is bad in that is that I cannot fetch data because it is finished. Does anyone know how to solve this?
$.post("../admin-login",
{
dataName:JSON.stringify({
username:uname,
password:pass,
})
}, function(data,status){
console.log("Data:"+data);
answer = data;
}
);
becomes
function getResult(data) {
// do something with data
// you can result = data here
return data;
}
$.ajax({
url: "../admin-login",
type: 'post',
contentType: "application/x-www-form-urlencoded",
data: {
dataName:JSON.stringify({
username:uname,
password:pass,
})
},
success: function (data, status) {
getResult(data);
console.log(data);
console.log(status);
},
error: function (xhr, desc, err) {
console.log(xhr);
}
});
You need to see how the information os arriving to your servlet as query parameter or payload.
See this HttpServletRequest get JSON POST data
You could try structuring your AJAX request like the below:
var dataName = username:uname, password:pass;
$.ajax({
url: "../admin-login",
data: JSON.stringify(dataName),
type: "POST",
cache: false,
dataType: "json"
}).done(function(data, status) {
console.log("Data:"+data);
answer = data;
});

Categories