I'm trying to get a list of JSON objects (products) from a local file using Jquery and store all the objects in a single array called allItems. The file is co-located in the same directory as the code, and it's called "allItems.json". Here's how I'm doing it now:
function getAllSupportedItems(){
var allItems = new Array();
$.getJSON("allItems.json",
function(data){
$.each(data.items,
function(item){
allItems.push(item);
});
});
return allItems;
}
Based on this example: http://api.jquery.com/jQuery.getJSON/
For getAllSupportedItems to be able to return any items, the AJAX call needs to run synchronously.
getJSON translates to the following asynchronous call:
$.ajax({
url: url,
dataType: 'json',
data: data,
success: callback
});
Asynchronous is the default. You therefore need to explicitly change your request to a synchronous one:
$.ajax({
url: url,
dataType: 'json',
data: data,
success: callback,
async: false
});
An alternative is to rethink the way you use getAllSupportedItems and make it into an asynchronous utility:
function getAllSupportedItems(callback){
$.getJSON("allItems.json",
function(data){
var allItems = [];
$.each(data.items,
function(item){
allItems.push(item);
});
callback(allItems);
// callback(data.items); should also work
});
}
Update
When I initially wrote this answer, jQuery didn't have built-in Deferred support. It is a lot more concise and flexible to do something like this today:
function getAllSupportedItems( ) {
return $.getJSON("allItems.json").then(function (data) {
return data.items;
});
}
// Usage:
getAllSupportedItems().done(function (items) {
// you have your items here
});
How are you using this? If you're expecting the main function ("getAllSupportedItems") to return the array you make, well that won't work. The $.getJSON function is asynchronous, and so the handler won't actually build the array until after the outer function has returned.
Related
I'm working in my own rss reader using JS, JQuery and PHP for serving the data as JSON. What I'm doing basically is making async calls to my server to get JSONs with the posts, then on 'success' I parse them using a '$.each' and with JQuery load the content in the DOM.
All of this operations were made async, but now I need to call them in a certain order, and when everithin is done THEN calling a function to process the data.
To give you some background on my task, what I'm doing is a query over a small list of RSS sources to get just the very latest post. With them I concat a string and this string is passed to a text-to-speech service.
I've managed to make it work using an arbitrary setTimeout value of 10 seconds, but my goal is to call the function when all the sources have been processed.
This is a basic version of my parser:
function urgent_posts(url) {
$.ajax({
//the location of my server
url: 'myPostServer.php?url=' + encodeURIComponent(url),
dataType: 'json',
success: function(data) {
//do this for each entry in the feed
$.each(data.feed.entries, function(key, value) {
//validate the date to get just the latest post
if (is_urgent(value.publishedDate)) {
//if condition is met save the title
save_urgent_post_title(value.title);
}
});
}
});
}
What I did to 'make it work' was the following:
$('#test_button').on('click',function(){
urgent_posts(source_1);
urgent_posts(source_2);
urgent_posts(source_3);
//and so on...
urgent_posts(source_n);
setTimeout(function(){
text_to_speech(get_urgent_post_string);
},10000);
});
I tried with no result to make use of the deferred object y JQuery like this:
function urgent_posts(url) {
var deferred = $.Deferred();
$.ajax({
//the location of my server
url: 'myPostServer.php?url=' + encodeURIComponent(url),
dataType: 'json',
success: function(data) {
//do this for each entry in the feed
$.each(data.feed.entries, function(key, value) {
//validate the date to get just the latest post
if (is_urgent(value.publishedDate)) {
//if condition is met save the title
save_urgent_post_title(value.title);
}
});
}
});
return deferred.promise();
}
And chaining everything together:
$('#test_button').on('click',function(){
urgent_posts(source_1)
.then(urgent_posts(source_2))
.then(urgent_posts(source_3))
.then(function(){
text_to_speech(get_urgent_post_string);
});
});
I'd apreciatte your comments and suggestions.
First, your deferred object is never resolved. You have to add the deferred.resolve() somewhere. Just after the $.each loop looks like a nice place.
Second, $.ajax already returns a promise. So you can just write this :
return $.ajax({
//the location of my server
url: 'myPostServer.php?url=' + encodeURIComponent(url),
dataType: 'json',
success: function(data) {
//do this for each entry in the feed
$.each(data.feed.entries, function(key, value) {
//validate the date to get just the latest post
if (is_urgent(value.publishedDate)) {
//if condition is met save the title
save_urgent_post_title(value.title);
}
});
}
});
I manage to solve the problem using this article: link
The refactored code looks like this now:
function urgent_posts_feed_1(callback) {
return $.ajax({
//the location of my server
url: 'myPostServer.php?url=' + encodeURIComponent(feed_1),
dataType: 'json',
success: function(data) {
//do this for each entry in the feed
$.each(data.feed.entries, function(key, value) {
//validate the date to get just the latest post
if (is_urgent(value.publishedDate)) {
//if condition is met save the title
save_urgent_post_title(value.title);
}
});
}
});
}
I repeat myself (I know it's not cool to do so) and write the following functions manually setting the url:
urgent_posts_feed_2
urgent_posts_feed_3
urgent_posts_feed_4
...
urgent_posts_feed_n
And finally...
urgent_post_feed_1()
.then(urgent_post_feed_2)
.then(urgent_post_feed_3)
//...
.then(urgent_post_feed_n)
.then(function(){
text_to_speech(get_urgent_post_string);
});
This way it works like a charm. Now I have to figure out how to pass parameters to the function and not interfer with the callback.
Like in this article, I have several ajax requests to perform followed by 1 action.
However, the difference is that all my ajax request only differ by one incremental parameter like this:
$.when(
// ajax requests
// 1
$.ajax({
url:"https://www.aaaaaaa.com?param="+0,
crossDomain: true,
dataType: "jsonp",
success: function (response) {
data = data.concat(response);
}
}),
// 2
$.ajax({
url:"https://www.aaaaaaa.com?param="+2500,
crossDomain: true,
dataType: "jsonp",
success: function (response) {
data = data.concat(response);
}
}),
// 3
$.ajax({
url:"https://www.aaaaaaa.com?param="+5000,
crossDomain: true,
dataType: "jsonp",
success: function (response) {
data = data.concat(response);
}
})
// etc. ~10 times
).then(function() {
// action
console.log(data);
});
Like python I don't like to repeat myself 10 times.
I tried to make a for loop but it seems not possible to write for loops in the $.when().
Any ideas how to achieve this ?
I searched everywhere whithout results.
Many thanks,
What should probably work is to define a function before your $.when something like this:
function createRequest(port) {
return $.ajax({
url:"https://www.aaaaaaa.com?param="+port,
crossDomain: true,
dataType: "jsonp",
success: function (response) {
data = data.concat(response);
}
})
}
and then use that in your $.when
$.when(createRequest(0), createRequest(2500), createRequest(5000));
And if you want to create this function call dynamically with more parameters you can create an array of these requests for-loop and then call $.when.apply(this, array)
$.when.apply(this, your_request_array)
See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply
Hope this helps
You can use Kriskowal's q implementation : https://github.com/kriskowal/q
there is a method Q.allSettled(arrayOfPromises) that suits your needs.
eg :
Q.allSettled(promises)
.then(function (results) {
results.forEach(function (result) {
if (result.state === "fulfilled") {
var value = result.value;
} else {
var reason = result.reason;
}
});
});
Angular has based his $q directive on this
Just put your promises in an array:
var promises = [0, 2500, 5000].map(function(n) {
return $.ajax(...); // appending `n` to the URL as required
});
and then call $.when.apply:
$.when.apply($, promises).then(...)
The parameters passed to the .then callback will be individual arrays, each containing the three parameters that a single $.ajax callback receives.
BTW, your current code will concat the arrays in whatever order the calls complete, not necessarily in the order they were started.
If the order of concatenation matters, you should use those .then function parameters rather than your existing success handlers to create your data variable:
then(function() {
var data = [];
[].forEach.apply(arguments, function(response) {
data = data.concat(response[0]);
});
});
I'm experiencing the following problem.
I have the following nested / foreach loops ajax call structure:
var children = [];
$.fn.ajaxHelper.loadAjax({
url: someUrlReturningJsonOfChildren,
cache: true,
callback: function(options) {
var json = options.json;
$.each(json, function (i) {
// get the details of this child
$.fn.ajaxHelper.loadAjax({
url: urlForDetailsUsingId,
cache: true,
callback: function(options) {
var json = options.json;
children[i] = json;
}
});
}
}
});
// want to do something with (newly filled) children here
As you can imagine, I'm running into the trouble that the ajax calls are asynchronous (duh), but I want to do something with the children array only when all the ajax calls are done. Otherwise I'm obviously dealing with an incomplete array.
I have been looking at some jQuery solutions such as Deferred objects (using $.when().then() and such), but that would only solve the problem if I would not have the foreach-loop (as far as I can tell).
Also, changing the REST API (where the ajax calls are going) is not an option unfortunately, due to specified requirements regarding the API.
Ok, so without further ado: can anyone of you geniuses help me with this? :-)
ajax is asynchronous by default but you can turn it off. Here goes the API on how to do it
https://api.jquery.com/jQuery.ajax/
heres a little demp
$.ajax({
url: my_url.php,
type: "POST",
async: false,
dataType: 'json'
});
Or just make your next ajax call in a success function (Recommended)
function testAjax(handleData) {
$.ajax({
url:"getvalue.php",
success:function(data) {
//next ajax call here
}
});
}
You must run ajax query when previous query is completed with success (in jQuery onSuccess callback)
I had a smiler issue... below is a simplified version of my solution.
Step one: Declare global variables.
var results1,
results2,
[resultsN];
Step two: Make a function that accepts the results of each AJAX call as parameters.
function foo(results1, results2, [resultsN]) {
if (results1, results2, [resultsN]) {
//... do whatever you want with all of your results
}
}
Step three: Call all of the AJAX functions, set results to global variables, and call function foo for each.
function ajax() {
//AJAX call 1
$.ajax({
type: 'POST',
url: //URL,
success: function (data, textStatus, jqXHR) {
results1 = data;
},
dataType: 'json',
complete: function () {
foo(results1, results2);
}
});
//AJAX call 2
$.ajax({
type: 'POST',
url: //URL,
success: function (data, textStatus, jqXHR) {
results2 = data;
},
dataType: 'json',
complete: function () {
foo(results1, results2);
}
});
};
This method has the advantage of running as fast as the longest AJAX call takes. If you simply nest AJAX queries in the complete event then you will have to wait for each AJAX call to complete before moving to the next one...
i have small issue with exchanging data in between methods in a JavaScript object (class):
var TEST = (function () {
var TEST = function() {
};
TEST.prototype.get = function() {
$.ajax({
type: "GET",
url: "http://test.com/getall",
dataType: "json",
success: function (data) {
return data; // if i console log this i will get a json obj
}
});
};
TEST.prototype.parse = function(data) {
$.each(this.get(), function(k, v){
console.log(v);
});
};
return TEST;
})();
so i am trying to call one method in the each statement in another method. the issue is that
the response is undefined.
i also tried it like this, but with he same result
var testing = new TEST();
var get = testing.get();
testing.parse(get);
What am i missing? how can i return the data from this.get to be used in this.parse.
thanks
$.ajax() per default is asynchronous. That means, that the execution of your function get() wont wait until the request is finished. Hence you return no value from it, which results in undefined being returned.
In order to have your get() function be able to return a value, you would have to do the request in a synchronous way and set a variable in the outer function (as success itself is just another function, whose return value is not caught):
TEST.prototype.get = function() {
var result;
$.ajax({
type: "GET",
url: "http://test.com/getall",
async: false, // this is the important part!
dataType: "json",
success: function (data) {
result = data;
}
});
return result;
};
EDIT
As mentioned by #pebbl, this will halt the execution of all your scripts, until the request is done. Hence your whole page will be blocked for the time being.
The general approach is to use callbacks in such cases, which will be executed once the requests finished. So in your case something like this:
TEST.prototype.get = function( cb ) {
$.ajax({
type: "GET",
url: "http://test.com/getall",
dataType: "json",
success: function (data) {
cb( data );
}
});
};
with later on calling like this:
var testing = new TEST();
testing.get( function( data ) {
testing.parse( data );
});
You can't construct your function this way as you are relying on an asyncronous call, which will return it's result outside of the normal execution flow. The only way you can actually receive the result of your .get function is to use a callback.
Put simply your value isn't being returned from the .get function, it's being returned from the callback you are passing into jQuery's .ajax method.
You'd be far better off redesigning your code so as to still support the asyncronous call -- rather than disabling async.
A rough idea is to change your parse function like so:
TEST.prototype.parse = function(data) {
this.get(function(result){
$.each(result, function(k, v){
console.log(v);
});
});
};
And to change your get function accordingly:
TEST.prototype.get = function(callback) {
$.ajax({
type: "GET",
url: "http://test.com/getall",
dataType: "json",
success: callback
});
};
The above is just a quick example, you'd be wise reading up on the following jQuery topics:
http://api.jquery.com/promise/
http://api.jquery.com/category/deferred-object/
If you design your code around the promise pattern you'll find it complicated at first, but it gives you a lot of power in your code -- and gets around the whole callback stacking madness you can end up with when dealing in ajax calls.
Whilst it's not entirely clear from the jQuery.ajax documentation, this function returns a jqXHR object which implements the promise interface. So this means you can use the promise methods done, always and fail.
http://api.jquery.com/jQuery.ajax/
Got some basic problem again.
I need to modify a function that previously returned a in code written object.
Im now trying to get the object from json through $.getJSON
function getEventData() {
var result = '';
$.getJSON("ajax.php?cmd=getbydate&fromdate=&todate=", function(data) {
result = data;
});
return result;
}
Problem is that result isn't set in the callback function for obvious reasons.
Do you guys have a solution for this?
Edit:
Ok i got an answer that was removed.
I just had to change it abit..
This is the answer that works:
function getEventData() {
var result = '';
url = "ajax.php?cmd=getbydate&fromdate=&todate=";
$.ajax({
url: url,
async: false,
dataType: 'json',
success: function(data) {
result = data;
}
});
return result;
}
You should program your application in an asynchronous way, which means, that you should use callback functions for you application flow, too, or continue in the getJson callback function. You can also make the request synchronously which should then be able to return the value (or at least assign it and block the function till the callback is completed), but this is not recommended at all:
function getEventData() {
var result = '';
result = $.ajax({
url: "ajax.php?cmd=getbydate&fromdate=&todate=",
async: false,
dataType: "json",
data: data,
success: function(data) {
return data;
}
});
return result;
}
Are you sure that the server returns valid json? It will be better to validate it using a tool like jsonlint. Also make sure that application/json is used as content type for the response.