Javascript function returns undefined [duplicate] - javascript

This question already has answers here:
How to return value from an asynchronous callback function? [duplicate]
(3 answers)
Closed 9 years ago.
First off I am new to javascript and this is my first 'project' in this language, so I apologize for my noobiness in advance.
I am using leaflet and D3 in this project and I can't seem to get this function to return anything except for 'Undefined'. At first I though I wasn't returning from the function properly so I tried to duplicate the error on a smaller scale here:
http://jsfiddle.net/KhqwR/
However, that worked for me so now I am a little lost on what to do.
Here is a simple version of my code, I tried to remove everything that didn't seem relevant and changed the names to make it easier to understand:
$(function () {
...
function getThings(code) {
d3.csv("data.csv", function(data){
for (var i = 0, len = data.length; i < len; i++){
if (data[i].code == code){
alert("return 5!")
return 5;
}
else{
return 0;
}
}
})
}
L.geoJson( features, {
style: function (feature) {
return { opacity: 0, fillOpacity: 0.5, fillColor: "#0f0" };
},
onEachFeature: function(feature, layer){
var test = getThings(5);
alert(test);
...
I consistently get to the "return 5!" alert and then at the alert(test) I just get "Undefined".
Does anybody know where I went wrong?
Thanks in advance!

d3.csv actually returns a useful value that can be used for attaching relevant callbacks. However, because the getThings doesn't have a return statement, then it will always yield undefined when invoked.
Remember that return applies to the nearest enclosing function, including anonymous functions such as the provided callback.
function getThings(code) {
/* Without an explicit return, a function always evaluates
to undefined when invoked. */
return d3.csv("data.csv", function(data){ .. });
})
var test = getThings(..);
/* Now test is NOT undefined, but is also NOT the data
for the asynchronous reasons discussed elsewhere.
See the link above for correct usage. */
test.row(..);

d3.csv() is async. Which means, the function getThings() kicks off d3.csv() and instantly returns undefined
From d3 documentation:
Issues an HTTP GET request for the comma-separated values (CSV) file
at the specified url. The file contents are assumed to be
RFC4180-compliant. The mime type of the request will be "text/csv".
The request is processed asynchronously, such that this method returns
immediately after opening the request.

This is happening due to Javascript Async Nature. Use function Callback.

Related

Uncaught ReferenceError: function is not defined. Jquery already attached

I just got an error and I do not know why it is happening. Below are my functions.
function senditnow(){
//something
}
$('.check-with-bank').click(function(){
//something
checksuccess_checkall(successsent);
if(successsent == true) {
//It already passed and come to this function but It cannot call.
senditnow();
}
}
I also attached jQuery and all other features working well except stopping at senditnow() function.
Can you help me to explain why?
the problem may be that successsent value is not changing, as far as i know pass by reference only works on arrays an objects, so it would be better if you do
successsent = checksuccess_checkall();
if checksuccess_checkall() returns a boolean, that way you can validate if successsent is true, and you should check what values successsent has before and after calling checksuccess_checkall()

Scope of global array javascript [duplicate]

This question already has answers here:
Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference
(7 answers)
Closed 5 years ago.
I am trying to load data from a csv and store it in an array of objects. I know global variables are frowned upon but I can't think of a better way to store the data and access it from multiple functions.
Here is my code:
var mydata = new Array;
$(document).ready( function () {
$.get('./datafile.csv', function(data) {
var head = data.split("\n");
for(var i = 1; i < head.length; i++){
line = head[i].split(",");
var obj = {
index:i,
img:line[0],
caption:line[1],
desc:line[2]
};
mydata.push(obj);
}
console.log(mydata); //1
});
console.log(mydata); //2
//I then want to select various elements on my page and set some attributes to
//an object in my data, but I can't since everything is undefined
});
At the first spot it logs my data correctly, but at second spot it logs an empty array. I read this article on global variables in JavaScript so I'm not sure what is going wrong.
The second part (//2) runs too soon. When $.get executes, it just starts the HTTP request to get the CSV, but doesn't wait for it to finish - that's why you need to pass that function(data) in. After the request finishes, the callback function gets called, and it's there that you should continue your initialization.
So, your code should look something like that below. (if you need to use the data elsewhere, you can keep on using the global, but it's not needed just for this)
$(document).ready( function () {
$.get('./datafile.csv', function(data) {
var mydata = [];
var head = data.split("\n");
// ...
console.log(mydata); //1
continueSetup(mydata); // 2
});
});
function continueSetup(mydata) {
// do what you need
}
I think you might be getting confused about the order of what is happening in your code. First of all, there is nothing wrong with using a global variable like this, especially if you are accessing it multiple times throughout your page (using events and such). Secondly, the reason you are seeing an empty array at your "second" spot in code is because that spot (#2) is actually getting executed before your get function has received the data and before #1.
get is an asynchronous function, which means that it waits to receive a response, and then executes the code inside (including #1). However, #2 gets executed immediately, while your array is still empty.
At 2 the data will be same as what you initialized. At 1 the data will be the same as what you populated.
2 gets printed first if you have observed closely. This is because $.get is an asynchronous call and gets executed in the background. The callback you are providing to $.get will run after the GET request is either successfully completed or errored out.

variable value not being stored, does js compile code as it is written? [duplicate]

This question already has answers here:
Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference
(7 answers)
Closed 6 years ago.
i am trying to do a simple task. here is my function i am taking in a url link as parameters. i read the link, scrap it for data like title and headers. then i just try to store the data in mongo.
for some reason looking at this code console prints y first and then x.
why is javascript not compiling the code as it is written?
any help on how i may be able to store this data in a global var.
thanks
i believe it is a call back error..
insertNewItem(link){
check(link, String);
var xray = new Xray();
var tname;
xray(link, 'title')(function(err, title) {
tname = title;
console.log('x', tname);
});
var header;
xray(link, 'h1')(function(err, h1) {
header = h1;
});
console.log('y',tname);
Items.insert({
url: link,
name: tname,
bio: header
});
}
Your code snippet is a bit short, but it appears that the function returned from xray executes its callback asynchronously. This means that your function will run to completion, then your callback (containing the console.log('x'...) will be executed.
This works much like setTimeout:
setTimeout(function() {
console.log('a');
}, 1)
console.log('b');
// Prints b, a
Whenever you use an async callback, you must keep in mind that your code will not be executed top-to-bottom.
It takes a little to wrap you head around, but you catch on eventually.
In your case, you will probably want to do something like:
var tname;
var i = 0
xray(link, 'title')(function(err, title) {
tname = title;
console.log('x', tname);
insert();
});
var header;
xray(link, 'h1')(function(err, h1) {
header = h1;
insert();
});
console.log('y', tname);
function insert() {
if (i = 1) Items.insert({
url: link,
name: tname,
bio: header
});
else i++;
}
That will start xray running, and call Items.insert when all the data is available. It would be a bit cleaner with promises, but that's a whole different subject.

Understanding variable scope and closures with JavaScript callback functions [duplicate]

This question already has answers here:
Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference
(7 answers)
Closed 6 years ago.
I have been stuck for far too long on the following problem that I really need to consider my theoretical knowledge about variable scope and callback functions in Javascript. Rather than a quick fix for my particular problem a generalized answer that tries to explain the theory behind my problem is preferred. Here is the code (that doesn't work) (oh and it uses jQuery's $.getJSON).
function getStreamerStatus(streamer) {
var channelurl = "https://api.twitch.tv/kraken/channels/";
var streamurl = "https://api.twitch.tv/kraken/streams/";
var temporary = {
status: "",
game: "",
picture: "",
name: streamer,
link: "https://www.twitch.tv/" + streamer
};
$.getJSON(streamurl + streamer, createCallback(temporary));
$.getJSON(channelurl + streamer, createCallback(temporary));
return temporary;
}
After some searching I used the "createCallback()" function in an attempt to make the "temporary" object visible to the callback function.
function createCallback(tmpobj) {
return function(json) {
//get's some information and stores it in the object passed as tmpobj
filterOut(json, tmpobj);
};
}
And in the end in the main function I have an array with names of twitch streamers and for each name the "getStreamerStatus()" function is called and the returned object is stored in an array.
function TwitchInit() {
var channels = [/*filled with strings of streamer names*/];
var response = []; //array with objects with all the information
for(var i = 0; i < channels.length; i++) {
response.push(getStreamerStatus(channels[i]));
}
parseContent(response); //not relevant for now
//for debugging
for(var j = 0; j < response.length; j++) {
console.log("--responseArray with Objects--");
for(var prop in response[j]) {
if(response[j].hasOwnProperty(prop)) {
console.log(prop + ": " + response[j][prop]);
}
}
}
}
The problem here is that if I log the objects to the console only the "link" and "name" properties of the objects have some content and the other properties who're supposed to be written by the "filterOut()" function always remain empty. According to the console the communication with the Twitch server is fine and I can read the response header/object from the console so that rules out. And since the "name" and "link" properties are also different at each log to the console that means that each time a new object is created which is fine. That leads me to the conclusion that the "temporary" object still somehow isn't visible to the callback function inside $.getJSON despite my attempt with "createCallback()" to make the object visible to the "filterOut()" function. I have found a lot of information about variable scope in JavaScript but so far it hasn't helped my to solve my problem. I have no clue what I am doing wrong here and I'm starting to get frustrated. I really hope someone can enlighten me here.
I think there is no problem is closure here, the only problem is that your getStreamerStatus function will perform async tasks but will return a value directly, and use it without waiting the async calls (getJSON) to complete.
Try to put you debug logs inside a setTimeout with few seconds delay ;)
To so things better you should rewrite your getStreamerStatus to only returns the data after the getJSON calls are done, not before, with a callback as parameter, or by returning a promise.
Or you should have something (ie: an event) to tell your function that the calls are finished, and that it can process the results.

javascript dynamic properties dissapears after succesfully declaring it from json - becomes empty object (not undefined)

var s = store.get('billablexxxx');
if (!s) {
if (false) {
s = {
"something" : 'Value', ....
}
}
}else {
s = new Object;
$.getJSON('Translation/GetIndexLabels', function(data) {
$.each(data, function(key, val) {
s[key] = val;
// temp[key] = val;
})}) ;
}
}
//here i use the variable
But where i use the variable, the dynamic properties dissapaered, it's not undefined but it's an empty object.
However, when it has been set in the $.getJSON() function, all values are added.
What did i do wrong?
Edit:
Fixed the problem by putting it into a function. When i posted the question, i was already close to the answer that i have looked for the last "hour" (weird javascript console results brought confusion).
Thanks for the advice!
The call to $.getJSON() is asynchronous, so the execution will reach the part where you "use the variable" before the asynchronous call completes.
The usual way to deal with this is to have the use of the variable inside a callback function that is referenced in the getJSON() call.
Here's the reference: http://api.jquery.com/jQuery.getJSON/
The getJSON method is asynchronous, it calls your function(data) once it has completed.
At the point which you are using s, the getJSON method has not yet returned so the properties of s have not been initialised.

Categories

Resources