This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 9 years ago.
I want to build a javascript class which I initialize and will make only one ajax request to save some data off so I can do stuff with it aftewards. It is important that there is only one request for performance reasons.
Here is the initialisation
var web = new webService();
web.connect(app.info);
web.info();
and this is my class
function webService() {
this.d = new Object;
this.connect = function(app) {
console.log(app);
$.ajax({
url: 'my working url which gives me my jsonp object',
dataType: 'jsonp',
jsonp: 'jsoncallback',
timeout: 5000,
success: function(data) {
this.d = data;
},
async: false
});
}
this.info = function() {
console.log(this.d);
}
}
I was wondering if there might be a problem with synchronizing? I'm not sure so I wanted to ask you guys.
jQuery $.ajax (and similar methods, like $.getJSON()) will return a Deferred object. Like other JavaScript objects, this is a "thing" which you can store in a variable and pass around in your code. Then you can add (async) callbacks to it at any time:
// Don't include a 'success' callback yet.
$def = $.ajax(...);
// $def is an object which you can store globally
// or pass as an argument into other functions.
//
// Somewhere else, add a success callback:
$def.done(function(data) {
// ...
});
See http://api.jquery.com/category/deferred-object/
If you refactor your code to return a deferred object thus:
function webService() {
this.d = new Object;
this.connect = function(app) {
console.log(app);
return $.ajax({
url: 'my working url which gives me my jsonp object',
dataType: 'jsonp',
jsonp: 'jsoncallback',
timeout: 5000,
success: function(data) {
this.d = data;
}
});
}
this.info = function() {
console.log(this.d);
}
}
You can then use done:
var web = new webService();
web.connect(app.info).done(function() {web.info();});
this also means your A jax is asynchronous, like it should be.
You could argue if your going down this route though, what is your function webservice even doing. Why not just let deferred do all the work?
this.connect = function(app) {
console.log(app);
var that = this; //store this into a variable
$.ajax({
url: 'my working url which gives me my jsonp object',
dataType: 'jsonp',
jsonp: 'jsoncallback',
timeout: 5000,
success: function(data) {
that.d = data; //use that so you have the right scope
},
async: false
});
}
other option is to use bind or jQuery's proxy
Related
I'm somewhat breaking my head over this. I have an ajax call like this:
function genericname()
{
var domain = $('#input').val();
var sendData = {
'domain': domain
};
var promise = $.ajax(
{
type: 'POST',
url: '/functions.php',
data:
{
module: 'modulename',
operation: 'functionname',
parameters: sendData
},
dataType: 'json'
}).promise();
promise.then(function(data)
{
console.log(data);
return data;
});
promise.fail(function(data)
{
console.log(data);
});
}
Now the problem is that when debugging I notice that both promise.then and promise.fail are just skipped. The php proces I am calling to output is true. Actually when I look in the network tab of the debug tools the response says true.
Could anyone explain what the mistake is here?
EDIT: the result being output by the php function is json_encoded
This function is being called in the .then portion of another ajax call
remove .promise at the end of ajax request:
var domain = $('#input').val();
var sendData = {
'domain': domain
};
var promise = $.ajax(
{
type: 'POST',
url: '/functions.php',
data:
{
module: 'modulename',
operation: 'functionname',
parameters: sendData
},
dataType: 'json'
})
The issue is fixed now and here is how I solved it.
The function was required to return a boolean which was used in the if statement in another .then statement of another ajax call to change some html.
In the end I resorted to placing the html changes in the .then portion if this function.
Hope I can help someone with this information.
I'm pretty new to Javascript. Please don't make it too harsh :)
I have two functions, both of which involve executing jQuery requests within for loops. For example,
function a(n,locations) {
for (var i = 0; i < n; i ++) {
$.ajax({
url: 'https://geocoder.cit.api.here.com/6.2/geocode.json',
type: 'GET',
dataType: 'jsonp',
jsonp: 'jsoncallback',
data: {
searchtext: input,
app_id: APP_ID,
app_code: APP_CODE,
},
success: function (data) {
handleData(data,locations);
}
});
}
The handleData() function would make changes to the empty array locations from the jQuery data. My function b(m) is of similar format but would use the updated locations as input.
Now, I have a c(n,m) in which I would like execute a() and b() sequentially:
function c(n,m) {
var locations = [];
a(n,locations);
b(m,locations);
}
From previous answers I understand that sequentially executing functions involving jQuery calls can be achieved by using promises (such as .then). However, this solution is only applicable when a(n) returns a promise, which is not achievable under the for-loop structure. Could you please share your insights on how to solve this issue? Thanks in advance for the help.
I would suggest recursion instead of your for loop. For example, you can call the function recursionExample like this,
function a(n) {
return new Promise ((resolve, reject) {
(function recursionExample(a) {
if (a === n) {
resolve;
} else {
$.ajax({ url: 'https://geocoder.cit.api.here.com/6.2/geocode.json',
type: 'GET',
dataType: 'jsonp',
jsonp: 'jsoncallback',
data: {
searchtext: input,
app_id: APP_ID,
app_code: APP_CODE,
},
success: function(data) {
handleData(data);
recursionExample(a + 1);
}
});
}
})(0);
});
}
This will then allow you to use the promise and .then functions. Like so...
function c(n,m) {
var locations = [];
a(n,locations)
.then (function() {
b(m,locations);
});
}
Problem: Extracting data from ajax request inside page.evaluate
Description: I usually get variables out of page.evaluate by simply returning them. However, I need to make an ajax request within the context of a page, and then I need to process its result out of the page's context.
The code I'm trying to fix is:
var theOutput = page.evaluate(function () {
return $.ajax({
async: false,
url: 'http://localhost:8080/captcha.php',
data: { filename: 'C:\\wamp\\www\\images\\0.png' },
type: 'post',
success: function (output) {
parsed_output = $.parseHTML(output);
return parsed_output[4].data.trim();
},
});
});
console.log(theOutput);
The variable parsed_output[4].data.trim() is a string. But when I log output I get a [object Object], with the properties abort, always, complete, done, error, fail, getAllResponseHeaders, getResponseHeader, overrideMimeType, pipe null, progress, promise, readyState, setRequestHeader, state, statusCode, success,then.
Question: How can I extract theOutput from page.evaluate?
Since this is a blocking AJAX request, you can create a temporary variable:
var theOutput = page.evaluate(function () {
var result;
$.ajax({
async: false,
...
success: function (output) {
parsed_output = $.parseHTML(output);
result = parsed_output[4].data.trim();
},
});
return result;
});
console.log(theOutput);
You can also directly access the responseText from the jqXHR object:
var theOutput = page.evaluate(function () {
var jqXHR = $.ajax({
async: false,
url: 'http://localhost:8080/captcha.php',
data: { filename: 'C:\\wamp\\www\\images\\0.png' },
type: 'post'
});
parsed_output = $.parseHTML(jqXHR.responseText);
return parsed_output[4].data.trim();
});
console.log(theOutput);
If you fear that async: false is deprecated, you can simply use the underlying XMLHttpRequest to use blocking execution:
var theOutput = page.evaluate(function () {
var request = new XMLHttpRequest();
request.open('POST', 'http://localhost:8080/captcha.php', false);
request.send($.param({ filename: 'C:\\wamp\\www\\images\\0.png' }));
var parsed_output = $.parseHTML(request.responseText);
return parsed_output[4].data.trim();
});
console.log(theOutput);
I am trying to write a JavaScript Object which has many Properties and Methods. The basic function of this code is to send an ajax call and get data from server.
Code IS:
function restClient(options) {
var _response;
var _response_status;
var _response_message;
var _response_data;
// Default Options
var _default = {
restCall: true,
type: "GET",
url: '',
contentType: "application/json; charset=utf-8",
crossDomain: false,
cache: false,
dataType: 'json',
data: {},
beforeSend: _ajaxBeforeSend,
success: _ajaxSuccess,
error: _ajaxError,
complete: _ajaxComplete
};
// Extend default Options by User Options
var ajaxOptions = $.extend(_default, options);
// Private Methods
function _ajaxBeforeSend() {
}
function _ajaxSuccess(response) {
_response = response;
_response_status = response.status;
_response_message = response.message;
_response_data = response.data;
}
function _ajaxError(xhr, status, error) {
_response_status = xhr.status;
_response_message = error;
}
function _ajaxComplete(xhr, status) {
}
// Send Ajax Request
this.sendRequest = function() {
$.ajax(ajaxOptions);
};
// Get Server Response Pack [status,message,data]
this.getResponse = function() {
return _response;
};
// Get Server Response Status: 200, 400, 401 etc
this.getStatus = function() {
return _response_status;
};
// Get Server Message
this.getMessage = function() {
return _response_message;
};
// Get Server Return Data
this.getData = function() {
return _response_data;
};
}
Now I am trying to create object using new operator and call sendRequest(); method to send an ajax call and then I am calling getResponse(); to get server response like:
var REST = new restClient(options);
REST.sendRequest();
console.log(REST.getResponse());
Every thing is working properly But the problem is REST.getResponse(); call before to complete Ajax which give me empty result. If i do like this
$(document).ajaxComplete(function(){
console.log(REST.getResponse());
});
then it work But Still two problems are
If there are another ajax call its also wait for that
its looking bad I want to hide this ajaxComplete() some where within restClient();
Please Help me.
Thanks.
You have to change method sendRequest to accept a callback, that you'll call on response completion.
this.sendRequest = function(cb) {
this.cb = cb;
$.ajax(ajaxOptions);
};
this._ajaxComplete = function(xhr, status) {
this.cb && this.cb();
}
Also, after defining this._ajaxComplete change the _default.complete handler, in order to bind the this object, otherwise you'll miss the cb property:
_default.complete = this._ajaxComplete.bind(this);
Your client code will become:
var REST = new restClient(options);
REST.sendRequest(function(){
console.log(REST.getResponse());
});
I have the following script to add a new value to the array of my session variable, and show me the varible totally live session
(function ($) {
Drupal.behaviors.MyfunctionTheme = {
attach: function(context, settings) {
$('.add-music').click(function () {
var songNew = JSON.stringify({
title: $(this).attr('data-title'),
artist: $(this).attr('data-artist'),
mp3: $(this).attr('href')
});
var songIE = {json:songNew};
$.ajax({
type: 'POST',
data: songIE,
datatype: 'json',
async: true,
cache: false
});
var session;
$.ajaxSetup({cache: false})
$.get('/getsession.php', function (data) {
session = data;
alert(session);
});
});
}}
})( jQuery );
the problem is that the POST shipping takes longer than the call GET ALERT then shows me the session variable not updated.
Is there a way to put an IF condition for shipping only when POST is complete return the response I GET?
thanks
Actually, what you want do do is to use a callback - that is, a function that is called as soon as your POST ajax request returns.
Example:
(function ($) {
Drupal.behaviors.MyfunctionTheme = {
attach: function(context, settings) {
$('.add-music').click(function () {
var songNew = JSON.stringify({
title: $(this).attr('data-title'),
artist: $(this).attr('data-artist'),
mp3: $(this).attr('href')
});
var songIE = {json:songNew};
$.ajax({
type: 'POST',
data: songIE,
datatype: 'json',
async: true,
cache: false
})
.done(
//this is the callback function, which will run when your POST request returns
function(postData){
//Make sure to test validity of the postData here before issuing the GET request
var session;
$.ajaxSetup({cache: false})
$.get('/getsession.php', function (getData) {
session = getData;
alert(session);
});
}
);
});
}}
})( jQuery );
Update per Ian's good suggestion I've replaced the deprecated success() function with new done() syntax
Update2 I've incorporated another great suggestion from radi8