I'm working on a HTML / Javascript project to create a simple game of Minesweeper. In order to create a clickable grid of cells, I adopted code that I found in another thread. That code works perfectly on its own (see this JSBin for more details):
var lastClicked;
var grid = clickableGrid(10,10,onClick);
document.body.appendChild(grid);
// This is the clickableGrid object constructor. It takes in the number of rows and columns
// for the grid, and a callback function that will be executed when a cell is clicked
function clickableGrid( rows, cols, callback ){
// 'i' is the variable that will store the number in each cell. A 10x10
// grid, for example, will see i range from 1 (top left cell) to 100 (bottom right cell)
var i=0;
// Create the table element and assign it a class name so that CSS formatting
// may be applied
var grid = document.createElement('table');
grid.className = 'grid';
// Build the grid row by row
for (var r=0;r<rows;++r){
// Create a table row element and append it to the table element ('grid')
var tr = grid.appendChild(document.createElement('tr'));
tr.row = r;
// Build the row cell by cell
for (var c=0;c<cols;++c){
// Create the cell element and append it to the row element ('tr')
var cell = tr.appendChild(document.createElement('td'));
// Input the number to the cell's innerHTML
cell.innerHTML = ++i;
// Add an event listener that will execute the callback function
// when the cell is clicked, using the cell's element and information
cell.addEventListener('click',(function(el, r, c, i){
return function() {
callback(el, r, c, i);
}
})(cell, r, c, i),false);
}
}
return grid;
}
// This function contains the actions we want to be executed when the click occurs
function onClick(el, row, col, i) {
// Log to the console the details of the cell that was clicked
console.log("You clicked on element:",el);
console.log("You clicked on row:",row);
console.log("You clicked on col:",col);
console.log("You clicked on item #:",i);
// Record in the element that it was clicked
el.className='clicked';
// If the element is not the same as
if (lastClicked) lastClicked.className='';
lastClicked = el;
}
However, I can't seem to make it work properly in my Minesweeper game. The "mined" grid gets built and appended to the DOM, but the innerHTML and listeners are not applied. This other JSBin contains all the game code I have so far. The current process is:
1) Run init to initialize the page and create all elements. Part of this includes adding an event listener to the "New Game" button.
2) When the "New Game" button is clicked, create a clickable grid that will be "mined". At the moment, no mines get placed, but the code tries to place an "X" inside each cell. Furthermore, each cell should have an event listener attached to it.
The relevant code section in the game is:
function startGame() {
var gameDifficulty = document.getElementsByTagName("select")[0].value;
var currGrid = document.querySelector('.grid');
var newGrid = new minedGrid(gameDifficulty, onClick);
currGrid.parentNode.replaceChild(newGrid, currGrid);
}
// minedGrid object constructor: creates and returns a fully-mined and
// prepared Minesweeper grid
function minedGrid(difficulty, callback){
var rows, cols, mines;
var newGrid = document.createElement('table');
newGrid.className = 'grid';
switch (difficulty) {
case 0:
rows = 10;
cols = 10;
mines = 10;
break;
case 1:
rows = 16;
cols = 16;
mines = 40;
break;
case 2:
rows = 16;
cols = 30;
mines = 99;
break;
default:
rows = 10;
cols = 10;
mines = 10;
break;
}
for (var r = 0; r < rows; ++r) {
var tr = newGrid.appendChild(document.createElement('tr'));
for (var c = 0; c < cols; ++c) {
var cell = tr.appendChild(document.createElement('td'));
cell.innerHTML = "X";
cell.addEventListener('click',(function(el, r, c){
return function() {
callback(el, r, c);
}
})(cell, r, c),false);
}
}
return grid;
}
// This function contains the actions we want to be executed when the click occurs
function onClick(el, row, col) {
// Log to the console the details of the cell that was clicked
console.log("You clicked on element:",el);
console.log("You clicked on row:",row);
console.log("You clicked on col:",col);
// Record in the element that it was clicked
el.className='clicked';
// If the element is not the same as
if (lastClicked) lastClicked.className='';
lastClicked = el;
}