Array gives errors after JSON function - javascript

I'm trying to check if the twitch stream is online or offline and if so change a background colour. If i check without the array and just put in the name it works, but with the array it doesn't (I don't have a lot of knowledge of JSON).
function test() {
var twitchChannels = ["imaqtpie", "summit1g", "tyler1", "greekgodx"];
for (var i = 0; i < twitchChannels.length; i++) {
console.log(i + " " + twitchChannels[i]);
$.getJSON('https://api.twitch.tv/kraken/streams/' + twitchChannels[i] + '?client_id=XXXX', function(channel) {
console.log(i + " " + twitchChannels[i]);
if (channel["stream"] == null) {
console.log("Offline: " + twitchChannels[i])
document.getElementById(twitchChannels[i]).style.backgroundColor = "red";
} else {
console.log("Online: " + twitchChannels[i])
document.getElementById(twitchChannels[i]).style.backgroundColor = "green";
}
});
}
}
Error: http://prntscr.com/i6qj51 inside the red part is what happens inside of json fuction

Your code is quite weak since you didn't manage the callback of every get you make.
Also you didn't check if:
document.getElementById(twitchChannels[i])
is null, since the exception clearly stated that you can't get :
.style.backgroundColor
from nothing.
Basic check VanillaJS:
if(!document.getElementById("s"))
console.log('id ' + twitchChannels[i] + ' not found in dom')
else
console.log('id ' + twitchChannels[i] + ' found in dom')
Also consider mixing JQuery with VanillaJS extremely bad practice; use proper JQuery method to access dom element by ID .

You should pass twitchChannel to the function because the var i is changing, this is an issue like others already mentioned: Preserving variables inside async calls called in a loop.

The problem is that you made some ajax call in a cicle, but the ajax calls are async.
Whey you get the first response, the cicle is already completed, and i==4, that is outside the twitchChannels size: that's why you get "4 undefined" on your console.
You can change your code in such way:
function test() {
var twitchChannels = ["imaqtpie", "summit1g", "tyler1", "greekgodx"];
for (var i = 0; i < twitchChannels.length; i++) {
executeAjaxCall(twitchChannels[i]);
}
}
function executeAjaxCall(twitchChannel){
$.getJSON('https://api.twitch.tv/kraken/streams/' + twitchChannel + '?client_id=XXXX', function(channel) {
console.log(twitchChannel);
if (channel["stream"] == null) {
console.log("Offline: " + twitchChannel)
$('#'+twitchChannel).css("background-color", "red");
} else {
console.log("Online: " + twitchChannel)
$('#'+twitchChannel).css("background-color", "green");
}
});
}
}

When console.log(i + " " + twitchChannels[i]); is called inside the callback function, the variable i has already been set to 4, and accessing the 4th element of array twitchChannels gives undefined since the array has only 4 elements.
This is because $.getJSON is a shorthand Ajax function which, as the name suggests, executes your requests asynchronously. So what actually happened is, based on the output you provided,
The loop is executed 4 times, and four Ajax requests have been sent.
The loop exits; i is already set to 4 now.
The ajax requests return; the callbacks are called, but the i value they see is now 4.
You can change the console.log inside your callback to something like console.log(i + " " + twitchChannels[i] + " (inside callback)"); to see this more clearly.
The correct result can be obtained by binding the current value of i to the closure.
function test() {
var twitchChannels = ["imaqtpie", "summit1g", "tyler1", "greekgodx"];
function make_callback(index) {
return function (channel) {
console.log(index + " " + twitchChannels[index]);
if (channel["stream"] == null) {
console.log("Offline: " + twitchChannels[index])
document.getElementById(twitchChannels[index]).style.backgroundColor = "red";
} else {
console.log("Online: " + twitchChannels[index])
document.getElementById(twitchChannels[index]).style.backgroundColor = "green";
}
}
}
for (var i = 0; i < twitchChannels.length; i++) {
console.log(i + " " + twitchChannels[i]);
$.getJSON('https://api.twitch.tv/kraken/streams/' + twitchChannels[i] + '?client_id=XXXX', make_callback(i));
}
}

Related

Uncaught TypeError: Cannot read property '0' of undefined beqause it is unexistant

what is the best way to say devenitions=true? i cant figgure it out...
if (!defenitieGetoond) {
getDef();
defenitieGetoond = true;
} else {
getWoord();
defenitieGetoond = false;
}
This is my loop who expects that there is always a defenition? but in my json file this is not always the case. it searches to the Json file as follows.
function getDef() {
document.getElementById("demo_").innerHTML = "<br>" + savedWord[1].definitions[0].definition
// + "<br>" + "</br>"+ savedWord[1].definitions[1].definition
;
}
it needs to skip of ignore the Deffenitions[0] som how
You should need to add check in case of element exist or not. like this -
function getDef(){
const ele = document.getElementById("demo_");
if (savedWord[1].definitions && savedWord[1].definitions.length) {
ele.innerHTML = "<br>" + savedWord[1].definitions[0].definition
// + "<br>" + "</br>"+ savedWord[1].definitions[1].definition;
}
}

variable is not getting defined even though the code works somwhere else

so i am building a game in three js and trying to make it multiplayer throught socket.io so i am loading all of my characters into an array called players on my server side
and then i pass it to each client when they connect like so
socket.on('addPlayer', function(username) {
players.push(username)
console.log(username + " joined")
console.log("online Users " + players)
socket.broadcast.emit('syncPlayers', players)
socket.emit('syncPlayers', players)
})
and on my client syncPlayers looks like this
socket.on('syncPlayers', function(players) {
players.forEach(function(value) {
if (value == username) {
console.log("not adding " + value + " thats you ")
loadPlayerdata(username)
} else {
console.log("player Online " + value);
newplayer = value;
loadPlayerdata(newplayer)
addPlayer(newplayer)
}
});
})
then it calls this wich sends the server data
function loadPlayerdata(playerName) {
console.log(playerName)
console.log("phase1")
socket.emit('loadPlayerdata', playerName)
}
then this is called and it retrieved the player name and the data of the players location this is were my problem lies
socket.on('loadPlayerdata', function(data, username) {
toMove = threeObjects[username + "Char"]
if (data == "null" || "") {
console.log(username + " is new")
} else {
console.log(username + " Exists")
console.log(toMove)
toMove.position.set(world.spawnPointx, world.spawnPointy, world.spawnPointz)
}
i keep getting Uncaught TypeError: Cannot read property 'position' of undefined
even though i can use this
function addPlayer(playerName) {
var charObjectName = playerName + "Char"
var threeObject = models.tent1.mesh.clone();
scene.add(threeObject)
//threeObject.position.set(world.spawnPointx, world.spawnPointy, world.spawnPointz)
// set reference
threeObjects[charObjectName] = threeObject;
}
btw i have an object
var threeObjects = {};
can someone please explain why it wont work and how to fix it
You can read this answer to understand the difference between dot and brackets notation.
You are getting error because, tomove seems to be undefined and dot notation will throw error if any new user joins and if the object is empty.
Check if this helps. This will assign the object key as username and position as an value which will be array like this,
{"usernamechar": {"position": [x,y,z]}}
socket.on('loadPlayerdata', function(data, username) {
if (data == "null" || "") {
console.log(username + " is new")
} else {
console.log(username + " Exists")
threeObjects[username + "Char"]["position"] = [world.spawnPointx, world.spawnPointy, world.spawnPointz]
}
}

How would you create a call to a function inside a for loop? [duplicate]

I'm new to node, but I love it already. Only issue is, the asynchronous functionality is killing me.
I am using the google package to get my websites' rankings in google as so:
for (var j=0;j<keywords.length;j++) {
var keyword = keywords[j];
google(keyword, function(err, next, links) {
console.log('Searching for keyword "' + keyword + '" in google.' + google.tld + ' ('+ google.lang +')');
if (err) console.error(err);
for (var i = 0; i < links.length; ++i) {
var rank = i+1;
console.log(keyword + ' #'+ rank + ' - ' + links[i].link + ' | ' + links[i].title);
//link.href is an alias for link.link
//console.log(links[i].description + "\n");
}
console.log('\n');
});
}
My problem is that it the console log shows the same keyword for all websites, although I have defined three in my keywords array.
What am I missing?
The immediate problem here is that the j and keyword variables go on changing before the callbacks are called.
A simple solution is to protect this variable in a closure :
for (var j=0; j<keywords.length; j++) {
(function(j){
var keyword = keywords[j];
...
})(j);
}
When you're just working with a simple array, then you can also use a closure through forEach :
keywords.forEach(function(keyword, j){
...
});
To deal with this kind of asynchronous problems, you should now dive in promises which help structure your code in a clearer (and less indented) way. An introduction.

JavaScript: SyntaxError: missing ) after argument list

I am getting the error:
SyntaxError: missing ) after argument list
With this javascript:
var nav = document.getElementsByClassName('nav-coll');
for (var i = 0; i < button.length; i++) {
nav[i].addEventListener('click',function(){
console.log('haha');
}
}, false);
};
What does this error mean?
You have an extra closing } in your function.
var nav = document.getElementsByClassName('nav-coll');
for (var i = 0; i < button.length; i++) {
nav[i].addEventListener('click',function(){
console.log('haha');
} // <== remove this brace
}, false);
};
You really should be using something like JSHint or JSLint to help find these things. These tools integrate with many editors and IDEs, or you can just paste a code fragment into the above web sites and ask for an analysis.
You got an extra } to many as seen below:
var nav = document.getElementsByClassName('nav-coll');
for (var i = 0; i < button.length; i++) {
nav[i].addEventListener('click',function(){
console.log('haha');
} // <-- REMOVE THIS :)
}, false);
};
A very good tool for those things is jsFiddle. I have created a fiddle with your invalid code and when clicking the TidyUp button it formats your code which makes it clearer if there are any possible mistakes with missing braces.
DEMO - Your code in a fiddle, have a play :)
just posting in case anyone else has the same error...
I was using 'await' outside of an 'async' function and for whatever reason that results in a 'missing ) after argument list' error.
The solution was to make the function asynchronous
function functionName(args) {}
becomes
async function functionName(args) {}
Similar to Josh McGee, I was trying to use await in the global scope, which, since it isn't an async function, will throw an error. See here for solutions.
This error maybe is the version of your Android (especially if you are using Web Views), try to change your code like an old version of the JavaScript Engine, like:
.then(function(canvas){
//canvas object can gained here
});
This error can also occur if you are missing a (tick) '
Failed:
if (!string.IsNullOrWhiteSpace(clientSideMethod))
{
return "function(e){" + clientSideMethod + " OnOptionChangedDxGrid(e," + hasConditionalFormatting.ToString().ToLower() + "','" + "false".ToString().ToLower() + "', '" + string.Empty + "'); }";
}
else
{
return "function(e){ OnOptionChangedDxGrid(e," + hasConditionalFormatting.ToString().ToLower() + "','" + "false".ToString().ToLower() + "', '" + string.Empty + "'); }";
}
Worked:
public static string GetOnOptionChangedMethodCall(string clientSideMethod, bool hasConditionalFormatting)
{
if (!string.IsNullOrWhiteSpace(clientSideMethod))
{
return "function(e){" + clientSideMethod + " OnOptionChangedDxGrid(e,'" + hasConditionalFormatting.ToString().ToLower() + "','" + "false".ToString().ToLower() + "', '" + string.Empty + "'); }";
}
else
{
return "function(e){ OnOptionChangedDxGrid(e,'" + hasConditionalFormatting.ToString().ToLower() + "','" + "false".ToString().ToLower() + "', '" + string.Empty + "'); }";
}
}
Notice there is a missing (tick) ` before the first double quote: (e," + hasConditionalFormatting.ToString()
I got the same error and I figured with the increased use of ES6 and string interpolation, that more and more people would start making the same mistake I did with Template Literals:
Initially, I logged a statement like so:
console.log(`Metadata: ${data}`);
But then changed it and forgot to remove the ${}:
console.log('Metadata: ' + JSON.stringify(${data}));

SDK GridRefresh Call Throwing Exception

I'm going to try to explain this as best I can, please feel free to ask for clarifications as required.
Using IE10, CRM Online with RU12.
I am playing about with subgrids and getting them to refresh. Consider the following script, which I have nicked wholesale from MSDN (and wrapped in a try/catch block)
function start() {
try {
var controls = Xrm.Page.ui.controls.get(isSubGrid);
if (controls.length > 0) {
var subGridNames = "";
for (var i in controls) {
controls[i].refresh();
subGridNames += (" - " + controls[i].getName() + "\n");
}
alert("The following subgrids were refreshed: \n" + subGridNames);
}
else {
alert("There are no subgrid controls on the current form.");
}
}
catch (ex) {
alert(ex);
}
}
function isSubGrid (control)
{
return control.getControlType() == "subgrid";
}
Nothing special going on there - get all controls of type subgrid (this returns 10 elements as expected) and call refresh() on them.
However this is consistently failing on the first call to refresh().
The exception details is fairly straightforward
TypeError: Unable to get property 'Refresh' of undefined or null reference
Which suggests that the control[i] is null when called in the loop at this point here
for (var i in controls) {
controls[i].refresh();//error thrown here - suggests controls[i] is null
subGridNames += (" - " + controls[i].getName() + "\n");
}
However I can see that it isn't null (and has the method refresh as expected).
I can make it work by using setInterval
function waitAndThenRefresh(gridname) {
var grid = Xrm.Page.ui.controls.get(gridname);
var intervalId = setInterval(function () {
if (grid === null || grid._control === null || grid._control._element === null) {
return;
}
if (grid._control._element.readyState === 'complete') {
window.clearInterval(intervalId);
if (grid != null) {
grid.refresh();
}
}
}, 1000);
}
But that is pretty hideous, not to mention does not explain with the SDK call doesn't work as expected.
So I guess the question is: has anyone else seen this issue? Or can you replicate it on another instance? Am I missing something? There is nothing in the SDK that suggests you need to defer calling refresh until the inner control's readyState is complete?
The code block you are using,
for (var i in controls) {
controls[i].refresh();
subGridNames += (" - " + controls[i].getName() + "\n");
}
should be replaced with the following:
for (var i in controls) {
i.refresh();
subGridNames += (" - " + i.getName() + "\n");
}
or:
for (var i = 0; i < controls.length; i++) {
controls[i].refresh();
subGridNames += (" - " + controls[i].getName() + "\n");
}
You are getting the exception because controls[i] is undefined in your case, i being the control (the element of the array controls).
I asked a CRM-buddy of mine. He said that the issue depends on the new refreshment Engine. According to him, it's sort of a bug but not really. If I got it right, the refresh has been reengineered to accommodate the new perpetual saving functionality.

Categories

Resources