javascript array error: array[n] is undefined - javascript

relevant code:
function stepNetwork() {
for(i = 0; i<maxNeurons; i++) {
if(neuronArray[i].charge >= neuronArray[i].threshhold) {
var elapsed = ((new Date()).getTime()) - neuronArray[i].lastFired;
if(elapsed >= 5000){
fireNeuron(i);
}
}
}
}
function fireNeuron(n){
//get number of outputs on this neuron
var outs = neuronArray[n].outputs.length;
for(p = 0; p < outs; p++) {
sendChargeTo = neuronArray[n].outputs[p];
addCharge(sendChargeTo);
}
neuronArray.charge = 0;
neuronArray.lastFired = ((new Date()).getTime());
}
function addCharge(n) {
neuronArray[n].charge++;//HERES THE ERROR!!
}
Here is what firebug is telling me:
neuronArray[n] is undefined ///then why can I see its value in the scripts->watch tab?
addCharge(n=100)js_operation.php (line 73)
fireNeuron(n=73)js_operation.php (line 66)
stepNetwork()
The thing that gets me is that when I pass a number it works, and when I evaluate neuronArray, neuronArray[n], neuronArray[n]. charge etc in the scripts pane (watch area), it always is able to reference it.

Maybe this is the problem:
sendChargeTo = neuronArray[n].outputs[p];
addCharge(sendChargeTo);
You're not sending addCharge an index, you're sending it neuronArray[n].outputs[p].

Apart from Raynos's comments about the last two lines in fireNeuron I can't see an obvious problem.
Perhaps you have a globals problem? I think that variables i, p, and sendChargeTo should be declared local with var.

Related

Get object out of observable array

Why is m "undefined" in this code:
currentViewModel = ko.mapping.fromJS(viewModel);
currentViewModel.getReport = function(reportId) {
for(var i=0;i<currentViewModel.availableReports().length;i++) {
if(currentViewModel.availableReports()[i].id == reportId) {
var m = currentViewModel.availableReports()[i];
return currentViewModel.availableReports()[i];
}
}
}
I call getReport() as an onclick event and I want to send the report object to a view (modal) I can do a foreach on the availableReports and it's all there. When I run through the debugger, it loops through the array and finds the right one. But why can't I pull it out of the array? "m" remains undefined the the function returns undefined.
What am I missing here?
EDIT: there is a follow up question here:
Can knockout.js wait to bind until an onClick?
You just need to change if(currentViewModel.availableReports()[i].id ... to if(currentViewModel.availableReports()[i].id() ... because after mapping id will become an observable, i.e. function.
Updated code:
currentViewModel = ko.mapping.fromJS(viewModel);
currentViewModel.getReport = function(reportId) {
for (var i = 0; i < currentViewModel.availableReports().length; i++) {
if (currentViewModel.availableReports()[i].id() == reportId) {
var m = currentViewModel.availableReports()[i];
return currentViewModel.availableReports()[i];
}
}
}
Demo - Fiddle.
I'll repeat the solution from #NikolayErmakov's answer here, but want to add two things to get a more complete answer. You end with:
...m remains undefined and the function returns undefined.
What am I missing here?
You're missing two things:
The var m bit of the first statement inside the if is hoisted to the top of the current scope (the top of the function). This is why the debugger can tell you what m is, even if you never reach the line of code it's on.
If a function invocation reaches the end of a function (as is the case for you, since you never go inside the if) without seeing an explicit return statement, it will return undefined.
To better understand this, you should interpret your function like this:
currentViewModel.getReport = function(reportId) {
var m;
for (var i = 0; i < currentViewModel.availableReports().length; i++) {
if (currentViewModel.availableReports()[i].id == reportId) {
m = currentViewModel.availableReports()[i];
return currentViewModel.availableReports()[i];
}
}
return undefined;
}
Some people (e.g. Douglas Crockford) do recommend placing var statements at the top of a function, though it's a matter of style to some degree. I don't think many people explicitly return undefined at the end of a function, though in your case I might be explicit about that scenario and return null (or throw an Error even).
As promised, I'll repeat the actual solution, as I concur with the other answer:
you need to invoke id as a function to get its value (because the mapping plugin will map to observable()s.
In addition:
I'd retrieve the array only once
I'd suggest using === instead of ==
Here's my v0.5 version:
currentViewModel.getReport = function(reportId) {
var m = null, reports = currentViewModel.availableReports();
for (var i = 0; i < reports.length; i++) {
if (reports[i].id() === reportId) {
m = reports[i];
return m;
}
}
return m;
}
But I'd optimize it to this v1.0:
currentViewModel.getReport = function(reportId) {
var reports = currentViewModel.availableReports();
for (var i = 0; i < reports.length; i++) {
if (reports[i].id() === reportId) {
return reports[i];
}
}
return null;
}
For completeness, here's another version that utilizes filter on arrays:
currentViewModel.getReport = function(reportId) {
var reports = currentViewModel.availableReports().filter(function(r) { return r.id() === reportId; });
return reports.length >= 1 ? reports[0] : null;
}

Int from for loop not working in function - JS

I am pretty new to Javascript and have noticed this odd issue come up.
var dispatchMouseEvent = function(target, var_args) {
var e = document.createEvent("MouseEvents");
e.initEvent.apply(e, Array.prototype.slice.call(arguments, 1));
target.dispatchEvent(e);
};
var Level1Cats = document.getElementsByClassName("p-pstctgry-lnk-ctgry "); //GETTING LEVEL 1 CATS
var Level1CatsLen = Level1Cats.length; //GETTING LEVEL 1 CAT LEN
for (i = 0; i <= Level1CatsLen-1; i++) {
var ID1 = Level1Cats[i].id;
var temp1 = Level1Cats[i].innerHTML;
temp1.replace(/&/gi, "&").replace(/<[^>]*>/gi, "");
function GoToLevel2(callback) { //GO TO NEXT LEVEL!
dispatchMouseEvent(Level1Cats[i], "mouseover", true, true);
dispatchMouseEvent(Level1Cats[i], "click", true, true);
}
function GetLevel2() { //GET NEXT LEVEL
var Level2Cats = document.getElementsByClassName("p-pstctgry-lnk-ctgry");
return Level2Cats.length;
}
setTimeout(function() { //RUN IT WITH TIMING
GoToLevel2();
}, 100);
var Level2CatsLen = GetLevel2();
}
When the code is executed it gives me an error (Cannot read property 'dispatchEvent' of undefined)
I know this is because the i in the function does not seem to work. If I simply replace it with an int value of 1 it will execute and click cat 1, 16 times, as expected..
I would have thought this should work, any ideas how I can work around it?
Inside the loop, a closure GoToLevel2 is created, closing over the variable i, when i is 1. Then the loop runs through, i is incremented to 2, and the loop is terminated.
Then your setTimeout fires after 100ms, and invokes your closure. It still remembers that there was once a variable i, but it now contains 2. Level1Cats[2] is undefined, and you get an error.
The standard solution is to enclose the contents of the loop into another self-evaluating function that will not close over i:
for (i = 0; i <= Level1CatsLen-1; i++) {
(function(i) {
// ...
})(i);
}
(Note also that setTimeout(function() { GoToLevel2(); }, 200) is identical to, but less efficient than setTimeout(GoToLevel2, 200).)

Javascript Typerror variable undefined.

I m trying to make a simple dumb tic-tac-toe game using HTML, CSS and Javascript.
In the below function for the player move the ComputerMove Function cannot be called because of Typeerror in JSON object.
function Mymove(idValue)
{
var flag=0;
var image = document.getElementById(idValue);
if (image.src.match("blank.png")) {
image.src = "X.png";
flag=Check();
if (flag==1)
{
alert("You Won");
reset();
return;
};
ComputerMove();
};
}
function Check(){
for (var i =0 ; i <= 8;i++) {
var image=document.getElementById(winList[i].a);
if (!image.src.match("blank.png")) {
if(image.src==document.getElementById(winList[i].b).src && image.src==document.getElementById(winList[i].c).src)
return 1;
}
}
Here is the JSON object below:-
var winList =[
{a:1,b:2,c:3},
{a:4,b:5,c:6},
{a:7,b:8,c:9},
{a:1,b:4,c:7},
{a:2,b:5,c:8},
{a:3,b:6,c:9},
{a:1,b:5,c:9},
{a:3,b:5,c:7}];
The check function works always, and the console response as
TypeError: winList[i] is undefined
While Debugging I found after this error the ComputerMove() function never gets called.
So please help.
Your winList array has a length of 8, with an index spanning from 0 - 7.
Your loop for (var i =0 ; i <= 8;i++) tries to access the winList[8] (when the i == 8), which is undefined - thus crashing the script when you try to access a of undefined (winList[i].a).
Try changing your loop condition to the following: for (var i = 0 ; i < 8; i++)

How to use OOP in jQuery/Javascript to pass a value cross-browser compatible out of a function?

This may be asked several times, but I need it ASAP for a production-environment and I am totally overwhelmed by which objects I could create and use.
function scroll(min, max) {
// do stuff
}
function scrollmore() {
min += 10;
max += 10;
// do more stuff
}
I will accept an answer which guides me on the right path through a link or an explicit answer (which works). ;)
One way to take an OOP approach to this might be something like this. The min and max values are members of the object stored in objVar. This is very much like the object representing the min and max values you were looking for. Why not take it a step or two further, though?
We can include the inScroller() function. Now, since it's a part of the object, it can access objVar.min and objVar.max directly and doesn't need to have them passed to it. You can just call objVar.inScroller(); and it will operate on the variables objVar.min and objVar.max.
So what about incrementing by 10? Extending that same concept, we can create a function that increments the objVar.min and objVar.max variables and simply call it thusly: objVar.increment();.
Next time that objVar.inScroller(); is called, objVar.min and objVar.max will have been incremented by 10 each. You could even put 'em in a loop, like:
for (int i=0;i<totalRuns;i++) {
objVar.inScroller();
objVar.increment();
}
The Object:
var objVar = new function() {
this.min = 0;
this.max = 10;
this.increment() = function() { min += 10; max += 10; }
this.inScroller = function() {
for (var i=min;i<max;i++) {
var pic = $('.scrolling p')[i],
pic = $(pic).text(),
var img = $('<img />').attr("src","img/profile/" + pic).css('display','none');
$('.pfiles').append(img);
$('img').load(function() {
$(this).fadeIn(400)
});
}
}
Finally, it's called thusly:
$(window).scroll(function() {
if ($(window).scrollTop() + window.innerHeight >= $('.pfiles').height() && $('.scrolling p').length > $('.pfiles img').length) {
objVar.increment();
objVar.inScroller();
}
});
Or even thusly:
$(window).scroll(function() {
if ($(window).scrollTop() + window.innerHeight >= $('.pfiles').height() && $('.scrolling p').length > $('.pfiles img').length) {
for (int i=0;i<totalRuns;i++) { objVar.inScroller(); objVar.increment(); }
}
});

Update happens only on the last row, instead of first

function createTextFields(obj) {
for (var i = 0; i < obj.length; i++) {
var dataDump = {};
for (var key in obj[i]) {
var textField = Ti.UI.createTextField(pm.combine($$.labelBrown, {
left: 200,
height:35,
value:obj[i][key],
width:550,
keyboardType:Ti.UI.KEYBOARD_NUMBER_PAD,
layout:'horizontal',
backgroundColor:'transparent',
id:i
}));
dataDump[key] = textField.value;
var callback = function (vbKey) {
return function (e) {
dataDump[vbKey] = e.source.value;
};
}(key);
}
globalData.push(dataDump);
}
}
I am using the simlar code for Adding the data and it works fine. I posted the problem yesterday and it got resolved...
Last Object is always getting updated?
Now when i go to edit page, it shows me four text fields or number of text fields added... now when i edit something and click on save... the value get's updated on the fourth or the last TextFields Object...
Don't define functions inside loops. Computationally expensive and leads to problems, like this one. Here's a fix that should solve it:
function createTextFields(obj) {
var callback = function (vbKey, localDump) {
return function (e) {
localDump[vbKey] = e.source.value;
};
}
var i;
var max = obj.length;
for (i = 0; i < max; i++) {
var dataDump = {};
for (var key in obj[i]) {
dataDump[key] = textField.value;
var callBackInstance = function(keyn, dataDump);
}
globalData.push(dataDump);
}
}
JavaScript does not have block level scope, so your variables dataDump and callback, though "declared" inside for-loops actually belong to the function. As in, you're saving a value to dataDump, then you're overwriting it, each time you go through the loop. Which is why finally only the code that operated on the last value remains.
Take a look at What is the scope of variables in JavaScript? too.

Categories

Resources