I am starting out with developing Win8 App with Javascript. I am new to javascript hence I am not too strong with the language. I am trying to parse a json response in my code and store it in an array. Now I want the array to be of objects with particular properties which I am trying to set in the steps of parsing.
But, it seems that the array is not getting updated within the WinJS.xhr portion. To make it more clear, the REF 1(comment in the code below) console output works fine, but REF 2(comment in the code below) console output throws an error as follows:
JavaScript runtime error: Unable to get property 'Name' of undefined
or null reference
var sampleArr = new Array();
WinJS.xhr({ url: "http://some-api-with-json-response" }).then(
function (response) {
var name= JSON.parse(response.responseText);
sampleArr[0] = { Name: name.title };
console.log("First chance:" + sampleArr[0].Name); //REF 1
item_number++;
};
console.log("Second chance:" + sampleArr[0].Name); //REF 2
Can anyone tell, where am I going wrong?
Thanks :)
The problem is that the XHR call is being performed in the background and, while this is happening the JavaScript runtime moves on to the next statement - which is REF2. And so you are trying to read the results of a request before the request itself has completed.
The solution is to put the code that accesses the result in a function which you pass to another call of the then method, like this:
var sampleArr = new Array();
WinJS.xhr({ url: "http://some-api-with-json-response" }).then(
function (response) {
var name = JSON.parse(response.responseText);
sampleArr[0] = { Name: name.title };
console.log("First chance:" + sampleArr[0].Name); //REF 1
item_number++;
}).then(function () {
console.log("Second chance:" + sampleArr[0].Name); //REF 2
});
The function that contains REF2 won't be executed until the function that contains REF1 has completed and that function won't be executed until the XHR request is completed.
.then(callback), the callback function will be executed when the request success.
The code of REF 2 runs before the callback function, at that time, sampleArr[0] is undefined.
Related
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 3 years ago.
I'm working on a live update chart, and for that, I made a separate file with the data I need. I made a request on my main page with AJAX so I could get the Array into the main page. But for some reason, I can't use this array outside the request. I would need to use this arrays inside the part only. Here's what I have:
<script>
$(document).ready(function(){
$.getJSON("loadchart.php", function(data){
var sensor1 = data[0];
var sensor2 = data[1];
var sensor3 = data[2];
var sensorsum = data[3];
});
});
console.log(sensor1);
//My chart stuff down here
When I try to console log of the array it gives an error:
Uncaught ReferenceError: sensor1 is not defined
at main.php:107
This is the new function I tried:
async () => {
async function foo() {
return $.ajax({
url: "loadchart.php",
success: function(data){
return data;
}
});
}
var result = await foo();
console.log(result);
};
There are two reasons why sensor1 is undefined.
One reason is that you declare the variable in a lower scope. You can't access a variable that was declared in your callback function outside that callback function.
The second reason is because a callback function gets called after a response is given from the api that you are calling. However, you are trying to access the variable right away when the script runs. This won't work because you need the variable to be defined first.
The solution:
$(document).ready(function(){
$.getJSON("loadchart.php", function(data){
var sensor1 = data[0];
var sensor2 = data[1];
var sensor3 = data[2];
var sensorsum = data[3];
//move the console.log into this scope.
console.log(sensor1);
});
});
Keep in mind, the console.log() will only work if:
The request is successful
The returned data has the same data structure as you are using.
I have a question about a problem I am bumping into. I am using AngularJS as my framework and do not have access to jQuery nor Lodash.
The problem
I have a function called "refresh". That function makes an async call via angular $http to get new data from the server. The server only gives 25 new updates to me from the date I specify. So to get all the new messages I need to call the server (and update the "updateDate" everytime I get data) until it tells me that it has no more messages (empty array).
Code example
$scope.refresh = function () {
var date = new Date();
$http({
method: 'GET',
url: 'http://path.to.my.server',
timeout: 6000
}).then(function (success) {
date = success.date[0].date; //0 is always the newest message
callback(success.data);
//Do some stuff with the data
}, function (error) {
console.error("Could not retrieve new messages: \n", error.data);
errcallback(error);
});
}
What I have tried
I have tried to get set the request in a separate function and make calls to it like you would do with a normal a-sync function.
I have also tried a while loop and setting a boolean when I am done with collecting. The only problem is that a while loop doesn't wait for the call to end (otherwise it wouldn't be async) and makes quite an impressive loop (not yet infinite, but enough to crash my program).
I was thinking about a for loop, but I do not know how much iterations I should make. It could be 1 but also could also be 5 or more.
I know how recursive functions work, but I do not know how I should use an async recursive function. Any advice or solutions are welcome. (I won't have to be recursive if anyone knows an other solution)
There's nothing particularly special about making async functions recursive, you just don't have to worry about running out of stack.
Just isolate your ajax call into a function, and have that function call itself until it has a complete picture of the data:
$scope.refresh = function () {
var date = new Date();
var results = [];
gather();
function gather() {
$http({
method: 'GET',
url: 'http://path.to.my.server',
timeout: 6000
// presumably using `date` here?
}).then(function(success) {
// This seems to assume you'll always have at least
// one row, which doesn't seem to match with your description
date = success.data[0].date; //0 is always the newest message
if (thereAreNewResults) {
results.push.apply(results, success.data);
gather();
} else {
// We're done
callback(results);
}
}, function (error) {
console.error("Could not retrieve new messages: \n", error.data);
errcallback(error);
});
}
};
That's not meant to be full-formed and perfect, but it should send you in the right direction.
Note my if (thereAreNewResults). I would have thought that would be if (success.data.length) but the code in your question seemed to suggest there'd always be at least one row, so adjust as appropriate.
I will make a recursive function who get the data :
$scope.refresh = function () {
$scope.allDatas = [];
var getData = function(date){
$http({
method: 'GET',
url: 'http://path.to.my.server'+/ date , // should format date her
timeout: 6000
}).then(function (success) {
date = success.date[0].date; //0 is always the newest message
//Do some stuff with the data; all the datas will be available in $scope.allDatas
$scope.allDatas = $scope.allDatas.concat(success.data);
// call again ?
if( /* decide when you stop getting data */ ){
getData(date);
}
}, function (error) {
console.error("Could not retrieve new messages: \n", error.data);
errcallback(error);
});
}
var date = new Date();
// launch the function
getData(date);
}
I have a simple 2-column csv file that I would like my site to read and ultimately parse into an array. The data is in the following format:
Atlanta Braves, Atlanta_Braves
Baltimore Orioles, Baltimore_Orioles
Boston Red Sox, Boston_Red_Sox
etc.
The file is currently stored in the same location as my html file. I am trying to use an ajax request to pull the data from the file into an array, then parse further such that myArray[0][0] = 'Atlanta Braves'.
Here is my code:
var myArray = [];
$.ajax({
type: 'GET',
url: 'datafilename.csv',
success: function(data){processData(data);}
});
function processData(data){
myArray = data.split('\n');
for (i = 0; i < myArray.length; i++){
myArray[i] = myArray[i].split(',');
}
}
alert(myArray[0][0]);
Unfortunately, the alert only returns 'undefined'. What am I doing wrong here? Any feedback would be appreciated.
$.ajax is an asynchronous function. That means that it won't complete until sometime later, after your other synchronous code has already run. Try adding this:
function processData(data) {
// Your existing code goes here...
alert(myArray[0][0]);
}
This works because processData is only run after the AJAX call has returned. Asynchronous functions basically work like this:
var value = 1;
setTimeout(function() {
value = 2; // This won't happen for about 1 second
console.log(value); // 2
}, 1000); // Run this function in 1 second
console.log(value); // 1. This happens almost immediately, without pause
Hi I've been trying to clarify this but there's something I'm still confused about. I know that you can't return values from asynchronous functions so I've referenced this answer's top answer Returning value from asynchronous JavaScript method?
What I'm trying to do is use the flickrAPI to get the biggest size image. The flickrAPI allows one to search images, so I use this to get the photo_id, then I use this photo_id to procses another request to the API's getSize method to get the URL for the biggest size photo.
The code looks a little messy as it is, because I have a method called flickrRequest which sends an XMLHttp request and gets back a JSON string. I know that I can achieve what I want by writing the functions as follows:
function flickRQforimage() {
...got ID
function flickrRQforSize() {
...got maxsizeURL
create image based on maxsizeURL here
}
}
but I was wondering if it was possible to do something like this
function flickRQforimage() {
...got ID
function flickrRQforSize() {
...got maxsizeURL
}
create image based on maxsizeURL here
}
or even create image based on maxsizeURL here
In general my question is whether it is possible to have a callback function that references another statically defined function (I think?). The specifics of the my function is that it takes a callback and the ID and URL processing happens in those callbacks:
flickrRQ(options, cb)
I am wondering whether/what would happen if that unnamed function is instead something else, say flickrRQ(options, processPhoto(data)), and then I define the function in a separate method. This just makes sense for me because I want to keep functionality for the URL processing separate in an attempt to make my code cleaner and more readable.
I tried the following below and it didn't work. Nothing prints. I even have a console.log in the processPhoto method. In fact anything inside of the flickrRQforSize method seems to not evaluate
flickrRQforSize(options, function(data) {
processPhoto(data)
}
even though in the flickrRQforSize definition, a callback function is taken as an argument. I'm suspecting there must be something about functions/async calls that I don't understand.
I hope this is clear -- if not, I can post my actual code.
Here's my code:
var flickrRequest = function(options, xhrRQ, cb) {
var url, xhr, item, first;
url = "https://api.flickr.com/services/rest/";
first = true;
for (item in options) {
if (options.hasOwnProperty(item)) {
url += (first ? "?" : "&") + item + "=" + options[item];
//parses to search equest;
first = false;
}
}
//XMLHttpRQ to flickr
if(xhrRQ == 1 ) {
xhr = new XMLHttpRequest();
xhr.onload = function() { cb(this.response); };
xhr.open('get', url, true);
xhr.send();
};
}
var processPhotoSize = function(photoJSON) {
var parsedJSON = JSON.parse(data);
var last = parsedJSON.sizes.size.length;
console.log(parsedJSON.sizes.size[last-1].source);
return parsedJSON.sizes.size[last-1].source;
}
...
flickrRequest(options, 1, function(data) {
...
flickrRequest(sizesOptions, 0, function(data) {
parsedJSON = JSON.parse(data);
console.log(parsedJSON);
processPhotoSize(data);
});
}
I am still trying to figure all this out and I am coming across a really weird error.
I was using getJSON but after searching for solutions to this problem, I found that it was better to try to use the AJAX function (for error capturing -> which isnt firing).
Using breakpoints in firebug, if I go slowly through the running code, it works (mostly) fine (just need to change some coordinates for better drawing). But if I let it run at normal speed, it attempts to do the callback before the json object is returned. The firebug console says everything works ok (code 200), but when examining the jobj inside ship object/function it appears to be "undefined or null"
Following the breakpoints, the ajax calls seem to be going to "error" and not "success". But it isn't firing the alert...
Also, the response takes like 300-500ms.... is that normal? or do I need to find a better server?
Edited Code:
var init = (function(){
thisplayer = new player();
jQuery.ajax({type: "GET", url: "shipdata.php", processData: true, data: {shipid:1}, dataType: "json",
success: function(json) {
var pship = new ship(json);
player_ship = $.extend(thisplayer, pship);
starfield = new starfield();
for(var i = 0; i < player_ship.enemytotal; i++) {
$.ajax({
type: "GET",
url: "shipdata.php",
processData: true,
data: {shipid:Math.round((Math.random()*2+2))},
dataType: "json",
success: function(json) {
var enemy = new ship(json);
game.enemies.push(enemy);
},
error: function(x,y,z) {
// x.responseText should have what's wrong
alert(x.responseTest);
}
});
}
game.initialized = true;
},
error: function(x,y,z) {
// x.responseText should have what's wrong
alert(x.responseTest);
}
});
})
..............................
var ship = (function(json){
var self = this;
jobj = jQuery.parseJSON(json.responseText);
self.height = jobj.height;
self.width = jobj.width;
self.xinit = jobj.xinit;
self.yinit = jobj.yinit;
self.speed = jobj.speed;
self.weapons = jobj.weapons;
self.maxlasers = jobj.maxlasers;
self.imagesrc = jobj.imgurl;
self.lasers = [];
self.x = self.xinit;
self.y = self.yinit;
JSON being sent in:
{"height":75,"width":50,"xinit":275,"yinit":525,"speed":3,"weapons":[1,2],"maxlasers":2,"imgurl":"images\/ship.png"}
Live Demo:
http://www.schennshome.net/medicalmmj/practice/index.html (The code is far from being perfect, Im running through it to try and catch the various errors before animating, but cant get past this.)
I've dug through your source code, and the problem is not actually shown in your question. The problem is with this line, which follows your Ajax call:
player_ship = $.extend(thisplayer, game.pship);
game.pship refers to the data returned by the ajax call, but since this is asynchronous, the above line will be evaluated first, which means game.pship will not be defined.
To fix this, you need to include all of the code in your init function that is currently below the ajax call directly in the success callback. This will prevent the code from being evaluated until the ajax call has returned.
The reason that it works with breakpoints is that this interrupts evaluation, which allows the ajax call to complete before game.pship is referenced.
Edit
I'm now getting an error on line 489, stating that player_ship is undefined. This is again because of the evaluation order of async code. The problem is that player_ship is being defined inside the ajax function in init now, but is being referenced in gameLoop, outside of this callback.
This is how I would rewrite gameLoop:
var callback = function() {
game.canvas.clearCanvas();
drawStarfield();
if(player_ship.alive && game.initialized && !(game.loading)) {
drawPlayer();
drawLaser();
drawEnemies();
}
};
if(game.initialized==false) {
init(callback);
} else {
callback();
}
And then amend init to accept a callback method which is called at the bottom of your success callback. This way, if the game has not been initialized (and player_ship is not yet defined), it will be executed after the ajax call.