Iterating through array in getJSON callback - javascript

I am trying to invoke a getJSON function for each value in an array and if the user is offline, display their name. However, I keep getting undefined. When a number is hard coded for i though, it works fine.
function getStreamersList() {
$('#listOfStreams').html("");
for (var i = 0; i < streamers.length; i++) {
console.log("This works: " + streamers[i]);
$.getJSON('https://api.twitch.tv/kraken/streams/' + streamers[i], function(data) {
if (data.stream !== null) {
$('#onlineStreams').append('<div class="online"><p>' + data.stream.channel.status + '</p></div>');
} else {
console.log(streamers[i]);
$('#offlineStreams').append('<div class="offline"><p>' + streamers[i] + ' is offline.</p></div>');
}
}, 'jsonp')
}
}
Can someone please explain what's happening? Thanks for any help!

Related

Want to populate datatable row one by one using asynchronous in JavaScript

I am facing a problem where I want to return all the rows one by one without interupting the current function. The issue is intermittent. Sometimes I can get all the datatables data but sometimes not.
Then I started investigating and realised after checking the developer tool in network section that it throws error after page 10. And the error is 429 too many requests. Also, realised that the script was synchronous json call.
429 too many requests
I tried using below code in my script but the spin is not working. Also, found that this is not recommended way.
Can someone help me with solution? Thank you
// Set the global configs to synchronous
$.ajaxSetup({
async: false
});
My Script
function getMed(sDate, eDate) {
var pData;
var firstURL = mUrl + "?sDate=" + moment(sDate).format(dateFormat) + "&eDate=" + moment(eDate).add(1, 'day').format(dateFormat) + "&pNum=1";
....
}).done(function (data) {
if (pData.Number > 0) {
var counter = 0;
// Set the global configs to synchronous
$.ajaxSetup({
async: false
});
var requestsProcessed = 0;
for (var i = 1; i <= pData.Number; i++) {
$("#iconSpin").css('display', 'block');
var pURL = mUrl + "?sDate=" + moment(sDate).format(dateFormat) + "&eDate=" + moment(eDate).add(1, 'day').format(dateFormat) + "&pNum=" + i;
console.log("calling: " + pURL);
var pageRequest = $.getJSON(pURL, function (data) {
requestsProcessed++;
$("#progress").innerHTML = "Fetching batch " + requestsProcessed + " of " + pData.Number + " batches.";
....
}).fail(function () {
$("#iconSpin").css('display', 'none');
console.log("fail for " + pURL + " in " + new Date());
});
console.log("completed for " + pURL + " in " + new Date());
}
} else {
alert("There is no data.");
}
}).fail(function () {
$("#iconSpin").css('display', 'none');
});
}

Understanding variable mistakes within closures?

I am learning about closures. This example is given as a common mistake made when making a closure:
function assignTorpedo(name, passengerArray) {
var torpedoAssignment;
for (var i = 0; i<passengerArray.length; i++) {
if (passengerArray[i] == name) {
torpedoAssignment = function() {
alert("Ahoy, " + name + "!\n" +
"Man your post at Torpedo #" + (i+1) + "!");
};
}
}
return torpedoAssignment;
}
Since the for loop completes before the closure is returned, the i value will not match with the name. So, I understand that the loop continues on before the return happens.
My question comes from this, an example of the correct way to do things:
function makeTorpedoAssigner(passengerArray) {
return function (name) {
for (var i = 0; i<passengerArray.length; i++) {
if (passengerArray[i] == name) {
alert("Ahoy, " + name + "!\n" +
"Man your post at Torpedo #" + (i+1) + "!");
}
}
};
}
I don't understand why in the above example the for loop wouldn't also continue past the first time it finds a match, which would result in another mismatched i. I understand that return stops a function, but I don't understand the connection between the return and that first match since they don't happen together (visually). I understand how the code knew to stop if that return was within the if function or the for loop.
I don't understand why in the above example the for loop wouldn't also continue past the first time it finds a match
It would.
which would result in another mismatched i.
It wouldn’t, because it checks if (passengerArray[i] == name) every time. That’s wasteful, though; it’s an unusual fix. A better way would be to pass the index:
function makeTorpedoAssigner(passengerArray, i) {
return function (name) {
alert("Ahoy, " + name + "!\n" +
"Man your post at Torpedo #" + (i+1) + "!");
};
}
function assignTorpedo(name, passengerArray) {
for (var i = 0; i<passengerArray.length; i++) {
if (passengerArray[i] == name) {
return makeTorpedoAssigner(passengerArray, i);
}
}
}
What happens here is :
assignTorpedo() returns a function based on name, So, every time it
checks for name in passengerArray and returns a function, but before
assignTorpedo could return torpedoAssignment, value of i would have
changed to the last value (length-1 of passengerArray), as loop will continue executing.
function assignTorpedo(name, passengerArray) {
var torpedoAssignment;
for (var i = 0; i<passengerArray.length; i++) {
if (passengerArray[i] == name) {
torpedoAssignment = function() {
alert("Ahoy, " + name + "!\n" +
"Man your post at Torpedo #" + (i+1) + "!");
// value of i
};
}
}
// value of i = length of Array since loop has executed fully
return torpedoAssignment;
}
Right approach explained :
Here you are returning a function which takes a name and checks each
time in the array, the concept of closure here is that, even though
function(name) is returned, it would remember passengerArray (if you
will see passengerArray is not passed everytime, but no error is
thrown. This is closure.)
function makeTorpedoAssigner(passengerArray) {
return function (name) {
for (var i = 0; i<passengerArray.length; i++) {
if (passengerArray[i] == name) {
alert("Ahoy, " + name + "!\n" +
"Man your post at Torpedo #" + (i+1) + "!");
//value of i
}
}
};
}

Javascript - passing parameter to function which calls another function

Okay my title is a bit confusing but basically, I have a function and after that function is finished executing, it should do the given steps. Here is my javascript:
createSideTable(showThis, function() {
$('#' + showThis + 'Screen').slideDown('slow');
});
I want the createSideTable function to run all it's code before the step
$('#' + showThis + 'Screen').slideDown('slow');
can get executed. The createSideTable more or less just makes a side table fade in slowly. The function can be seen at the end of this post.
Normally, when I have a function which I want to execute all it steps and then execute other given steps, i'd do it like this
createSideTable(function() {
$('#' + showThis + 'Screen').slideDown('slow');
});
and it works, however, the createSideTable function needs a parameter (the parameter which it needs is showThis). So when I tried
createSideTable(showThis, function() {
$('#' + showThis + 'Screen').slideDown('slow');
});
it did create the sideTable however, this step
$('#' + showThis + 'Screen').slideDown('slow');
didn't get executed after it created the sideTable. How come?
This is my createSideTable function.
function createSideTable(test) {
var key = test.substr(test.length -1); //index of Heading
for (var i=0; i<window['headings' + key].length; i++) {
if (i == 0) {
$('#row' + i).addClass('subHeadingClicked');
}
$('#row' + i).text('').removeClass('column1invisible');
$('#row' + i).append(window['headings' + key][i]);
}
$('#sideTable').fadeIn(1500);
}
Add the callback parameter, and if it exists, call it at the end:
function createSideTable(test, callback) {
var key = test.substr(test.length -1); //index of Heading
for (var i=0; i<window['headings' + key].length; i++) {
if (i == 0) {
$('#row' + i).addClass('subHeadingClicked');
}
$('#row' + i).text('').removeClass('column1invisible');
$('#row' + i).append(window['headings' + key][i]);
}
$('#sideTable').fadeIn(1500);
if (callback) callback();
}
And you should be able to call it like this:
createSideTable(showThis, function() {
$('#' + showThis + 'Screen').slideDown('slow');
});
Edit -
The first example was showing how a callback works. You can execute the callback where ever you want... for example, if you want it to be executed after the fadeIn(), you could do this:
function createSideTable(test, callback) {
var key = test.substr(test.length -1); //index of Heading
for (var i=0; i<window['headings' + key].length; i++) {
if (i == 0) {
$('#row' + i).addClass('subHeadingClicked');
}
$('#row' + i).text('').removeClass('column1invisible');
$('#row' + i).append(window['headings' + key][i]);
}
$('#sideTable').fadeIn(1500, function() {
if (callback) callback();
});
}

Array to String conversion in Javascript

Attached is the code in question.
var http = require("http");
var i = 0;
var hostNames = ['www.1800autoland.com','www.youtube.com','www.1800contacts.com'];
for(i;i<hostNames.length;i++){
var options = {
host: hostNames[i],
path: '/'
};
http.get(options, function(res){
console.log("url: " + hostNames[i]);
console.log("status: " + res.statusCode);
for(var item in res.headers){
if(item == "server"){
console.log(item + ": " + res.headers[item]);
}
if(item == "x-powered-by"){
console.log(item + ": " + res.headers[item]);
}
if(item == "x-aspnet-version"){
console.log(item + ": " + res.headers[item]);
}
}
console.log("\n");
})
};
I have an array of URLs, and the issue I came to consult the site is that in my code, hostNames[i] does not display the n-th (or "i" in this case) index as a string. The output in console would always be "undefined." I have tried String(), toString(), and a number of different methods to no avail. Could someone point me to the right direction? What is the conversion I need to do?
This is a typical closure problem that occurs because of asynchronousness. When your callback fires the value of i will always be hostNames.length.
To fix it close around the value of i:
http.get(options, (function(res) { // '(' before function is optional, I use it to indicate immediate invocation
return function (i) { // this is the closed value for i
console.log("url: " + hostNames[i]);
console.log("status: " + res.statusCode);
// .. etc
};
}(i))); // immediate invocation with i
What's important to realize about using closures like this, is that you're making a number of anonymous functions, not just one. Each function is bound to its own value of i.
The easiest way to avoid having to write these strange bits of code is to not use for loops directly, but use a map function. Like:
function array_map(array, callback) {
var i, len = array.length;
for (i = 0; i < len; i += 1) {
callback(i, array[i]);
}
}
This makes it so you automatically close the value of i. Your loop will look like:
array_map(hostNames, function(i, hostname) { // i and hostname have the closed value
// .. etc
});
It's the closure problem, try this:
(function (i) {
http.get(options, function(res){
console.log("url: " + hostNames[i]);
console.log("status: " + res.statusCode);
for(var item in res.headers){
if(item == "server"){
console.log(item + ": " + res.headers[item]);
}
if(item == "x-powered-by"){
console.log(item + ": " + res.headers[item]);
}
if(item == "x-aspnet-version"){
console.log(item + ": " + res.headers[item]);
}
}
console.log("\n");
})
})(i);
You should use the .get(i) method to retrieve the item. You do not need to initialize the counter in the array, as others have stated.

Javascript function not called in jQuery $.submit

Hey there,
Again, I've been searching a solution to find out why a function, would not being called... and guess what, I did not find.
I have a form, that I submit using jQuery Ajax. When error, I get every local data, I got, I sorted them, and show them to the user.
Here is the sample code :
$.ajax({
type: "POST",
url: "http://xxx/register.php",
data: form,
success: function(msg){
//console.log("Data Saved: " + msg);
$.iGrowl(2,stringdata[4]);
var data = parseJSON(msg);
if(data.msg.score != undefined){
var cpt = 0;
$.each(data.msg.score, function(index,el){
if(cpt<8){
if(el.selected)
$('tbody').append('<tr class="win"><td>' + el.name + '</td><td>' + el.score + '</td></tr>');
else
$('tbody').append('<tr><td>' + el.name + '</td><td>' + el.score + '</td></tr>');
}
});
}
else{
$.iGrowl(3,"Erreur inconnue...");
}
$("#scorediv").css("visibility","visible");
$( "#formule" ).css('opacity',0);
$( "#scorediv" ).css('opacity',1);
},
error: function(data) {
cpt = 0;
var i = 0;
score.each(function(r){
arrayScore[i] = r;
i++;
});
arrayScore.sort(function(a, b){
console.log("sorting...");
if(a[3])
{
if(b[3])
{
return (b[3].value - a[3].value); //causes an array to be sorted numerically and descending
}
}
});
$.each(arrayScore, function(index,el){
//arrayScore.forEach(function(el) {
//score.each(function(el){
if(cpt<8)
{
if(el[2].value == form[2].value)
$('tbody').append('<tr class="win"><td>' + el[1].value + '</td><td>' + el[3].value + '</td></tr>');
else
$('tbody').append('<tr><td>' + el[1].value + '</td><td>' + el[3].value + '</td></tr>');
cpt++;
}
else
return false;
});
var user = form;
store.save(user, function(r) {
});
$.iGrowl(3,stringdata[5]);
$("#scorediv").css("visibility","visible");
$("#formule").css('opacity',0);
$( "#scorediv" ).css('opacity',1);
}
});
My array is never sorted. If I change this part :
var i = 0;
score.each(function(r){
arrayScore[i] = r;
i++;
});
by this :
score.each(function(r){
arrayScore.push(r);
});
arrayScore is never filled.
I try to execute each line in the console step by step, it works.... I'm getting kind of crazy... and I really do not know what could have happened ?
Any help would be graceful appreciate !
P.S : I'm using, jQuery1.5 + Lawnchair and CSS3 animation.
Code tested on safari and chrome.
Thanks !
Javascript array objects don't support a method called each. You should try
$.each(score, function(index, value){...});

Categories

Resources