Changing status of <td> on click with javascript - 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);

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

Send a grid as json

I'm relatively new to the world of JavaScript. I create a grid in which I can select any cells.
Now I would like to send all cells as binary with a Json document to the backend. For this purpose, an unselected cell should have a 0 and a selected one should have a 1. I orientate myself on Conway's Game of Life. I've been at it for 2 days now and don't know how best to implement it. Does anyone have an idea?
Here is my code to create the grid
var rows = 10;
var cols = 10;
var grid = new Array(rows);
var nextGrid = new Array(rows);
var startButton = document.getElementById('start');
startButton.addEventListener('click', event => {
initialize()
})
function initializeGrids() {
for (var i = 0; i < rows; i++) {
grid[i] = new Array(cols);
nextGrid[i] = new Array(cols);
}
}
function copyAndResetGrid() {
for (var i = 0; i < rows; i++) {
for (var j = 0; j < cols; j++) {
grid[i][j] = nextGrid[i][j];
}
}
}
// Initialize
function initialize() {
createTable();
initializeGrids();
}
// Lay out the board
function createTable() {
var gridContainer = document.getElementById('gridContainer');
if (!gridContainer) {
// Throw error
console.error("Problem: No div for the drid table!");
}
var table = document.createElement("table");
for (var i = 0; i < rows; i++) {
var tr = document.createElement("tr");
for (var j = 0; j < cols; j++) {
var cell = document.createElement("td");
cell.setAttribute("id", i + "_" + j);
cell.setAttribute("class", "dead");
cell.onclick = cellClickHandler;
tr.appendChild(cell);
}
table.appendChild(tr);
}
gridContainer.appendChild(table);
}
function cellClickHandler() {
var rowcol = this.id.split("_");
var row = rowcol[0];
var col = rowcol[1];
var classes = this.getAttribute("class");
if(classes.indexOf("live") > -1) {
this.setAttribute("class", "dead");
grid[row][col] = 0;
} else {
this.setAttribute("class", "live");
grid[row][col] = 1;
}
}

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>

Non-loading Results with insertCell.innerHTML

For some reason when I put use .innerHTML to change the text of the cell, the code never stops and stays within the last statement. How do I get the code to run how it's supposed to run and not stop within the last if statement.
w3.filterHTML = function(id, sel, filter) {
var a, b, c, i, ii, iii, hit;
var searchItem = document.getElementById('search-list');
var row = searchItem.insertRow(0);
var rows = searchItem.rows.length;
var cell = row.insertCell(0);
a = w3.getElements(id);
for (i = 0; i < a.length; i++) {
b = w3.getElements(sel);
for (ii = 0; ii < b.length; ii++) {
hit = 0;
if (b[ii].innerHTML.toUpperCase().indexOf(filter.toUpperCase()) > -1) {
hit = 1;
}
c = b[ii].getElementsByTagName("*");
for (iii = 0; iii < c.length; iii++) {
if (c[iii].innerHTML.toUpperCase().indexOf(filter.toUpperCase()) > -1) {
hit = 1;
}
}
//Here is what you need to edit.
if (hit == 1) {
// b[ii].style.display = "";
console.log(filter);
var row = searchItem.insertRow(0);
var cell = row.insertCell(0);
document.getElementById("search-list").insertRow(0).insertCell(0).innerHTML = '<a class="list-group-item" href="#">Hello</a>';
} else {
// searchItem.b[ii].style.display = "none";
}
}
}
};
`
I copied the code from W3Schools (the filterHTML function).

ES6 object.method is not a function

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;

Categories

Resources