Javascript Typerror variable undefined. - javascript

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++)

Related

Passing an object to function. JavaScript

gameI created the following "class":
function State(){
this.board = [];
for (i=0; i< 9; i++){
var row = [];
for (j=0; j< 9; j++){
row.push(0);
}
this.board.push(row);
}
}
It has a method called nextEmptyCell:
State.prototype.nextEmptyCell = function(){
...
}
I created an instance of this class and passed it to another function.
game = new State();
function solveSudoku(game){
var next = game.nextEmptyCell();
...
}
On the following line: var next = game.nextEmptyCell(); I receive an error saying:
"Uncaught TypeError: Cannot read property 'nextEmptyCell' of undefined".
I don't understand why 'game' is undefined and how to fix this error.
Link to the full code: jsfiddle.net/py6kv7ps/5
P.S. Is there a better way of using JS as OOP?
Issue comes from solveSudoku(), you are calling it recursively without passing an argument. Thats why you are getting error.
"Uncaught TypeError: Cannot read property 'nextEmptyCell' of
undefined".
function solveSudoku(game) {
if (solveSudoku(ADD game OBJECT HERE)) {
return game;
}
}
You probably meant game.nextEmptyCell(), not state.nextEmptyCell(). There is no variable named state anywhere in the code you posted.
Its because your parameter game shadows the glbal variable game of the same name. The global variable game = new State(); has the correct value. So you can pass it to your method call to use the correct value of game within the method solveSudoku()
function State(){
this.board = [];
for (i=0; i< 9; i++){
var row = [];
for (j=0; j< 9; j++){
row.push(0);
}
this.board.push(row);
}
}
State.prototype.nextEmptyCell = function(){
console.log('egvse gtrs');
document.write('egvse gtrs');
};
var game = new State();
function solveSudoku(game){
var next = game.nextEmptyCell();
}
solveSudoku(game);

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;
}

Error calling function second time

I have a function which works just fine the first if I call it just once, but when I call it repeatedly within a for loop, I get the following error:
TypeError: getNamedRange is not a function, it is string.
Doing a search on this error gives me a clue that this is a javascript error, not a Google Apps Script error. I haven't worked much with javascript, but I suspect it may have something to do with how I return the value from the function.
This is the code which calls the function:
var ss = SpreadsheetApp.getActiveSpreadsheet();
var baseSheet = ss.getSheetByName("Base");
var catCol = 9;
var riskAreaColumn = 10;
var numRows = baseSheet.getDataRange().getNumRows();
// I am not using this var, should I be?
var data = baseSheet.getDataRange().getValues();
var cell;
var rangeName;
var range;
var rule;
for(var i=2; i<numRows; i++){
cell = baseSheet.getRange(i, riskAreaColumn);
rangeName = getNamedRange("CategoryRiskRange",baseSheet.getRange(i, catCol).getValue());
range = SpreadsheetApp.getActiveSpreadsheet().getRangeByName(rangeName);
rule = SpreadsheetApp.newDataValidation().requireValueInRange(range).build();
cell.setDataValidation(rule);
}
SpreadsheetApp.flush();
}
This is the function being called:
function getNamedRange(categoryRange, category) {
var categoryList = SpreadsheetApp.getActive().getRangeByName(categoryRange).getValues();
for (var i = 0; i < categoryList.length; i++) {
if (categoryList[i][0] == category) {
getNamedRange = categoryList[i][1];
return getNamedRange;
}
}
}
The first time through the for loop works, the second time gives me the aforementioned error. Thank you for reading this, I hope it's clear.
you are overwriting the function definition here:
getNamedRange = categoryList[i][1];
this will work:
if (categoryList[i][0] == category) {
return categoryList[i][1];
}
Javascript doesn't interpret things until it gets to them, and is very happy to redefine things when you tell it to.
The first time through, it sees
function getNamedRange(categoryRange, category)
and says "oh, a function! Cool!" But in that function, you have the line
getNamedRange = categoryList[i][1];
and it says "Oh, so getNamedRange is something else now. Okay, I'm fine with that."
Rename your variable, and you should be fine.

passing array values into a function

In the script below, the console.log is returning the correct values, and both alerts fire. However, the value is coming up undefined.
Any ideas what I'm doing wrong?
jQuery(document).ready(function(){
jQuery("#customfield_21070").attr('style','width:60px');
jQuery("#customfield_21070").attr('disabled','disabled');
var customfields = [
'#customfield_11070',
'#customfield_11071',
'#customfield_20071',
'#customfield_20072',
'#customfield_20073',
'#customfield_20074',
];
for(var i=0, len=customfields.length; i<len; i++) {
console.log(customfields[i]);
jQuery(customfields[i]).keyup(function(){
alert('calculate');//FIRES
calculateSum();
});
}
function calculateSum() {
var sum = 0;
alert('value: ' + this.value);//UNDEFINED
if(!isNaN(this.value) && this.value.length!=0 && this.id !== "customfield_21070") {
sum += parseFloat(this.value);
}
jQuery("#customfield_21070").val(sum.toFixed(2));
}
});
Use Function.prototype.call():
Calls a function with a given this value and arguments provided
individually.
Its first parameter is thisArg:
The value of this provided for the call to fun. Note that this may not
be the actual value seen by the method: if the method is a function in
non-strict mode code, null and undefined will be replaced with the
global object, and primitive values will be boxed.
So, pass this from your handler function to calculateSum like so:
jQuery(customfields[i]).keyup(function(){
calculateSum.call(this);
});
#canon is absolutely correct, following as he said will resolve your Issue.
You can possibly write :-
jQuery(document).ready(function () {
jQuery("#customfield_21070").attr('style', 'width:60px');
jQuery("#customfield_21070").attr('disabled', 'disabled');
var customfields = [
'#customfield_11070',
'#customfield_11071',
'#customfield_20071',
'#customfield_20072',
'#customfield_20073',
'#customfield_20074',
];
for (var i = 0, len = customfields.length; i < len; i++) {
jQuery(customfields[i]).keyup(function () {
calculateSum(this);//Edited
});
}
function calculateSum(param) {//Edited
var sum = 0;
alert('value: ' + param.value);//UNDEFINED
if (!isNaN(param.value) && param.value.length != 0 && param.id !== "customfield_21070") {//Edited
sum += parseFloat(param.value);
}
jQuery("#customfield_21070").val(sum.toFixed(2));
}
});
This reflects proper value in your alert. **Tested**

javascript array error: array[n] is undefined

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.

Categories

Resources