I am making a tic-tac-toe game in which I have a series of 9 buttons. I change the background image to an X or an O based on the boolean value of variable isX.
I have a div with an id stage which holds all the buttons of class square. I added a listener on the stage and passed it an event parameter. However, the function clickHandler is not recognized. Chrome says:
Uncaught ReferenceError: clickHandler is not defined 2Players.html:38
(anonymous function)
HTML:
<body>
<div id="stage">
</div>
</body>
CSS:
#stage{
width: 400px;
height: 400px;
padding: 0px;
position: relative;
}
.square{
width: 64px;
height: 64px;
background-color: gray;
position: absolute;
}
JavaScript:
const ROWS = 3;
const COLS = 3;
const GAP = 10;
const SIZE = 64;
var stage = document.querySelector("#stage");
var lotOfButtons = [];
var winningPatterns = ["123","159","147",
"258","357","369",
"456","789"];
var isX = true;
var player1Pattern = "";
var player2Pattern = "";
stage.addEventHandler("click",clickHandler,false);
prepareBoard();
function prepareBoard(){
for(var row = 0;row<ROWS;row++){
for(var col = 0;col < COLS;col++){
var square = document.createElement("button");
square.setAttribute("class","square");
stage.appendChild(square);
lotOfButtons.push(square);
square.style.left = col * (SIZE+GAP) + "px";
square.style.top = row * (SIZE+GAP) + "px";
}
}
function clickHandler(event){
if(isX===true){
event.target.style.backgroundImage = "url(../img/X.PNG)";
isX = false;
}else{
event.target.style.backgroundImage = "url(../img/O.PNG)";
isX = true;
}
}
}
You have some syntax and semantic errors in the code -- possibly more than I caught, but it is in a working state.
You only closed one of the braces in the nested for loops in prepareBoard. This leads to clickHandler being defined inside prepareBoard rather than on window.
It's addEventListener, not addEventHandler.
http://jsfiddle.net/4pgQ8/
Related
I'm making a simple tic tac toe game as my introduction to JS and I ran into a problem almost immediately. I have a div with the class="container", and I use JS to create 9 more div elements inside it.
I have created the div elements with and put them in the cells[] array with no problem. The problem arrises when i try to access .style from the array elements.
const container = document.getElementById("container");
const cells = [];
for (let i = 0; i < 9;) {
cells[i] = document.createElement("div");
container.appendChild(cells[i]);
cells[i].onclick = function(){cells[i].style.backgroundColor = "red";} //this line is where the problem is
i++;
}
I have gone about this using addEventHandler() too, still with me not being able to access the .style property. When I type it in it doesn't show up on that autofill thing VSCode does.
Help?
Ps. I have noticed the cells[] array can't always access it's elements when inside a block.
This issue is due to how closures work in JavaScript.
Here's a demo with your current code (plus some CSS to make it clear what's happening):
const container = document.getElementById("container");
const cells = [];
for (let i = 0; i < 9;) { // actually, the problem is here...
cells[i] = document.createElement("div");
container.appendChild(cells[i]);
cells[i].onclick = function(){cells[i].style.backgroundColor = "red";} // ...here...
i++; // ...and here
}
div:not([class]) {
height: 20px;
border: 1px solid white;
background: cornflowerblue;
}
div:hover {
opacity: .5;
}
<container id="container"></container>
Note that the next div is always highlighted, not the one that was clicked.
Because you increment i within the block itself, that value is captured by the onclick callback, so it's always 1 higher than it should be.
Instead, you need to increment i within the parentheses as the third setup statement for the loop itself.
Here's the fix:
const container = document.getElementById("container");
const cells = [];
for (let i = 0; i < 9; ++i) { // increment here...
cells[i] = document.createElement("div");
container.appendChild(cells[i]);
cells[i].onclick = function() { cells[i].style.backgroundColor = "red"; }
// ...not here
}
div {
height: 20px;
border: 1px solid white;
background: cornflowerblue;
}
div:hover {
opacity: .5;
}
<container id="container"></container>
const container = document.querySelector('.container');
for (let i = 0; i < 9; ) {
const div = document.createElement('div');
container.appendChild(div);
div.addEventListener('click', chanegColor);
div.classList.add('setWidth');
i++;
}
function chanegColor() {
this.style.backgroundColor = 'red';
}
.setWidth {
width: 100px;
height: 100px;
border: 1px solid black;
}
<div class="container"></div>
const container = document.querySelector('.container');
for (let i = 0; i < 9; ) {
const div = document.createElement('div');
container.appendChild(div);
div.addEventListener('click', chanegColor);
div.classList.add('setWidth');
i++;
}
function chanegColor() {
this.style.backgroundColor = 'red';
}
I have two divs, one for left side and one for right side.
On the left one I appended 5 different images. I need to clone those 5 to the right one, append them to the right one and delete the last node.
For the left one:
var LS = document.getElementById("left");
var number = 5;
while(number > 0)
{
var theImage = document.createElement("img");
LS.appendChild(theImage);
number--;
}
For the right side:
var RS = document.getElementById("right");
var leftImages = LS.cloneNode(true);
RS.appendChild(leftImages);
while(RS.lastChild!=null)
{
var noviCh = RS.lastChild;
}
RS.removeChild(noviCh);
Code doesn't work. Anyone has idea why?
Instead of adding all the images and then removing one, how about just not adding the last one in the first place?
var LS = document.getElementById("left");
for (var i = 0; i < 5; i += 1) {
var theImage = document.createElement("img");
LS.appendChild(theImage);
}
var RS = document.getElementById("right");
var imgs = LS.getElementsByTagName('img');
for (var i = 0; i < imgs.length - 1; i += 1) {
RS.appendChild(imgs[i].cloneNode(true));
}
#left {
background-color: yellow;
}
#right {
background-color: green;
}
img {
width: 100px;
height: 100px;
background-color: red;
}
<div id="left"></div>
<div id="right"></div>
var LS = document.getElementById("left");
for ( var number = 5; number > 0; number--)
{
LS.appendChild(document.createElement("img"));
}
and
var RS = document.getElementById("right");
while( LS.lastChild )
{
RS.appendChild( LS.lastChild.cloneNode(true) );
LS.removeChild( LS.lastChild );
}
I am trying to make a memory board game. I got the css part of the game done, but how it the JavaScript part suppose to work out. I tried using the codes below. When I click on the box, even if they are the same, the box won't disappear and when it's not the same number, the box doesn't turn back. Also, for my "gamebox", I want to add a picture to be the background. I couldn't get it to work. Can anyone help me. Thanks.
<html>
<style>
#gamebox
{
position: absolute;
top: 100px;
left: 100px;
background-image: url("https://www.google.com/url?sa=i&rct=j&q=&esrc=s&source=images&cd=&cad=rja&uact=8&ved=&url=http%3A%2F%2Fwww.pokemontimes.it%2Fhome%2F2014%2F10%2Fannunciato-il-pokemon-center-mega-tokyo-in-apertura-a-dicembre%2F%3F%3Drelated&psig=AFQjCNFGPAm9tU9MR4AZJKe1s6F90F8UFg&ust=1454720806721506");
}
div.box
{
position: absolute;
background-color: red;
top: -800px;
left: -800px;
width: 100px;
height: 100px;
text-align: center;
font-size: 30px;
}
div.box:hover
{
background-color: blue;
}
</style>
<div id=gamebox></div>
<div id=boxdiv class=box onclick="clickedBox(this)"></div>
<script>
var squaresize = 100;
var numsquares = 6;
var numClicked = 0;
var firstClicked;
var secondClicked;
var game = [];
for (var i = 0; i < numsquares; i++)
{
game[i] = [];
for (var j = 0; j < numsquares; j++)
{
game[i][j] = Math.floor(Math.random()*5);
makeBox(i, j);
}
}
function theSame(abox, bbox)
{
var boxParts = abox.id.split("-");
var i = boxParts[1];
var j = boxParts[2];
var boxaNum = game[i][j];
var boxParts = bbox.id.split("-");
i = boxParts[1];
j = boxParts[2];
var boxbNum = game[i][j];
return(boxaNum == boxbNum);
}
function nextTurn()
{
if (numClicked != 2)
return;
if (theSame(firstClicked, secondClicked))
{
deleteBox(firstClicked);
deleteBox(secondClicked);
}
else
{
hideBox(firstClicked);
hideBox(secondClicked);
}
numClicked = 0;
}
function hideBox(box)
{
box.innerHTML = "";
box.style.backgroundColor = "red";
}
function deleteBox(box)
{
//really delete the box
box.style.backgroundColor = "";
}
function showBox(box)
{
var boxParts = box.id.split("-");
var i = boxParts[1];
var j = boxParts[2];
box.innerHTML = game[i][j];
box.style.backgroundColor = "black";
box.style.color = "white";
}
function clickedBox(box)
{
showBox(box);
numClicked++;
if (numClicked == 1)
{
firstClicked = box;
return;
}
if (numClicked == 2)
{
secondClicked = box;
}
}
function makeBox(i, j)
{
var boxdiv = document.getElementById("boxdiv");
var newBox = boxdiv.cloneNode(true);
newBox.style.left = i * (squaresize + 5);
newBox.style.top = j * (squaresize + 5);
newBox.style.width = squaresize;
newBox.style.height = squaresize;
newBox.id = 'box-' + i + '-' + j;
var gamebox = document.getElementById("gamebox");
gamebox.appendChild(newBox);
}
</script>
</html>
I think you're not calling nextTurn() anywhere in your code, meaning theSame() is never called, so nothing gets compared to eachother.
Maybe try calling nextTurn() when the numClicked === 2 in the clickedBox() function.
I am trying to use JavaScript to update the CSS layout as the webpage loads. My code looks like so:
var container = 0; // Add Total UI
var containerTitle = 0; // Container Title
var article = 0;
var articleTitle = 0;
var divName = 0; // temp variable for article id names
var divNameT = 0; // temp variable for title id names
function setLayout(id) {
container = document.getElementById(id);
for(var x = 0; x < 18; ++x) {
// CREATE CONTAINER FOR ALL PANELS
divName = "articleCon"+ x;
article = document.createElement('div');
article.id = divName;
// SETUP CSS STYLE
article.style.cssText = 'height: 205px; width: 300px; background: red; margin-right: 20px; margin-bottom: 20px; display: block; float: left;';
setNewsTitle(count,divName); // Function Call to set Title Panel
container.appendChild(article);
}
}
function setNewsTitle(count,id) {
containerTitle = document.getElementById(id);
// CREATE CONTAINER FOR TITLE
divNameT = "articleTitle"+ count;
articleTitle = document.createElement('div');
articleTitle.id = divNameT;
// SETUP CSS STYLE
articleTitle.style.cssText = 'position: absolute; height: 45px; width: 100px; background: yellow; display: inline;';
containerTitle.appendChild(articleTitle);
}
When I compile my code without making the call to function setNewsTitle(count,id) all the CSS elements are working fine.
The issue I am facing here is whenever the function call is made, my page appears blank. Nothing displays on the screen.
I tried adding screenshots for better understanding, but i don't have the reputation yet.
Try ...
container.appendChild(article);
setNewsTitle(x,divName); // Function Call to set Title Panel
The article needs to be in place before setNewsTitle is run, since you are looking for the element by id. Also, you do not have count, you have x ...
jsFiddle: http://jsfiddle.net/rfornal/o1wyae74/
Try this, append child in DOM before call funtion setNewsTitle, replace count with x :
var container = 0; // Add Total UI
var containerTitle = 0; // Container Title
var article = 0;
var articleTitle = 0;
var divName = 0; // temp variable for article id names
var divNameT = 0; // temp variable for title id names
function setLayout(id) {
container = document.getElementById(id);
for(var x = 0; x < 18; ++x) {
// CREATE CONTAINER FOR ALL PANELS
divName = "articleCon"+ x;
article = document.createElement('div');
article.id = divName;
// SETUP CSS STYLE
article.style.cssText = 'height: 205px; width: 300px; background: red; margin-right: 20px; margin-bottom: 20px; display: block; float: left;';
container.appendChild(article);
setNewsTitle(x,divName); // Function Call to set Title Panel
}
}
function setNewsTitle(count,id) {
containerTitle = document.getElementById(id);
// CREATE CONTAINER FOR TITLE
divNameT = "articleTitle"+ count;
articleTitle = document.createElement('div');
articleTitle.id = divNameT;
// SETUP CSS STYLE
articleTitle.style.cssText = 'position: absolute; height: 45px; width: 100px; background: yellow; display: inline;';
containerTitle.appendChild(articleTitle);
}
You have 2 issues in your code:
You have not actually added the element to the DOM yet, so when you attempt document.getElementById in your function setNewsTitle() - it won't find anything.
You have an error in the method call to setNewsTitle(count,id). You are passing "count", but count doesn't exist. You need to call it as setNewsTitle(x, divName) but only AFTER you have made the call to container.appendChild(article).
The setLayout function would end up something like this:
function setLayout(id) {
container = document.getElementById(id);
for(var x = 0; x < 18; ++x) {
// CREATE CONTAINER FOR ALL PANELS
divName = "articleCon"+ x;
article = document.createElement('div');
article.id = divName;
// SETUP CSS STYLE
article.style.cssText = 'height: 205px; width: 300px; background: red; margin-right: 20px; margin-bottom: 20px; display: block; float: left;';
// Add it to the DOM first
container.appendChild(article);
// need to pass "X", not count
setNewsTitle(x,divName); // Function Call to set Title Panel
}
}
I am looking to create a grid of 3x3 text input boxes, relative to an existing square div, using pure JavaScript. Preferably I would like to construct the grid of a single 1D array that cycles through every third box (if not, then an array of an array of input boxes would do - I hope this makes sense). This is what my code looks like at the moment, but only three of the boxes show when I cycle the array length (if I don't then the array extends linearly across beyond the div confines):
var row0 = new Array(9);
for (var i = 0; i < 9; ++i)
{
row0[i] = document.createElement('input');
row0[i].style.position = "absolute";
row0[i].type = "text";
row0[i].style.marginLeft = 35px *i % 105 + "px";
row0[i].style.width = "35px";
row0[i].style.height = "35px";
document.getElementById('block1').appendChild(row0[i]);
}
How can I get the grid to display correctly?
I would use a combination of javascript and CSS
DEMO http://jsfiddle.net/x8dSP/3010/
JS
window.onload = function () {
var parent_div = document.createElement("div")
parent_div.id = "parent"
document.body.appendChild(parent_div);
var x = 0;
while (x < 9) {
var child_input = document.createElement("input")
child_input.className = "child"
document.getElementById(parent_div.id).appendChild(child_input);
x++;
}
}
CSS
div {
width: 150px;
}
input {
display: inline-block;
width: 30px;
height: 30px;
margin: 5px;
}