I am trying to get the string to order by how it is displayed (red,blue,orange,black). For some reason, it will append the order randomly. For Example: it would output (blue,orange,red,black). Any help would be great. Thanks.
var tCookie = "red,blue,orange,black";
var Cookies = tCookie.split(',');
if (Cookies) {
for (var i = 1; i <= Cookies.length; i++) {
var dataString = "TabId="+Cookies[i]+"";
$.ajax({
type: "POST",
url: "includes/tab.php",
data: dataString,
cache: false,
success: function(html){
$("#Dynamic_Tab").append(html).children(':last').hide().fadeIn("fast");
}
});
}
}
You could have a list of requests and responses, and start appending when all are done, so that the order is always correct:
var deferreds = [],
results = [];
for (var i = 1; i <= Cookies.length; i++) {
(function(i) { // to freeze i
var dataString = "TabId="+Cookies[i]+"";
deferreds.push($.ajax({
type: "POST",
url: "includes/tab.php",
data: dataString,
cache: false,
success: function(html){
results[i] = html; // insert at the synchronous position
}
}));
})(i);
}
$.when.apply($, deferreds).then(function() {
$.each(results, function(i, html) {
$("#Dynamic_Tab").append(html).children(':last').hide().fadeIn("fast");
});
});
You can use deferred objects here to only append the HTML after all of the AJAX requests come back:
//create array to store XHR objects that will resolve when the AJAX requests return
//also create an object to store the AJAX responses
var jqXHRs = [],
responses = {};
//iterate through each of the cookie indexes
$.each(cookies, function (index, value) {
//create the dataString and cache the value of this index so it can be used in the success callback for the AJAX request associated with this index
var dataString = "TabId=" + value,
thisValue = value;
//store an empty string in the output variable for the current index, this keeps it's place in-line
responses[thisValue] = '';
//do the AJAX request and store it's XHR object in the array with the rest
jqXHRs[jqXHRs.length] = $.ajax({
type : "POST",
url : "includes/tab.php",
data : dataString,
cache : false,
success : function (html) {
//now that the AJAX request has returned successfully, add the returned HTML to the output variable for this index
responses[thisValue] = html;
}
});
});
//wait for all of the XHR objects to resolve then add all the HTML to the DOM
$.when(jqXHRs).then(function () {
//all of the AJAX requests have come back and you can now add stuff to the DOM
var $element = $("#Dynamic_Tab");
$.each(responses, function (index, value) {
$element.append(value).children(':last').hide().delay(index * 250).fadeIn(250);
}
});
The .delay() is so that each new row will fade in, in order.
Related
I have an array of values (myarray), that I want to iterate through and run an AJAX request on each iteration. I've put each ajax request inside another array (requests), so that I can call an alert when all AJAX requests have completed:
Like so:
var requests = [];
for (i = 0; i < myarray.length; ++i) {
requests.push($.ajax({
url: 'anotherurl?=' + myarray[i],
dataType: "JSONP",
success: function (data) {
array_of_results.push(data);
}
}));
}
$.when.apply($, requests).done(function() {
alert('complete');
});
All the results are collected in array_of_results. However due to the AJAX requests taking different lengths of time to complete, this array doesn't have the results in the original order.
Is there any way to order this array?
I hope I've made sense. I appreciate this is quite convoluted.
Have you tried the following? I think this should work. All the responses should be available, in order, in the success function of the when().
var requests = [];
for (i = 0; i < myarray.length; ++i) {
requests.push($.ajax({
url: 'anotherurl?=' + myarray[i],
dataType: "JSONP"
}));
}
$.when.apply($, requests).done(function() {
array_of_results = arguments;
alert('complete');
});
Instead of using a loop consider using recursion. Here's a complete example:
var myArray = [
"somevalue",
"some other value",
"another value"
];
var i = myArray.length;
var responses = [];
function doRequests(){
i--;
$.ajax({
url: "myurl.php",
data: {paramname: myArray[i]}
}).done(function(response){
responses.push(response);
if(i>0) doRequests();
else{
// all requests sent.. do stuff
// responses array is in order
console.log(responses);
alert("all done!");
}
});
}
You can add a custom attribute to your $.ajax object, setted to your i var.
var requests = [];
for (i = 0; i < myarray.length; ++i) {
requests.push($.ajax({
url: 'anotherurl?=' + myarray[i],
dataType: "JSONP",
myCustomIndex: i,
success: function (data) {
array_of_results[this.myCustomIndex] = data;
}
}));
}
$.when.apply($, requests).done(function() {
alert('complete');
});
JavaScript is really permisive, if you attribute a value to an array out of its bounds (higher than 0), the size of the array will be automaticaly set to the right amount.
How about using jquery.ajax call with async setting as false. This way the reaponse will be in order as requested...
Building on #Christo's answer - using arrays map function
var array_of_results = [];
var requests = myarray.map(function(item, index) {
return $.ajax({
url: 'anotherurl?=' + item,
dataType: "JSONP",
success: function (data) {
array_of_results[index] = data;
}
}
});
...
I need to make 3 or less ajax calls, and the responses need to be appended to the dom in the same order they were requested.
I have the following function, but the problem is that the responses that I get are not necessarily in the correct order when they get appended to the dom.
I wouldn't want to use the async: false property because it blocks the UI and it's a performance hit of course.
mod.getArticles = function( ){
//mod.vars.ajaxCount could start at 0-2
for( var i = mod.vars.ajaxCount; i < 3; i++ ){
//mod.vars.pushIds is an array with the ids to be ajaxed in
var id = mod.vars.pushIds[i];
$.ajax({
url: '/ajax/article/' + id + '/',
type: "GET",
dataType: 'HTML',
error: function() {
console.error('get article ajax error');
}
}).done( function( data ) {
if (data.length) {
mod.appendArticle( data );
} else {
console.error('get article ajax output error');
}
});
}
};
You need to append the article to a certain position, based on for example the i variable you have. Or you could wait for all of the requests and then append them in order. Something like this:
mod.getArticles = function( ){
var load = function( id ) {
return $.ajax({
url: '/ajax/article/' + id + '/',
type: "GET",
dataType: 'HTML',
error: function() {
console.error('get article ajax error');
});
};
var onDone = function( data ) {
if (data.length) {
mod.appendArticle( data );
} else {
console.error('get article ajax output error');
}
};
var requests = [];
for( var i = mod.vars.ajaxCount; i < 3; i++ ){
requests.push(load(mod.vars.pushIds[i]));
}
$.when.apply(this, requests).done(function() {
var results = requests.length > 1 ? arguments : [arguments];
for( var i = 0; i < results.length; i++ ){
onDone(results[i][0]);
}
});
};
Here is an example using i to append them in the proper order when they all finish loading:
mod.getArticles = function( ){
// initialize an empty array of proper size
var articles = Array(3 - mod.vars.ajaxCount);
var completed = 0;
//mod.vars.ajaxCount could start at 0-2
for( var i = mod.vars.ajaxCount; i < 3; i++ ){
// prevent i from being 3 inside of done callback
(function (i){
//mod.vars.pushIds is an array with the ids to be ajaxed in
var id = mod.vars.pushIds[i];
$.ajax({
url: '/ajax/article/' + id + '/',
type: "GET",
dataType: 'HTML',
error: function() {
console.error('get article ajax error');
}
}).done( function( data ) {
completed++;
if (data.length) {
// store to array in proper index
articles[i - mod.vars.ajaxCount] = data;
} else {
console.error('get article ajax output error');
}
// if all are completed, push in proper order
if (completed == 3 - mod.vars.ajaxCount) {
// iterate through articles
for (var j = mod.vars.ajaxCount; j < 3; j++) {
// check if article loaded properly
if (articles[j - mod.vars.ajaxCount]) {
mod.appendArticle(articles[j - mod.vars.ajaxCount]);
}
}
}
});
}(i));
}
};
var success1 = $.ajax...
var success2 = $.ajax...
var success3 = $.ajax...
$.when(success1, success2, success3).apply(ans1, ans2, ans3) {
finalDOM = ans1[0]+ans2[0]+ans3[0];
}
Check this for more reference. This is still async, but it waits for all of them to complete. You know the order of invocation already, as its done through your code, so add the dom elements accordingly.
Solutions that rely solely on closures will work up to a point. They will consistently append the articles of a single mod.getArticles() call in the correct order. But consider a second call before the first is fully satisfied. Due to asynchronism of the process, the second call's set of articles could conceivably be appended before the first.
A better solution would guarantee that even a rapid fire sequence of mod.getArticles() calls would :
append each call's articles in the right order
append all sets of articles in the right order
One approach to this is, for each article :
synchronously append a container (a div) to the DOM and keep a reference to it
asynchronously populate the container with content when it arrives.
To achieve this, you will need to modify mod.appendArticle() to accept a second parameter - a reference to a container element.
mod.appendArticle = function(data, $container) {
...
};
For convenience, you may also choose to create a new method, mod.appendArticleContainer(), which creates a div, appends it to the DOM and returns a reference to it.
mod.appendArticleContainer = function() {
//put a container somewhere in the DOM, and return a reference to it.
return $("<div/>").appendTo("wherever");
};
Now, mod.getArticles() is still very simple :
mod.getArticles = function() {
//Here, .slice() returns a new array containing the required portion of `mod.vars.pushIds`.
//This allows `$.map()` to be used instead of a more cumbersome `for` loop.
var promises = $.map(mod.vars.pushIds.slice(mod.vars.ajaxCount, 3), function(id) {
var $container = mod.appendArticleContainer();//<<< synchronous creation of a container
return $.ajax({
url: '/ajax/article/' + id + '/',
type: "GET",
dataType: 'HTML'
}).then(function(data) {
if (data.length) {
mod.appendArticle(data, $container);//<<< asynchronous insertion of content
} else {
return $.Deferred().reject(new Error("get article ajax output error"));
}
}).then(null, function(e) {
$container.remove();//container will never be filled, so can be removed.
console.error(e);
return $.when(); // mark promise as "handled"
});
});
return $.when.apply(null, promises);
};
mod.getArticles() now returns a promise of completion to its caller, allowing further chaining if necessary.
Try utilizing items within mod.vars array as indexes; to set as id property of $.ajaxSettings , set returned data at this.id index within an array of responses. results array should be in same order as mod.vars values when all requests completed.
var mod = {
"vars": [0, 1, 2]
};
mod.getArticles = function () {
var results = [];
var ids = this.vars;
var request = function request(id) {
return $.ajax({
type: "GET",
url: "/ajax/article/" + id + "/",
// set `id` at `$.ajaxSettings` ,
// available at returned `jqxhr` object
id: id
})
.then(function (data, textStatus, jqxhr) {
// insert response `data` at `id` index within `results` array
console.log(data); // `data` returned unordered
// set `data` at `id` index within `results
results[this.id] = data;
return results[this.id]
}, function (jqxhr, textStatus, errorThrown) {
console.log("get article ajax error", errorThrown);
return jqxhr
});
};
return $.when.apply(this, $.map(ids, function (id) {
return request(id)
}))
.then(function () {
$.map(arguments, function (value, key) {
if (value.length) {
// append `value`:`data` returned by `$.ajax()`,
// in order set by `mod.vars` items:`id` item at `request`
mod.appendArticle(value);
} else {
console.error("get article ajax output error");
};
})
});
};
mod.getArticles();
jsfiddle http://jsfiddle.net/6j7vempp/2/
Instead of using a for loop. Call your function in response part of previous function.
//create a global variable
var counter = 0;
function yourFunc(){
mod.getArticles = function( ){
//mod.vars.ajaxCount could start at 0-2
//mod.vars.pushIds is an array with the ids to be ajaxed in
var id = mod.vars.pushIds[counter ];
$.ajax({
url: '/ajax/article/' + id + '/',
type: "GET",
dataType: 'HTML',
error: function() {
console.error('get article ajax error');
}
}).done( function( data ) {
if (data.length) {
mod.appendArticle( data );
} else {
console.error('get article ajax output error');
}
//increment & check your loop condition here, so that your responses will be appended in same order
counter++;
if (counter < 3)
{ yourFunc(); }
});
};
}
I'm faced same problem i'm solve this problem using following way.
just use async for get sequence wise response
<script type="text/javascript">
var ajax1 = $.ajax({
async: false,
url: 'url',
type: 'POST',
data: {'Data'},
})
.done(function(response) {
console.log(response);
});
I have a series of ajax calls that fill columns on a page.
var doneDefers = function(defer) {
// leftColDefer is another deferred that sets some header info
$.when(defer, leftColDefer).done(function(req1, req2){
var data = req1[0],
head = req2[0];
// spit this data out to elements on the page
});
};
for(i=0;i<window.ids.length;i++){
defer[i] = $.ajax({
url: 'api/get_runs_stats.php',
type: 'GET',
dataType: 'json',
data: {
run_id: window.ids[i]
}
});
doneDefers(defer[i]);
}
This works fine. If an ajax call fails, nothing is spit out and all is right with the world.
Now I want to do some calculations based on all the data that got spit out.
$.when.apply(null, defer)
.done(function() {
var args = Array.prototype.slice.call(arguments);
calcDeltas();
})
.fail(function() {
var args = Array.prototype.slice.call(arguments);
console.log('in list fail');
});
The done function works fine none of the ajax calls fail. If one of them fail, I go into the fail function and I don't have access to any of the return data from the other runs. The arguments array only has the failed call's data.
I would like to do my calculations on the data sets that passed. How can I get to the data from the good calls when one of them fails?
I'm not sure this is the simplest solution but it stands a chance of working.
var ajax_always_promises = [],//to be populated with promises that (barring uncaught error) are guaranteed to be resolved.
data_arr = [],//an array to be (sparsely) populated with asynchronously delivered json data.
error_arr = [];//an array to be (sparsely) populated with ajax error messages.
$.each(window.ids, function(i, id) {
var dfrd = $.Deferred();
var p = $.ajax({
url: 'api/get_runs_stats.php',
type: 'GET',
dataType: 'json',
data: {
run_id: window.ids[i]
}
}).done(function(json_data) {
data_arr[i] = json_data;//intentionally not `data_arr.push(json_data);`
}).fail(function(jqXHR, textStatus, errorThrown) {
error_arr[i] = textStatus;//intentionally not `error_arr.push(textStatus);`
}).always(dfrd.resolve);
ajax_always_promises[i] = dfrd.promise();
doneDefers(p);
});
$.when.apply(null, ajax_always_promises).done(function() {
//The data in the (sparsely) populated arrays `data_arr` and `error_arr` is available to be used.
var i, id, success_count=0, error_count=0;
for(i=0; i<Math.max(data_arr.length,error_arr.length); i++) {
//Here, the index i corresponds to the original index of window.ids ...
//...that's the advantage of sparsely populating the arrays.
id = window.ids[i];
if(data_arr[i]) {
//Here, do whatever is required with `data_arr[i]`, and `id` if needed.
success_count++;
}
else if(error_arr[i]) {
//Here, do whatever is required with `error_arr[i]`, and `id` if needed.
error_count++;
}
}
console.log("Success:errors: " + success_count + ':' + error_count);
});
Untested - may well need debugging
I am creating new functionality where I build a grid based on Json data returned from Ajax. I have decided I want to encapsulate this functionality within a function, so when I add/update/delete, I can on success retrieve a new representation of the data.
The problem I am having is I want to fill a global array but once my function that uses AJAX ends, I have an Array but no data. This isn't a problem when all the code is within the AJAX call but once I try to separate this in to its own function, it doesn't work as intended.
<script type="text/javascript">
var DataArray = [];
// Use this function to fill array
function retrieveNotes() {
$.ajax({
url: "http://wks52025:82/WcfDataService.svc/GetNotesFromView()?$format=json",
type: "get",
datatype: "json",
asynch:true,
success: function (data) {
returnedData = data;
$.each(data.d, function (i, item) {
DataArray[i] = [];
DataArray[i][0] = item.NotesTitle.trim();
DataArray[i][1] = item.ProfileName.trim();
DataArray[i][2] = item.IsShared;
DataArray[i][3] = item.NameOfUser.trim();
}) // End of each loop
}
});
}
$(document).ready(function () {
retrieveNotes();
DataArray;
</script>
It's asynchronous, so you'll have to wait for the ajax call to finish before you can use the data :
function retrieveNotes() {
return $.ajax({
url: "http://wks52025:82/WcfDataService.svc/GetNotesFromView()?$format=json",
type: "get",
datatype: "json"
});
}
$(document).ready(function () {
retrieveNotes().done(function(data) {
var DataArray = [];
$.each(data.d, function (i, item) {
DataArray[i] = [];
DataArray[i][0] = item.NotesTitle.trim();
DataArray[i][1] = item.ProfileName.trim();
DataArray[i][2] = item.IsShared;
DataArray[i][3] = item.NameOfUser.trim();
});
// you can only use the data inside the done() handler,
// when the call has completed and the data is returned
});
});
Hey all I am working on a json call that will implement Drupal's services module with json. I am using jquery's ajax function to call the function but I am getting an error stating that no parameters are being passed. When I look at the query string being posted I notice that sessid is not being passed even though its with the parameters. Below is what Im running.
// JavaScript Document
$(document).ready(function() {
function drupalConnect(src) {
$.ajax({
url: src,
type: 'POST',
data: {
method: 'system.connect'
},
success: function(data) {
return data["result"]["sessid"];
}
});
}
function getTimestamp() {
return Math.round((new Date).getTime() / 1000);
}
function randString(length) {
var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz";
var randomstring = '';
for (var i = 0; i < length; i++) {
var rnum = Math.floor(Math.random() * chars.length);
randomstring += chars.substring(rnum, rnum + 1);
}
return randomstring;
}
var session_id = drupalConnect('http://localhost/drupal/services/json-rpc');
var nonce = randString(10);
var timestamp = getTimestamp();
var username = "markusgray";
var password = "Markus1990";
var key = '2ae0392e0aebbfeeddefcc962ea1924f';
var domain = 'localhost';
var hashObj = new jsSHA(timestamp + ";" + domain + ";" + nonce + ";user.login", "TEXT");
var hash = hashObj.getHMAC(key, "TEXT", "SHA-256", "HEX");
var parameters = {
hash: hash,
domain_name: domain,
domain_time_stamp: timestamp,
nonce: nonce,
sessid: session_id,
username: username,
password: password
};
var par = JSON.stringify(parameters);
$.ajax({
url: 'http://localhost/drupal/services/json-rpc',
type: 'POST',
dataType: 'json',
data: {
method: 'user.login',
params: par
},
success: function() {
}
});
});
drupalConnect doesn't return anything, also the return from the success callback is just thrown away. The best way to use the data returned from an ajax call is to use it in thee callback itself.
function drupalConnect(src){
$.ajax({
url: src,
type: 'POST',
data:{method:'system.connect'},
success: function(data){
var session_id = data["result"]["sessid"];
//use session_id here
}
});
}
It is because of the Asynchronous ajax, let me elaborate, to get the session_id you are making an ajax call. At the moment it will send the request, but it wont ensure that the session_id will be assigned at that moment. Hence when you making the second ajax call, the session_id may not be assigned for a value.
There are two workarounds for this,
One is, making the first ajax call with an option async:false and assign the value within the success call, something like
var session_id;
function drupalConnect(src) {
$.ajax({
url: src,
type: 'post',
async : false,
data: {
method: 'system.connect'
},
success: function(data) {
session_id = data["result"]["sessid"];
}
});
};
DEMO
The second one and preferred way is, use of deferred objects, something like
$.when(
// make your first ajax request
).then(function(data) {
session_id = data["result"]["sessid"];
// make your second ajax call
});
DEMO