I wanted to be able to send the data from a successful jquery ajax call to other methods in my application because its quite large and it made coding sense to have one api method to work from, so I opted to try out promises. This is my first shot. I am getting some good results but clearly I am still a bit confused on context and timing.
When I run the following code, I am unable to wrap my return data from the ajax call as a jquery object without getting an error:
var widgetSystem={
listenForClick: function(){
$('div').on('click','a',function(){
var $selectTarget = $(this),
widgetid = $(this).data('widgetid');
apiRequestData = widgetSystem.makeApiRequestForSingleWidget(widgetid);
apiRequestData.then(function(result) {
widgetSystem.showWidget(result);
}).catch(function(e) {
console.log('no way big error ' +e);
});
});
},
makeApiRequest: function(widgetid){
return new Promise(function(resolve, reject) {
$.ajax({
method: "POST",
url: "localhost",
dataType: 'json',
data: {
data: {
widgetId: widgetid
},
action: 'apiMethod'
},
error: function (jqXHR, textStatus, errorThrown) {
console.log(jqXHR);
console.log(textStatus);
console.log(errorThrown);
reject();
},
success: function (data) {
resolve(data);
}
});
});
},
showWidget: function(data){
$(data).appendTo('body');
//this causes an exception in my apiRequestData.then function in listenForClick
}
}
I am running un minified jquery and getting the following error in my console:
no way big error TypeError: context is undefined
I don't know exactly what your HTML looks like or how the API is set up, but assuming that the API is working correctly and the data sent via POST is correct, I was able to get it working using jsonplaceholder api with the following code (you can find it on JSbin).
var widgetSystem={
listenForClick: function(){
$('div').on('click','a',function(){
console.log('clicked');
var $selectTarget = $(this);
var widgetid = $(this).data('widgetid');
widgetSystem.makeApiRequest(widgetid)
.then(function(result) {
widgetSystem.showWidget(result);
return result;
})
.catch(function(e) {
console.log('no way big error ' +e);
});
});
},
makeApiRequest: function(widgetid){
return new Promise(function(resolve, reject) {
var root = 'http://jsonplaceholder.typicode.com';
$.ajax({
method: "POST",
url: root+'/posts/',
dataType: 'json',
data: {
userId:1,
title:"Havanagila",
body:"Testing the greatness"
},
success: function(xData, status){
resolve(xData);
//reject('whoops');
},
error: function(xhr, status, error){
reject(status);
}
});
});
},
showWidget: function(data){
$('#space').append(document.createTextNode(JSON.stringify(data)));
}
}
widgetSystem.listenForClick()
I don't think there is an issue which how you are calling resolve(data) within the ajax success callback. There may be an issue with the data being sent to your API such that the error callback is called, which in turn calls reject and causes the callback passed to .catch to be called instead of the intended callback passed to .then.
Related
I'm struggling with an ajax GET using a promise.
If the ajax runs into an error, such as the URL is incorrect, the 'error: function ()' is called and I get an error in the browser debug saying "Uncaught (in promise) undefined"
The first two parts of the ajax function works OK i.e. if the ajax returns a success, then both inner conditions for result.success true/false are working, I just don't know how to resolve the reject call in the ajax error function at the bottom:
var myVariable = "test";
let promise = myFunction(myVariable);
promise.then(function () {
// Do Something
}).catch(function (message) {
console.error(message);
});
function myFunction(myVariable) {
return new Promise(function (resolve, reject) {
$.ajax({
type: "GET", //send it through get method
url: "/myURL/Edit?handler=GetBlahBlah",
data: {
sourceType: myVariable
},
contentType: "json",
dataType: "json",
success: function (result) {
if (result.success == false) {
reject(result.responseText); // This works
} else {
resolve(); // This works
}
},
error: function () {
reject("Error while making Ajax call! Get Trigger"); // NOT WORKING!!
}
});
});
}
Turns out my original question does actually work correctly, I hadn't noticed at first that the calling method to this ajax GET request was coming from two different process in my javascript at different times and i hadn't included a catch block on the process that was actually calling this ajax the first time round.
Apologies if I caused any confusion to anyone, my bad!
I'm attempting to coax JavaScript into synchronous behaviour, but I've so far failed.
I've tried 30 or more different methods, and here is the latest attempt, based on another answer, here on StackOverflow:
function fnc () {
$.ajax({
type: 'GET',
url: "libraries/resources/data.json",
dataType: 'json',
success: function (data) {
...
objSomething = {
...
};
},
error: function () {}
});
}
fnc().then(function(objSomething) {
google.maps.event.addDomListener(window, 'load', function(){ initialize(objSomething); });
}).catch(function(objSomething) {
...
});
However, I'm getting an error:
TypeError: undefined is not an object (evaluating
'fnc().then')
Most of the methods I've tried have resulted in similar errors.
As for the Google Maps code, it does work (although not always, due to the asynchronous nature of the code execution).
It's worth noting that while I'm able to write complex code from scratch, when it comes to the underlying mechanics, I'm not that proficient.
I'm using jQuery 2.2.2, via the Google API CDN.
This is a solution you are looking for.
function fnc () {
var dfd = jQuery.Deferred();
$.ajax({
type: 'GET',
url: "libraries/resources/data.json",
dataType: 'json',
success: function (data) {
...
objSomething = {
...
};
dfd.resolve(objSomething);
},
error: function (error) { dfd.reject(error); }
});
return dfd.promise();
}
$.when(fnc()).then(function(objSomething) {
google.maps.event.addDomListener(window, 'load', function(){
initialize(objSomething);
});
}, function(error){
//Handle Error
});
use $.ajax function you can use the then function. Refer the following link:
http://wildermuth.com/2013/8/3/JavaScript_Promises
I'm currently dealing with refactoring my code, and trying to automate AJAX requests as follows:
The goal is to have a context-independent function to launch AJAX requests. The data gathered is handled differently based on the context.
This is my function:
function ajaxParameter(routeName, method, array, callback){
//Ajax request on silex route
var URL = routeName;
$.ajax({
type: method,
url: URL,
beforeSend: function(){
DOM.spinner.fadeIn('fast');
},
})
.done(function(response) {
DOM.spinner.fadeOut('fast');
callback(response);
})
.fail(function(error){
var response = [];
response.status = 0;
response.message = "Request failed, error : "+error;
callback(response);
})
}
My problem essentially comes from the fact that my callback function is not defined.
I would like to call the function as such (example)
ajaxParameter(URL_base, 'POST', dataBase, function(response){
if(response.status == 1 ){
console.log('Request succeeded');
}
showMessage(response);
});
I thought of returning response to a variable and deal with it later, but if the request fails or is slow, this won't work (because response will not have been set).
That version would allow me to benefit the .done() and .fail().
EDIT : So there is no mistake, I changed my code a bit. The goal is to be able to deal with a callback function used in both .done() and .fail() context (two separate functions would also work in my case though).
As far as I can see there really is nothing wrong with your script. I've neatened it up a bit here, but it's essentially what you had before:
function ajaxParameter (url, method, data, callback) {
$.ajax({
type: method,
url: url,
data: data,
beforeSend: function(){
DOM.spinner.fadeIn('fast');
}
})
.done( function (response) {
DOM.spinner.fadeOut('fast');
if (callback)
callback(response);
})
.fail( function (error){
var response = [];
response.status = 0;
response.message = "Request failed, error : " + error;
if (callback)
callback(response);
});
}
And now let's go and test it here on JSFiddle.
As you can see (using the JSFiddle AJAX API), it works. So the issue is probably with something else in your script. Are you sure the script you've posted here is the same one you are using in your development environment?
In regards to your error; be absolutely sure that you are passing in the right arguments in the right order to your ajaxParameter function. Here's what I am passing in the fiddle:
the url endpoint (e.g http://example.com/)
the method (e.g 'post')
some data (e.g {foo:'bar'})
the callback (e.g function(response){ };)
Do you mean something like this, passing the success and fail callbacks:
function ajaxParameter(routeName, method, array, success, failure) {
//Ajax request on silex route
var URL = routeName;
$.ajax({
type: method,
url: URL,
beforeSend: function () {
DOM.spinner.fadeIn('fast');
}
}).done(function (response) {
DOM.spinner.fadeOut('fast');
success(response);
}).fail(function (error) {
var response = [];
response.status = 0;
response.message = "Request failed, error : " + error;
failure(response);
})
}
Called like:
ajaxParameter(
URL_base,
'POST',
dataBase,
function(response){
//success function
},
function(response){
// fail function
}
);
So when handling, for example, the success data in jquery, should you check if the return data has the necessary data like this:
success: function (data) {
if (data.new_rank !== undefined) {
$('._user_rank').html(data.new_rank);
}
}
Or let it fail when it is not present?
success: function (data) {
$('._user_rank').html(data.new_rank);
}
in the previous example you can check if something has changed and needs to be fixt because of the error.
What approach is the best?
It's better you check it, for other code that may be you have in complete or other event. If you didn't, they will not run after error. You can check it this too:
success: function (data) {
if (data.new_rank) {
$('._user_rank').html(data.new_rank);
}
}
jQuery ajax requests provide you a way to handle request errors.
$.ajax(url, {
success: function(data) {
// success
},
error: function() {
// error
}
});
If it's not a request error that you are trying to catch you still should handle error by yourself and not let javascript throw them all the way.
One solution I would say is follow strict data type in $.ajax like dataType: json.
Use success and error handler. And if the return data is anything other than json type it will be handled through error handler.
$.ajax(url, {
dataType: 'json'
success: function(data) {
// success
},
error: function() {
// error
}
});
I'm unsure why this jquery ajax call is failing. Basically, I want to authenticate and if the authentication is a success, do something.
I found this but the answer seems to abbreviated to be much use to me (is assumes you already know how to implement the solution). jQuery ajax return value
Here is my ajax call (I have stripped the fluff for getting the username/password):
function authenticate() {
$.ajax({ //TODO: Securely send this (ssl?)
type: 'POST',
url: 'includes/clientAuthenticate.php',
data: { username: username, password: password},
success:function(data){
if(data==='true') {
return "true";
} else {
return "User failed to log into the system.\nEmail request ignored.\n\nError message: \n" + data;
}
},
error:function(jqXHR, textStatus, errorThrown){
return "User failed to log into the system. Potential problem with server or connection.";
}
});
And I call it in this function:
function attemptEventSubmit(eKey) {
var authReturn = authenticate();
if(authReturn=="true") {
emailEvent(eKey);
} else {
alert(authReturn);
}
}
When it returns, it always alerts that authReturn is "undefined". I suspect it's defining authReturn as undefined because the authenticate function 'finishes' before the ajax call gets back...
But I'm not sure how to fix this problem.
I suspect I could call separate instead of returning values... (say, in this example, calling the emailEvent function directly in the ajax success function) but that would make the authenticate function specific... and it'd no longer be able to be used for authenticating for other purposes.
You can use your code but will need a callback. A better way would be look into promises.
function authenticate(onsuccess, onfail) {
$.ajax({ //TODO: Securely send this (ssl?)
type: 'POST',
url: 'includes/clientAuthenticate.php',
data: { username: username, password: password},
success:function(data){
onsuccess(data); // you should check if this is a function
},
error:function(jqXHR, textStatus, errorThrown){
onfail(errorThrown);
}
});
function attemptEventSubmit(eKey) {
authenticate(
function(ajaxData){
emailEvent('whatever you want to send');
},
function(errThrown){
alert(errThrown);
});
}
How about pass in a callback function as another argument of the function authenticate().
So the code changes will be
function authenticate(callback) {
$.ajax({ //TODO: Securely send this (ssl?)
type: 'POST',
url: 'includes/clientAuthenticate.php',
data: { username: username, password: password},
success:function(data){
if(data==='true') {
//return "true";
callback("true");
} else {
//return "User failed to log into the system.\nEmail request ignored.\n\nError message: \n" + data;
callback("User failed to log into the system.\nEmail request ignored.\n\nError message: \n" + data);
}
},
error:function(jqXHR, textStatus, errorThrown){
//return "User failed to log into the system. Potential problem with server or connection.";
callback("User failed to log into the system. Potential problem with server or connection.");
}
});
Calling the function authenticate will become:
function attemptEventSubmit(eKey) {
authenticate(function(authReturn){
if(authReturn=="true") {
emailEvent(eKey);
} else {
alert(authReturn);
}
});
}