Sequential ajax queries with jquery - javascript

I've spent quite a while trying to figure this out with various iterations of code, but with no luck. Coming from a php background I am new to javascript.
assume an array of three patches: patch1, patch2, patch3.
What I'm trying to achieve is:
an ajax call to the same php script for each patch, but each call must be made only after the previous call is completed
After all 3 are complete an ajax call to a separate php script is made.
Point 2 is working fine, point 1 not so.
Below is my code: the myAjaxInitialData func (and the underlying php script) is being called simultaneously for all 3 patches, rather than waiting for each to complete. The myAjaxGetSRCount is, correctly, not being called unitl all the patches are complete.
<body onload="initialData(0)">
<script>
function initialData(i) {
var patches = [<?php echo $jsPatchArray ?>];
var x = patches.length - 1;
var divId = "#initialData-patch-" +i;
var script = "ajax_initial_data.php";
var dataVar = "patch";
var data = patches[i];
if ( i != x) {
i++;
$.when(myAjaxInitialData(divId,script,dataVar,data)).then(initialData(i));
} else {
$.when(myAjaxInitialData(divId,script,dataVar,data)).then(myAjaxGetSRCount);
}
}
function myAjaxInitialData(divId,script,dataVar,data ) {
return $.ajax({
type: "GET",
url: script,
data: {patch:data},
success: function( response ) {
$( divId ).html( response );
}
});
}
function myAjaxGetSRCount() {
document.getElementById('srCount').innerHTML="Retrieving SR Counts..";
$.ajax({
type: "GET",
url: "ajax_sr_count.php",
success: function( response ) {
$( "#srCount" ).html( response );
}
});
}
</script>

Your problem seems to be here:
$.when(myAjaxInitialData(divId,script,dataVar,data)).then(initialData(i));
then takes a callback, i.e. a function. initialData(i) doesn't return anything so you are passing undefined into this function. If you mean to call initialData after this ajax request then you need to wrap it in a parameter-less function.
$.when(myAjaxInitialData(divId,script,dataVar,data)).then(function() { initialData(i); });
You should also be very aware that the value of i will be the value at the time of the callback. When closing over iterator variables, you should capture the value you expect before you create the callback. I.e.
if (i != x) {
i++;
var j = i;
$.when(myAjaxInitialData(divId,script,dataVar,data)).then(function() { initialData(j); });
}

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.

While loop with jQuery async AJAX calls

The thing:
I have a page, which has to display undetermined number of images, loaded through AJAX (using base64 encoding on the server-side) one by one.
var position = 'front';
while(GLOB_PROCEED_FETCH)
{
getImageRequest(position);
}
function getImageRequest(position)
{
GLOB_IMG_CURR++;
$.ajax({
url: urlAJAX + 'scan=' + position,
method: 'GET',
async: false,
success: function(data) {
if ((data.status == 'empty') || (GLOB_IMG_CURR > GLOB_IMG_MAX))
{
GLOB_PROCEED_FETCH = false;
return true;
}
else if (data.status == 'success')
{
renderImageData(data);
}
}
});
}
The problem is that images (constructed with the renderImageData() function) are appended (all together) to the certain DIV only when all images are fetched. I mean, there is no any DOM manipulation possible until the loop is over.
I need to load and display images one by one because of possible huge number of images, so I can't stack them until they all will be fetched.
Your best bet would be to restructure your code to use async ajax calls and launch the next call when the first one completes and so on. This will allow the page to redisplay between image fetches.
This will also give the browser a chance to breathe and take care of its other housekeeping and not think that maybe it's locked up or hung.
And, use async: 'false' is a bad idea. I see no reason why properly structured code couldn't use asynchronous ajax calls here and not hang the browser while you're fetching this data.
You could do it with asynchronous ajax like this:
function getAllImages(position, maxImages) {
var imgCount = 0;
function getNextImage() {
$.ajax({
url: urlAJAX + 'scan=' + position,
method: 'GET',
async: true,
success: function(data) {
if (data.status == "success" && imgCount <= maxImages) {
++imgCount;
renderImageData(data);
getNextImage();
}
}
});
}
getNextImage();
}
// no while loop is needed
// just call getAllImages() and pass it the
// position and the maxImages you want to retrieve
getAllImages('front', 20);
Also, while this may look like recursion, it isn't really recursion because of the async nature of the ajax call. getNextImage() has actually completed before the next one is called so it isn't technically recursion.
Wrong and wrong. Don't user timers, don't chain them. Look at jQuery Deferred / when, it has everything you need.
var imgara = [];
for (image in imglist) {
imgara[] = ajax call
}
$.when.apply($, imgara).done(function() {
// do something
}).fail(function() {
// do something else
});
Try using setInterval() function instead of while().
var fetch = setInterval(loadImage, 2000);
function loadImage(){
position= new position; //Change variable position here.
getImageRequest(position);
if(!GLOB_PROCEED_FETCH){
clearInterval(fetch);
}
}

get a callback function to add to object javascript

I have an issue with a method ive created for an object ive created. one of the methods requires a callback to another method. the problem is i cant add the data to the object that called the method. it keeps coming back as undefined. otherwise when i send the data to the console it is correct. how can i get the data back to the method?
var blogObject = new Object();
var following = [...];
//get posts from those blogs
blogObject.getPosts = function () {
var followersBlogArray = new Array();
for (var i = 0; i < this.following.length;i++){
var followersBlog = new Object();
// get construct blog url
var complete_blog_url = ...;
i call the getAvatar function here sending the current user on the following array with it.
followersBlog.avatar = blogObject.getAvatar(this.following[i]);
that part goes smoothly
followersBlogArray.push(followersBlog);
}
this.followersBlogArray = followersBlogArray;
}
here is the function that gets called with the current user in following array
this function calls an ajax function
blogObject.getAvatar = function (data) {
console.log("get avatar");
var url = "..."
this ajax function does its work and has a callback function of showAvatar
$(function() {
$.ajax({
type: "GET",
dataType: "jsonp",
cache: false,
url: url,
data: {
jsonp:"blogObject.showAvatar"
}
});
});
}
this function gets called no problem when getAvatar is called. i cant however get it to add the data to the followersBlog object.
blogObject.showAvatar = function (avatar) {
return avatar
}
everything in here works fine but i cant get the showAvatar function to add to my followersBlog object. ive tried
blogObject.showAvatar = function (avatar) {
this.followersBlog.avatar = avatar;
return avatar
}
that didnt work of course. it shows up as undefined. can anyone help?
so somethings like...
$(function() {
$.ajax({
type: "GET",
dataType: "jsonp",
cache: false,
url: url,
complete: function () {
this.avatar = data;
}
data: {
jsonp:"blogObject.showAvatar"
}
});
});
}
Welcome to the world of asynchronous programming.
You need to account for the fact that $.ajax() will not return a value immediately, and Javascript engines will not wait for it to complete before moving on to the next line of code.
To fix this, you'll need to refactor your code and provide a callback for your AJAX call, which will call the code that you want to execute upon receiving a response from $.ajax(). This callback should be passed in as the complete argument for $.ajax().
The correct option for setting the JSONP callback is jsonpCallback. The recommendation from the API for .ajax(...) is to set it as a function.
{
// ...
jsonpCallback: function (returnedData) {
blogObject.showAvatar(returnedData);
},
// ...
}

my function can't pass it's parameter value javascript

Ive been struggling to pass my parameters from a functions but I just really can't figure out where did I go wrong. I have a function that have a parameters that I want to pass to my postData to display datas in my jQgrid. Here's my function code with parameters:
function getTID(hdrID){
var selected = $('#editTallyHdr').val();
var hdrID = '';
var hdrNo = '';
var nameFlag=0;
var par_ams = {
"SessionID": $.cookie("SessionID"),
"dataType": "data"
};
$.ajax({
type: 'GET',
url: 'processjson.php?' + $.param({path:'getData/tallyHdr',json:JSON.stringify(par_ams)}),
dataType: primeSettings.ajaxDataType,
success: function(data) {
if ('error' in data)
{
showMessage('ERROR: ' + data["error"]["msg"]);
}
else{
$.each(data['result']['main']['rowdata'], function(rowIndex, rowDataValue) {
$.each(rowDataValue, function(columnIndex, rowArrayValue) {
var fldName = data['result']['main']['metadata']['fields'][columnIndex].name;
if (fldName == 'transaction_id'){
hdrID = rowArrayValue;
}
if (fldName == 'transaction_num'){
hdrNo = rowArrayValue;
if(selected == hdrNo){
nameFlag =1;
};
}
});
});
}
}
});
return (hdrID);
}
and here is my jQgrid code where I call that function to get it's parameter:
$("#tblPlank").jqGrid({
url: '',
datatype: 'local',
jsonReader : {
.
.
.
serializeGridData: function(postData) {
var ctr =0;
var filt=[];
var c=[];
var jsonParams = {
'SessionID': $.cookie("SessionID"),
'dataType': 'data',
'transaction_id':getTID(hdrID),
'filters': c,
'lines':plank_data,
'recordLimit': postData.rows,
'recordOffset': postData.rows * (postData.page - 1),
'rowDataAsObjects': false,
'queryRowCount': true,
'sort_fields': postData.sidx
};
.
.// some code here
.
.
return 'json=' + JSON.stringify(jsonParams);
},
loadError: function(xhr, msg, e) {
showMessage('HTTP error: ' + JSON.stringify(msg) + '.');
},
colNames:[...],
colModel:[
........................
],
.
.
.
caption: "Tally Transaction Details/Lines"
I also have another code where I want to get that parameter. Here's the last code:
var par_ams = {
"SessionID": $.cookie("SessionID"),
"dataType": "data",
"transaction_id": getTID(hdrTID)
}
$('#tblPlank').setGridParam({
url:'processjson.php?path=' + encodeURI('getData/tallyLnDtl') + '&json=' + encodeURI(JSON.stringify(par_ams)),
datatype: primeSettings.ajaxDataType,
});
$('#tblPlank').trigger('reloadGrid');
Those codes below that function getTID(hdrID) cant retrieve the parameter, it shows empty. This maybe simple to anyone, but I really need help on this.. been working with this for quite long hours.
This is a very common misunderstanding. I've probably answered 15 of these questions in the last two weeks alone. An ajax call is an asynchronous call. That means that when you make the ajax call, it just STARTs the request. Then, while that request goes in the background, your code immediately keeps executing. That means that your function getTID() returns before the ajax call has even completed and it's value is not yet known. Thus, there is no way to return the response value from the ajax function when you return from getTID() as it is simply not known yet.
To work with asynchronous function calls (like ajax calls), you have to change your programming style to something that works asynchronously. In this case, the response to your ajax call is ONLY known in the success handler for the ajax all. So, you have to restructure your code to continue on with the execution of your processing and the handling of the ajax response from the success handler. If you have only a little bit of work to do, then you can put it all in the success handler. If you have a lot of work to do, then you can put all the rest of that work in a function call and call it from the success handler.
The problem is that you're doing an ajax-request (asynchronous request). Then the function does not wait for an answer to arrive, but just continues and returns hdrID (which isn't set at the time). After that a response comes in, and the success-method is called, which sets hdrID to the appropiate value.
The common way to solve this is to execute a specific function with the desired values when the success-method is executed. It's too much code to look into, but it could go something like this:
function fetchContent(continueFunction) {
$.ajax(params).success(function(reply) {
// retrieve desired params from reply
continueFunction(retrievedParameters);
}
}
What you could do is define getTID to take in a callback to execute once it has the id, for instance
function getTID(hdrID, callback) {
//ajax stuff....
success: function (data) {
// Error checks, etc
hdrID = //something dependent on data
callback(hdrID); // THIS IS THE IMPORTANT PART
}
the callback will execute after the request has returned, when it is safe to use the data returned from the ajax request that will be needed in the callback. You could wrap all of the code that needs the return value of the request in the callback, for example
getTID(hdrID, function (ID) {
var params = {
"SessionID": $.cookie("SessionID"),
"dataType": "data",
"transaction_id": ID //USE ID
}
$('#tblPlank').setGridParam({
url:'processjson.php?path=' + encodeURI('getData/tallyLnDtl') + '&json=' + encodeURI(JSON.stringify(par_ams)),
datatype: primeSettings.ajaxDataType,
});
$('#tblPlank').trigger('reloadGrid');
};
});

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