ES6 object.method is not a function - javascript

I have an ES6 class that's defined like this and has a couple of functions:
class Cell{
constructor(i,j){
this.i = i;
this.j = j;
this.alive = false;
this.survives = false; //Made so not to change alive variabe mid-loop, also controls birthing of new cells
}
update(grid){
//Decide if this.survives is true or not
}
render(size){
//Draw's a rectangle in the cell's location in a color based on this.alive
}
}
And a main.js file:
const h = 800; //Height
const w = 800; //Width
const s = 80; //Size of squares
const rows = Math.floor(h / s);
const cols = Math.floor(w / s);
let cells = new Array(cols);
let isActive = false;
//A p5 function that is called once when the page is sketch is loaded
function setup() {
createCanvas(w, h);
for(let i = 0; i < cols; i++){
cells[i] = new Array(rows);
for(let j = 0; j < rows; j++){
cells[i][j] = new Cell(i, j);
}
}
}
//A p5 function that is called every frame
function draw() {
for(i = 0; i < cols; i++){
for(j = 0; j < rows; j++){
if(isActive === true){
cells[i][j].update(cells);
if(cells[i][j].survives){
cells[i][j] = true;
}else{
cells[i][j] = false;
}
}
cells[i][j].render(s);
}
}
}
When I open the webpage everything renders normally but when I set isActive to true through chromes console I get the following error message:
Uncaught TypeError: cells[i][j].render is not a function
I made sure to add references to everything in index.html, I'm not doing anything fancy with require(). It's all with script tags

Probably because right above it you have:
if(cells[i][j].survives){
cells[i][j] = true; // <--- Overwriting the cell!
}else{
cells[i][j] = false; // <--- Overwriting the cell!
}
You're overwriting your cells with Boolean values, and Booleans don't have a render method.
Maybe you meant?:
if(cells[i][j].survives){
cells[i][j].alive = true;
}else{
cells[i][j].alive = false;
}
Although it should be noted that this should really just be written as:
cells[i][j].alive = cells[i][j].survives;

Related

How to resolve a constructor console error in p5.js - data visual

I am basically trying to implement the bubble code (this code will just display the data from the csv file and display them in a bubble ellipse) into a data visualization template and the bubble code should be in an external constructor (meaning it should be in another file with the constructor name). To give u a general idea, i'm making a few tabs and once a tab is clicked - its designated code(constructor) will run.
I created a tab named as 'Food Data in Bubbles' and when that tab is clicked, the constructor should be called.
I don't have any problem with calling the constructor. The thing im having an issue with is that when the constructor is called, it gives an console error as you can see in this image
I want to know how i can resolve this Issue. Just for reference, I'll provide you with the files and code.
This is the index file that I'm using:
<!DOCTYPE html>
<html lang="en">
<head>
<script src="lib/p5.min.js"></script>
<!-- Main sketch file -->
<script src="sketch.js"></script>
<script src="bubble.js"></script>
<body>
<div id="app" class="container">
<ul id="visuals-menu"></ul>
</div>
</body>
</html>
This is the sketch file:
var dataTable;
var myScatter;
var data;
var bubbles = [];
var maxAmt;
var years = [];
var yearButtons = [];
function preload()
{
dataTable = loadTable('data/tech-diversity/gender-2018.csv', 'header');
data = loadTable("data/bubble/foodData.csv", "csv", "header");
}
function setup() {
// Create a canvas to fill the content div from index.html.
var c = createCanvas(1024, 576);
c.parent('app');
// Add the visualisation objects here.
gallery.addVisual(new BubbleData());
}
function draw() {
background(255);
if (gallery.selectedVisual != null) {
gallery.selectedVisual.draw();
}
translate(width/2, height/2);
for(var i = 0; i < bubbles.length; i++)
{
bubbles[i].update(bubbles);
bubbles[i].draw();
}
}
and this is the main Constructor file:
function BubbleData() {
// Name for the visualisation to appear in the menu bar.
this.name = 'Food Data in Bubbles';
// Each visualisation must have a unique ID with no special
// characters.
this.id = 'bubble-data';
// Property to represent whether data has been loaded.
this.loaded = false;
this.setup = function() {
var rows = data.getRows();
var numColumns = data.getColumnCount();
for(var i = 5; i < numColumns; i++)
{
var y = data.columns[i];
years.push(y);
b = createButton(y,y);
b.parent('years')
b.mousePressed(function()
{
changeYear(this.elt.value);
})
yearButtons.push(b);
}
maxAmt = 0;
for(var i = 0; i < rows.length; i++)
{
if(rows[i].get(0) != "")
{
var b = new Bubble(rows[i].get(0));
for(var j = 5; j < numColumns; j++)
{
if(rows[i].get(j) != "")
{
var n = rows[i].getNum(j);
if(n > maxAmt)
{
maxAmt = n; //keep a tally of the highest value
}
b.data.push(n);
}
else
{
b.data.push(0);
}
}
bubbles.push(b);
}
}
for(var i = 0; i < bubbles.length; i++)
{
bubbles[i].setData(0);
}
};
function changeYear(year)
{
var y = years.indexOf(year);
for(var i = 0; i < bubbles.length; i++)
{
bubbles[i].setData(y);
}
};
// Create a new pie chart object.
this.pie = new PieChart(width / 2, height / 2, width * 0.4);
this.draw = function() {
translate(width/2, height/2);
for(var i = 0; i < bubbles.length; i++)
{
bubbles[i].update(bubbles);
bubbles[i].draw();
}
};
this.Bubble = function(_name)
{
this.size = 20;
this.target_size = 20;
this.pos = createVector(0,0);
this.direction = createVector(0,0);
this.name = _name;
this.color = color(random(0,255), random(0,255), random(0,255));
this.data = [];
this.draw = function()
{
push();
textAlign(CENTER);
noStroke();
fill(this.color);
ellipse(this.pos.x, this.pos.y, this.size);
fill(0);
text(this.name,this.pos.x,this.pos.y);
pop();
};
this.update = function(_bubbles)
{
this.direction.set(0,0);
for(var i = 0; i < _bubbles.length; i++)
{
if(_bubbles[i].name != this.name)
{
var v = p5.Vector.sub(this.pos,_bubbles[i].pos);
var d = v.mag();
if(d < this.size/2 + _bubbles[i].size/2)
{
if(d > 0)
{
this.direction.add(v)
}
else
{
this.direction.add(p5.Vector.random2D());
}
}
}
}
this.direction.normalize();
this.direction.mult(2);
this.pos.add(this.direction);
if(this.size < this.target_size)
{
this.size += 1;
}
else if(this.size > this.target_size)
{
this.size -= 1;
}
};
this.setData = function(i)
{
this.target_size = map(this.data[i], 0, maxAmt, 20, 250);
};
};
}
there is another file which is the helper function file through which I'm calling this function and other task but that's unnecessary here, the only problem here is with the constructor file

Uncaught TypeError: Cannot read property 'show' of undefined at draw (sketch.js:49)

I am specifying the function show() inside the function Spot() but still I am getting this error of Uncaught TypeError and its saying its undefined at draw().
This is the Javascript code and I am using p5.js as library.
var cols = 5;
rows = 5;
var grid = new Array(cols);
var w,h;
function Spot(i,j){
this.x = i;
this.y = j;
this.f = 0;
this.g = 0;
this.h = 0;
this.show = function(){
fill(255);
stroke(0);
rect(this.x*w,this.y*h,w-1,h-1);
}
}
function setup(){
createCanvas(400,400);
console.log('A*');
w = width/cols;
h = height/rows;
for(var i = 0; i < cols;i++){
grid[i] = new Array(rows);
}
console.log(grid);
for(var i = 0; i < cols;i++)
{
for(var j = 0; i < rows;i++)
{
grid[i][j] = new Spot(i,j);
}
}
}
function draw(){
background(0);
for(var i = 0; i < cols-1;i++)
{
for(var j = 0; j < rows-1; j++)
{
grid[i][j].show();
}
}
}
body {
padding: 0;
margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/sketch.js/1.1/sketch.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.1.9/p5.min.js"></script>
I am getting this error in chrome console and i am running the html as a web server on my local pc.(localhost:8000)
This is the attached image for the error in google chrome console
I have just started with java script and not able to resolve this error despite extensive searching about it.
It would be helpful if someone knows about it.
Thanks in advance
Have a look in your setup loop.
In the nested loop, you are increasing the i value, instead of the j value.
And your also counting the rows/columns indexes different in the setup and draw.
This might be what you want, just thought I would point it out.
( rows/cols-1 vs cols/rows)
var cols = 5;
var rows = 5;
var grid = new Array(cols);
var w,h;
function Spot(i,j){
this.x = i;
this.y = j;
this.f = 0;
this.g = 0;
this.h = 0;
this.show = function(){
fill(255);
stroke(0);
rect(this.x*w,this.y*h,w-1,h-1);
}
}
function setup(){
createCanvas(400,400);
console.log('A*');
w = width/cols;
h = height/rows;
for(var i = 0; i < cols;i++){
grid[i] = new Array(rows);
}
console.log('grid: ', grid);
for(var i = 0; i < cols-1;i++)
{
for(var j = 0; j < rows-1;j++)
{
grid[i][j] = new Spot(i,j);
}
}
}
function draw(){
background(0);
for(var i = 0; i < cols-1;i++)
{
for(var j = 0; j < rows-1; j++)
{
grid[i][j].show();
}
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/sketch.js/1.1/sketch.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.1.9/p5.min.js"></script>

Why is theMethod on Object returns undefined

I'm trying to call a method walkDown(y,id){} on my object game and it returns undefined. The similar method walkUp(y,id){} works as intended. Here is the code:
class Game {
constructor(row,col,players) {
this.players = players;
this.row = row;
this.col = col;
this.gameBoard=[];
for (let i=0; i<row; i++){
this.gameBoard[i] =[];
for (let y =0; y<col; y++){
this.gameBoard[i][y] = 0;
}
}
}
placing(id){
var place = true;
while(place){
var y = Math.floor(Math.random()*10);
var x = Math.floor(Math.random()*10);
if (this.gameBoard[y][x] === 0){
this.gameBoard[y][x] = this.players[id];
place = false;
} //if finish
} // while finish
}// function placing finish
walkDown(y,id){
for(var k = 0; k < this.gameBoard.length; k++){
for(var m = 0; m < this.gameBoard[k].length; m++){
if(this.gameBoard[k][m]===this.players[id]){
this.gameBoard[k][m] = 0;
this.gameBoard[k+y][m]= this.players[id];
}
}
}
}
walkUp(y,id){
for(var k = 0; k < this.gameBoard.length; k++){
for(var m = 0; m < this.gameBoard[k].length; m++){
if(this.gameBoard[k][m]===this.players[id]){
this.gameBoard[k][m] = 0;
this.gameBoard[k-y][m]= this.players[id];
}
}
}
}
}// Class Game finish
class Player{
constructor(id){
this.id = id;
}
}
const game = new Game(10,10,[new Player(0), new Player(1)]);
game.placing(0);
game.placing(1);
// game.walkUp(1,0); will work
// game.walkDown(1,0); throws an error
The undefined comes from this line of code this.gameBoard[k+y][m]= this.players[id]. However as mentioned above the method walkUp(y,id){} with the similar line of code this.gameBoard[k-y][m]= this.players[id] presents the required result.
What am I doing wrong here? Link to the code
https://jsbin.com/kizateh/edit?js,console

Changing status of <td> on click with javascript

I am making a conways game of life in javascript and having trouble getting my onclick implementation to work. It is supposed to change the life status of the cell when the td is clicked, but instead I am getting an error at my console that says : TypeError: World.tds is undefined.
TLDR: Can't figure out why onclick won't work. World.tds[] is undefined for some reason.
Onclick implementation:
if (table !== null) {
for (var i = 0; i < 20; i++) {
for (var j = 0; j < 20; j++)
World.tds[i][j].onclick = function() {
if (World.tds[i][j].cells.alive) {
World.tds[i][j].cells.alive = false;
} else {
World.tds[i][j].cells.alive = true;
}
};
}
}
Constructor and tds[] filling
var World = function() {
this.h = maxH;
this.w = maxW;
this.tds = [];
};
//generate the world in which the cells move
World.prototype.init = function() {
var row, cell;
for (var r = 0; r < this.h; r++) {
this.tds[r] = [];
row = document.createElement('tr');
for (var c = 0; c < this.w; c++) {
cell = document.createElement('td');
this.tds[r][c] = cell;
row.appendChild(cell);
}
table.appendChild(row);
}
};
Problem Statement - When you trigger the click handler, by that time values of i and j have updated to 20 each and World.tds[20][20] is undefined.
Update your code inside for loop to
(function(i,j) {
World.tds[i][j].onclick = function() {
if (World.tds[i][j].cells.alive) {
World.tds[i][j].cells.alive = false;
} else {
World.tds[i][j].cells.alive = true;
}
};
})(i,j);

Javascript Dynamically added HTML

Please Look at the following code only the last image moves.
http://jsfiddle.net/u8Bg3/
But second one works
http://jsfiddle.net/u8Bg3/1/
As pointed by the Er144 even this works with jquery
http://jsfiddle.net/u8Bg3/14/
I also found out appendchild works but not innerhtml
The difference between two is that in first one html exits in second one it's dynamically created
HTML
<body>
<div class="racetrack" id="racetrack"></div>
<div id="track-tmpl" class="hide">
<div class="track"><div id="player{{ x }}" class="runner"></div></div>
</div>
</body>
JS
var position = [0,40,80,120,80],
racetrack = document.getElementById('racetrack');
track_tmpl = document.getElementById('track-tmpl').innerHTML;
function Players(ele, ptimeout)
{
this.el = ele;
this.i = 0;
this.iterations = 0;
this.stop = 0;
this.timeout = ptimeout;
this.position = 0;
this.animate = function(){
if(this.i !== 0){
this.move((this.position + 5), this.i);
}
if(!this.stop){
if(this.i < 5){
setTimeout(function(_this){
_this.i++;
_this.animate();
},this.timeout,this);
}
if(this.i==5){
this.iterations ++;
if(this.iterations < 50){
this.i = 0;
this.animate();
}
else{
this.el.style.backgroundPosition = '120px 0px';
}
}
}
};
this.start = function(){
this.stop = 0;
this.animate();
};
this.move = function(to,positionIndex){
this.position = to;
this.el.style.backgroundPosition = '-'+position[positionIndex]+'px 0px';
this.el.style.webkitTransform = 'translate('+to+'px)';
this.el.style.mozTransform = 'translate('+to+'px)';
}
}
function Game(noOfPlayers){
this.noOfPlayers = noOfPlayers;
this.players = new Array();
for (var i = 0; i < this.noOfPlayers ; i++){
racetrack.innerHTML = racetrack.innerHTML + track_tmpl.replace('{{ x }}', i);
this.players.push(new Players(document.getElementById('player' + i), (120 + i)));
/* issue here with dynamic added content*/
}
this.start = function(){
for (var i = 0; i < this.noOfPlayers; i++){
this.players[i].start();
}
};
}
var game = new Game(3);
game.start();
Why is that in dynamically added html only the last one moves
The issue is with creating the player(n) object inside the for loop along with the assignments to innerHTML using `+='. The modified fiddle: http://jsfiddle.net/u8Bg3/15/ works fine. Cheers for a good question!
var finalized_tracks= "" ;
for (var i = 0; i < this.noOfPlayers ; i++){
finalized_tracks += track_tmpl.replace('{{ x }}', i);
}
racetrack.innerHTML = racetrack.innerHTML + finalized_tracks;
for (var i = 0; i < this.noOfPlayers ; i++){
this.players.push(new Players(document.getElementById('player'+ i),(120+i)));
}
If you use the jquery:
var element = track_tmpl.replace('{{ x }}', i);
$(racetrack).append(element);
instead of the line where you change the innerHtml of racetrack div, all elements are moving.
However, I'm not sure, why...
theCoder has pretty much nailed the issue with your code there.
Just as an additional thought, you could manually build the necessary divs using javascript instead, it's more long winded however...
for (var i = 0; i < this.noOfPlayers ; i++){
var newTrack = document.createElement("div");
newTrack.id = "track"+i;
newTrack.className = "track";
var newPlayer = document.createElement("div");
newPlayer.id = "player"+i;
newPlayer.className = "runner";
newTrack.appendChild(newPlayer);
racetrack.appendChild(newTrack);
this.players.push(new Players(document.getElementById('player' + i), (120 + i)));
}

Categories

Resources