How to get synchronous result for jsonpCallback? - javascript

I want to call jsonpcallback function in while or for loop. But I am getting asynchronous results. How to achieve that in jsonpcallback. Kindly anyone help me out to fix this or provide any other solution.
window.onPublitoryOebPart = function(json) {
window.publitoryOebPartJson = json;
content = patchEditedContent(json);
saveOebPartToc(content);
}
i = 0;
while(i < $("#oeb_parts_count").val()) {
return unless $("#oeb-part-file-url-"+i).length > 0
fileUrl = $("#oeb-part-file-url-"+i).html();
$.ajax({
url: fileUrl,
crossDomain: true,
dataType: "script",
jsonpCallback: "onPublitoryOebPart"
})
i++;
}

JavaScript can't get a "synchronous" JSONP result. This is because JSONP involves creating a new script element; such a dynamically created script element can only load the resource asynchronously.
Just use the success callback for the JSONP request and handle the response asynchronously. Manually specifying the jsonpCallback is only required/useful if the service doesn't allow a dynamic function to be specified.
If using success callback in a loop, it's also important to read up on closures (and then read more).
For instance:
var i = 0; // Don't forget the "var"
while(i < $("#oeb_parts_count").val()) {
var elm = $("#oeb-part-file-url-"+i);
if (!elm.length) { return; } // Make sure to use valid syntax
var fileUrl = elm.html();
$.ajax({
url: fileUrl,
crossDomain: true,
dataType: "script",
success: function (i, fileUrl) {
// Return a closure, the i and fileUrl parameters above
// are different variables than the i in the loop outside.
return function (data) {
// Do callback stuff in here, you can use i, fileUrl, and data
// (See the links for why this works)
alert("i: " + i + " data: " + data);
};
})(i, fileUrl) // invocation "binds" the closure
});
i++;
}
It may be cleaner simply to create a closure via a named function, but it's all the same concept.
Synchronous XHR requests are also highly discouraged; XHR is not JSONP, even though such requests are also created with the jQuery.ajax function.

Related

jquery ajax - maintain ajax call sequence

I know my questions is marked as duplicate. But the given answer is using async:false. I don't want to force synchronous requests. How do maintain async ajax call sequence ???
I don't need to replace the content. I need to append svg one after another in a sequence.
I am appending 5 svg elements in a div. All svgs are coming by ajax call. The issue is the order of those svgs. Every time they appended in different order. I want to maintain their order. Please find below my code:
FlagRow.DEFAULTS = {
flagOrder: [
Enums.flagType.INDIA,
Enums.flagType.USA,
Enums.flagType.UK,
Enums.flagType.FRANCE,
Enums.flagType.GERMANY
]
}
var container = $(document.createElement("div"));
var topic = new Array();
for (var key in this.options.flagOrder) {
topic.push(this.options.flagOrder[key]);
}
var appendFlag = function (flag) {
console.log(flag);
var svgDiv = $(document.createElement("div"));
$(svgDiv).addClass('svgDiv');
var importedSVGRootElement = document.importNode(flag.documentElement, true);
$(importedSVGRootElement).attr('viewBox', '0 0 100 125');
svgDiv.append(importedSVGRootElement)
container.append(svgDiv);
}
$.each(topic, function (i, val) {
$.when(//ajax call to get flag svg).done(function (flag ) { appendFlag(flag ); });
});
// api call to get flag svg
var deferred = $.Deferred();
$.ajax({
url: url,
type: 'get',
data: '',
dataType: 'xml',
timeout: 300000,
success: function (data) {
deferred.resolve(data);
},
error: function (e) {
console.log(':::error in flag:::', e);
},
beforeSend: function (xhr) {
xhr.setRequestHeader("Authorization", 'myapikey');
}
});
Here every time flag svg comes in different order. I want it to display it in an order of enum. And so I tried it with $.when().done(). But it's working as per my requirement.
How do I maintain order of appended svgs coming via ajax call ???
You can use async: false to mimic what you tried to do with Deferred. Since you know the order at the moment of calling your ajax requests, using placeholders as the duplicate question (for some reason they re-opened this...) suggests is your best bet.
function getAllTheFlags() {
for( var i = 0; i < 5; i++ ) {
insertPlaceHolder( i ); //inserts <div id="placeholder-i"></div> at desired location
insertFlag( i );
}
}
function insertFlag( i ) {
$.ajax( { ... } ).success( function( data ) {
var svgDiv = $(document.createElement("div"));
$(svgDiv).addClass('svgDiv');
var importedSVGRootElement = document.importNode(flag.documentElement, true);
$(importedSVGRootElement).attr('viewBox', '0 0 100 125');
svgDiv.append(importedSVGRootElement)
$( '#placeholder-' + i ).replaceWith( svgDiv );
} );
}
The function insertFlag(..) is mandatory, as you need to copy the value of i.
You can not expect async ajax call to end in order of call. But you could wrap it in a function that takes the element as parameter that you can acces in your ajax callback.
function fetchContent(element, url){
$.ajax({
url: url,
success: function(data) {
element.whatever(...);
}
});
}
In your code you then create a div or search for an existent one. And call your fetchContent by passing that element as a parameter. Even if your ajax calls don't end in the order of call the content should be added to the good element.
I think it should work.

extract object of responseJSON

I solved a synchronous problem with ajax that way to use deferred function.
I get as an response now big object with statusResponse etc etc inside.
My JSONP Objects are also successfully stored in responseJSON Object. How Can I extract it or save it in another variable ?
var web = new webService();
web.init(app.info);
and here the class
function webService() {
this.init = function(app) {
var d = this.connect(app).done(function(){});
console.log(d);
}
this.connect = function(app) {
console.log(app);
return $.ajax({
url: 'working url',
dataType: 'jsonp',
jsonp: 'jsoncallback',
timeout: 5000
});
}
}
.done() is going to be called when the data has returned (but through a parameter). So, make sure you add a parameter to your callback function then inspect it for whatever you want out of it.
this.connect(app).done(function(mydata){
// mydata = the response object
// grab whatever information you want from it here.
});

Getting list back from ajax jsonp callback

I am making an ajax call via jquery with a jsonp callback function. The callback gets called and generates a list for me that I need to return to the original alling function and assign to a variable. However, it is not getting passed back. I know I am doing something wrong or misunderstanding how this flow works. Could somebody please point me in the correct direction? Here is the (abbreviated) code:
function() {
..build url...
var multiTargets = getMultiMetrics(url);
...do stuff with list...
}
getMultiMetrics = function(url) {
$.ajax({
url: url,
jsonp : true,
jsonpCallback: 'metricCallback',
cache: true,
dataType : 'jsonp',
async: false
});
};
metricCallback = function(data) {
var items = [];
for (var i = data.length - 1; i >= 0; i--) {
items.push(data[i].target);
};
return items;
};
Try not use quotes in
jsonpCallback: metricCallback,
This parameter must be function instead of a string

jquery $.ajax() and its success callback - where is it returning to?

Where does the jquery ajax success callback return to?
I have written a request method that makes an ajax call, detects if I have supplied a callback or returns the datanode of the response XML.
Request Method:
function request(request, dontRefresh)
{
var requestXML = composeRequestXML(request);
$.ajax({
url: 'someProcessor.php',
type: 'POST',
cache: false,
async: dontRefresh,
timeout: 5000,
data: "query="+requestXML,
success: function(response)
{
//parses xml into a js object
var responseObj = parseResponseXML(response);
if(request.callback){
request.callback(responseObj);
} else {
// responseObj.response[0].data[0] is the data
// node of the response Obj.
// this is what i see being the problem -
// I DON'T KNOW WHERE THIS IS RETURNED TO!!
return responseObj.response[0].data[0];
}
}
});
}
This request would use the callback
var requestObj = new Object();
requestObj.callback = function(responseObj){someCallbackFunction(responseObj);};
requestObj[0] = new Object();
requestObj[0].module = "someModule";
requestObj[0].action = "someModuleMethod";
request(requestObj);
//results are returned to the function someCallbackFunction()
This is an example of what i'd like to accomplish
var requestObj = new Object();
requestObj[0] = new Object();
requestObj[0].module = "userManager";
requestObj[0].action = "GET_USERID";
var userId = request(requestObj, false); //make the request asynchronous
I've tried returning the $.ajax() function itself... like so:
function request(request, dontRefresh){
return $.ajax({/*...options...*/);
}
But this bypasses the xml parser I have developed and returns the XHR object. I would like to use this kind of technique to register variables. So essentially...
I will be using this method with a callback or setting a variable with it.
It gets returned to jquery, and jquery discards it. If you want to make your code stop until something has been loaded, use synchronous ajax. But that makes the page irresponsive until the ajax request is complete, so please don't do it!
Example of synchronous ajax (without jquery):
var ajax=new XMLHttpRequest();
ajax.open("GET", url, false);
ajax.send(null);
return ajax.responseText;
Note: For IE compatibility, this gets a little bit more complicated, this is just a proof of concept. And this would be the jquery way of doing it: How can I get jQuery to perform a synchronous, rather than asynchronous, Ajax request?
From your perspective, the function does not return to anywhere. Return values are lost.
The key with asynchronous processing is that you handle any data associated with an event in the event handler, or pass it on from there.
/* ... */
success: function(response)
{
//parses xml into a js object
var responseObj = parseResponseXML(response);
if(request.callback){
request.callback(responseObj);
} else {
/* do something with the data */
setUserId(responseObj.response[0].data[0]);
}
}
Where setUserId() is a function that does something useful, as soon as the user ID is available.
As an aside, you should probably not use responseObj.response[0].data[0] without making sure first that that value actually exists.

jQuery ajax function return

I have this function that embeds flash :
function embedswfile(target, swf, base, width, height) {//dosomething}
And I want to call the function like this
embedSwf("flashgame",decode("<?=base64_encode($path['location'])?>"),decode("<?=base64_encode($path['base_directory'])?>"),"800","600" )
The idea is that whenever someone looks for any swf inside my website,he wont find anything clean.I will change the encoding algorithm,but this is just temporary. In order for that function to work,whenever I call the function 'decode' it must return a single value. PHP contains
<?php
echo base64_decode($_POST['s']);
?>
I tried this but it still wont work
var globvar;
function processdata(newmsg) {
globvar = newmsg;
}
function decode(s){
$.ajax({type: "POST",
url: "includes/decode.inc.php",
data: "s=" + s,
success:function(newmsg){
processdata(newmsg);
}
});
return globvar;
}
Important:
Forget about using Ajax and encoding, decoding the path. What do you think you gain from it? Security? No. One can figure out that this is bas64 encoded or he just monitors the network traffic and reads the response from the Ajax call.
Just do
embedSwf("flashgame","<? =$path['location']?>"),"<?=$path['base_directory']?>","800","600" )
Really, you cannot prevent someone else seeing the data and are just making things more complicated for you.
(Or you have to decrypt the data with JavaScript.)
(original answer is still correct nevertheless)
Ajax is asynchronous so something like var test = decode(s); will never work. The decode function will return before the Ajax call finishes.
Instead, put your logic into the callback handler. For example, if your code was this before:
var retdata = decode('s');
// here comes code that handles retdata
put the code into a function and call it from the success handler:
function process(retdata) {
// here comes code that handles retdata
}
function decode(s){
$.ajax({type: "POST",
url: "includes/decode.inc.php",
data: "s=" + s,
success:function(newmsg){
process(newmsg);
}
});
}
This seems to be a very common problem to all beginners. You will find a lot of questions here that deal with the same problem.
Update:
It is not nice, but you could change the function to
function decode(s, cb){
$.ajax({type: "POST",
url: "includes/decode.inc.php",
data: "s=" + s,
success:function(data){
cb(data);
}
});
}
and do
decode("<?=base64_encode($path['location'])?>", function(location) {
decode("<?=base64_encode($path['base_directory'])?>", function(dir) {
embedSwf("flashgame",location,dir,"800","600" );
});
});
Update 2:
For completeness, you can make the Ajax call synchronous, by using async: false. Then this will work:
function decode(s){
var ret;
$.ajax({type: "POST",
url: "includes/decode.inc.php",
data: "s=" + s,
async: false,
success:function(newmsg){
ret = newmsg;
}
});
return sync;
}
var val = decode(s);
However, this will block the browser until the Ajax call finished. You have to test whether this matters in your case or not.
Update 3:
You could also change your PHP script to not only accept one parameter but several and process both strings in one go.

Categories