I'm on my first week in a coding bootcamp, and I'm working through a class project where we create DOM elements with js. I have created a button that will add a div to my html when it is pressed, and I've also added several other events such as .onclick and .onmouseover. Each div's id is set to the .length of the div's that share the same class name. I am trying to have the nextsibling div removed, when a div is clicked on and the id of that div is an even number, but I'm getting a returned value of 'null'. I can't figure out what I'm missing...any help would be appreciated!
Here is my full code:
document.addEventListener('DOMContentLoaded', function() {
var button = document.createElement('button');
button.innerHTML = "button";
button.id = "boxButton";
document.body.appendChild(button);
document.getElementById("boxButton").onclick = function() {buttonClick()};
var colors = ['red', 'yellow', 'blue', 'green', 'orange']
function buttonClick() {
var mainDiv = document.createElement('div');
var box = document.createElement('div');
box.className = "black-box";
document.body.appendChild(mainDiv);
mainDiv.appendChild(box);
var divCounter = document.getElementsByClassName('black-box');
var divNumber = divCounter.length.toString();
box.id = divNumber;
box.onmouseover = function() {
document.getElementById(divNumber).innerHTML = divNumber;
box.className = 'hover-box';
}
box.onmouseleave = function() {
box.className = "black-box";
}
box.onclick = function() {
var randomColor = colors[Math.floor(Math.random()*colors.length)];
document.getElementById(divNumber).style.backgroundColor = randomColor;
}
box.ondblclick = function() {
if (divNumber % 2 === 0) {
var nextDiv = document.getElementById(divNumber).nextSibling;
console.log(nextDiv) <-- getting a 'null' value to console -->
}
}
}
});
I've cleaned up the code a bit and tried to show you that you should only add maindiv once, and not on every button click, then your black-box's will be siblings.
document.addEventListener('DOMContentLoaded', function() {
// Returns a random integer between min (included) and max (excluded)
function getRandomInt(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min)) + min;
}
var colors = ['red', 'yellow', 'blue', 'green', 'orange'];
var mainDiv = document.createElement('div');
mainDiv.id = 'mainDiv';
var button = document.createElement('button');
button.textContent = 'button';
button.id = 'boxButton';
button.addEventListener('click', function() {
var box = document.createElement('div');
box.id = document.getElementsByClassName('black-box').length + 1;
box.className = 'black-box';
box.addEventListener('mouseover', function(evt) {
evt.target.textContent = evt.target.id;
box.className = 'hover-box';
}, false);
box.addEventListener('mouseleave', function() {
box.className = 'black-box';
}, false);
box.addEventListener('click', function(evt) {
var randomColor = colors[getRandomInt(0, colors.length)];
evt.target.style.backgroundColor = randomColor;
}, false);
box.addEventListener('dblclick', function(evt) {
if (evt.target.id % 2 === 0) {
var nextDiv = evt.target.nextSibling;
console.log(nextDiv);
}
}, false);
mainDiv.appendChild(box);
}, false);
document.body.appendChild(button);
// only want to add this once, not on every click
document.body.appendChild(mainDiv);
}, false);
#mainDiv {
border: 1px solid black;
}
.black-box {
height: 1em;
width: 100%;
border: 1px solid black;
}
Related
The onClick event listener gets blocked by image and the square-box container behind it wont change color. How do I get around this so when I click on the checker piece image, the square-box behind it changes color?
Here's a video demonstration: https://www.youtube.com/watch?v=o4kXo4EWuZE
HTML Code
<!DOCTYPE html>
<html>
<head></head>
<body>
<script src="test.js"></script>
<input type="button" onclick="checkers()" value="Checkers">
<br>
<br>
<checkerboard>
</checkerboard>
<br>
<br>
<br>
<br>
</body>
</html>
Javascript code
'use strict'
// generates a parent container for the event listener.
function main_container(flag)
{
let body = document.getElementsByTagName("checkerboard");
let maincontainer = document.createElement("main-container1");
body[0].append(maincontainer);
maincontainer.setAttribute("id", 'main00');
maincontainer.style.border= "thick double black";
maincontainer.style.display = "inline-block";
return maincontainer;
}
// generates a parent row container to score grid squares.
function UI_box(UI_box_number,flag)
{
let body;
body = document.getElementsByTagName("main-container1");
let Rowcontainer = document.createElement("div");
body[0].append(Rowcontainer);
Rowcontainer.setAttribute("class", "row-container");
Rowcontainer.style.display = "flex";
return Rowcontainer;
}
//generates the squares
function square(Rowcontainer, color)
{
let square = document.createElement('div');
square.setAttribute("class", 'square-box');
square.style.width = "80px";
square.style.height = "80px";
square.style.margin = "2px 2px 2px 2px";
square.style.backgroundColor = color;
Rowcontainer.append(square);
return square;
}
function clickevent()
{
let maincontainer = document.getElementById("main00");
let selected;
let color;
maincontainer.addEventListener("click", function onClick(event)
{
let target=event.target;
if(target.classList.contains("square-box"))
{
if(selected !=null)
{
selected.classList.add(selected.style.backgroundColor = color);
}
color=target.style.backgroundColor;
target.classList.add(target.style.backgroundColor = "blue");
selected=target;
}
});
}
function checkers()
{
let body = document.getElementsByTagName("body");
main_container(0);
let color = "";
// loop down the rows. 8 is number of rows
for(let rowloop = 0; rowloop < 8; rowloop++)
{
//create new container for the row.
let Rowcontainer = UI_box(String(rowloop), 0);
// loop across the columns. 8 is number of columns
for(let columnloop = 0; columnloop < 8; columnloop++)
{
if(columnloop % 2 == 0 && rowloop %2 == 0)
{
color = "red";
}
else
{
color = "black";
if(rowloop % 2 != 0 && columnloop % 2 != 0)
{
color = "red";
}
}
// generates a parameterized square and attaches it to the row container.
if(color=='black' && rowloop <3)
{
let img = document.createElement("img");
img.src = "red.png";
let block1= square(Rowcontainer, color, rowloop, columnloop, img);
block1.append(img.cloneNode());
}
else if(color=='black' && rowloop >4)
{
let img = document.createElement("img");
img.src = "white.png";
let block1= square(Rowcontainer, color, rowloop, columnloop, img);
block1.append(img.cloneNode());
}
else
{
square(Rowcontainer, color, rowloop, columnloop);
}
}
}
clickevent();
}
Add pointer-events="none" to the checkers'style. You can do it in JavaScript like this:
let img = document.createElement("img");
img.src = "red.png";
img.style.pointerEvents = "none";
and, similarly:
let img = document.createElement("img");
img.src = "white.png";
img.style.pointerEvents = "none";
How can I remove divs with class name "grid-item" in the grid? How to iterate through them and remove them? I want to use the reset() function to delete every element with class name "grid-item.
const container = document.getElementById("container");
let canvasSize = Number(prompt("Enter amount of squares per side to make the new grid"));
let resetButton = document.createElement("button");
resetButton.innerHTML = "Reset Grid";
document.body.appendChild(resetButton);
function makeRows(_canvasSize) {
const rows = canvasSize
const cols = canvasSize
container.style.setProperty('--grid-rows', rows);
container.style.setProperty('--grid-cols', cols);
for (c = 0; c < (rows * cols); c++) {
let cell = document.createElement("div");
container.appendChild(cell).className = "grid-item";
cell.addEventListener('mouseover',
e => e.target.style.backgroundColor = "black"
)
};
};
resetButton.addEventListener('click', (e) => {
reset();
});
var list= document.getElementsByClassName("events");
function reset() {
container.classList.remove("grid-item");
makeRows(canvasSize)
}
makeRows(canvasSize);
You can use querySelectorAll() to find all elements with the class "grid-item" and then for each of them find their parent node use removeChild() to remove the element, something like:
function reset() {
document
.querySelectorAll(".grid-item")
.forEach((e) => e.parentNode.removeChild(e));
}
const container = document.getElementById("container");
let canvasSize = Number(
prompt("Enter amount of squares per side to make the new grid")
);
let resetButton = document.createElement("button");
resetButton.innerHTML = "Reset Grid";
document.body.appendChild(resetButton);
function makeRows(_canvasSize) {
const rows = canvasSize;
const cols = canvasSize;
container.style.setProperty("--grid-rows", rows);
container.style.setProperty("--grid-cols", cols);
for (let c = 0; c < rows * cols; c++) {
let cell = document.createElement("div");
container.appendChild(cell).className = "grid-item";
cell.addEventListener(
"mouseover",
(e) => (e.target.style.backgroundColor = "black")
);
}
}
resetButton.addEventListener("click", (e) => {
reset();
});
var list = document.getElementsByClassName("events");
function reset() {
document
.querySelectorAll(".grid-item")
.forEach((e) => e.parentNode.removeChild(e));
}
makeRows(canvasSize);
.grid-item {
border: 1px solid black;
width: 10px;
padding: 10px;
margin: 5px
}
<div id="container"></div>
I want to make a program changing background color of a div after clicking on a button.
After first click it should change one color to the second one. After second click the color should come back to the first option. And for the last time, the color should be switched again to the second option. So it should work for 3 times. But in my code it works just for the first click.
What did I do wrong?
var btn = document.getElementById('button');
var box = document.getElementById('sq');
function changeColor() {
var isPink = true;
var colorA = "#BA498B";
var colorB = "#5964E3";
var i = 0;
while (i < 3) {
if (isPink) {
change(colorB);
isPink = false;
i++;
} else {
change(colorA);
isPink = true;
i++;
}
}
}
function change(color) {
btn.addEventListener('click', function () {
box.style.backgroundColor = color;
});
}
window.onload = changeColor;
You're adding a new, identical event handler every time there's a click. Instead just add it once when the page loads, so that the redundant handlers don't cancel each other out.
var isPink = true;
function changeColor() {
var colorA = "#BA498B";
var colorB = "#5964E3";
if (isPink) {
change(colorB);
} else {
change(colorA);
}
isPink = !isPink;
}
function change(color) {
document.getElementById('sq').style.backgroundColor = color;
}
window.onload = function() {
document.getElementById('button').addEventListener('click', changeColor);
};
#sq {
width: 100px;
height: 100px;
position: relative;
}
<button id=button>CLICK</button>
<div id=sq></div>
Don't know what you wanted with the loop though, so I removed it. It runs immediately, and so you'd never see such a rapid color change.
try this:
var isPink = true;
var color = "#BA498B"
function changeColor() {
var colorA = "#BA498B";
var colorB = "#5964E3";
if (isPink) {
color = (colorB);
isPink = false;
} else {
color = (colorA);
isPink = true;
}
}
window.onload = function(){
var btn = document.getElementById('button');
var box = document.getElementById('sq');
btn.addEventListener('click', function () {
changeColor();
box.style.backgroundColor = color;
});
};
This way I'm only using 'addEventListener' on the button once
Here is an example which may help you:
var btn = document.getElementById('button');
var box = document.getElementById('sq');
var isPink = true;
function changeColor() {
var colorA = "#BA498B";
var colorB = "#5964E3";
var color=isPink?colorA:colorB;
isPink=isPink?false:true;
return color;
}
function change() {
box.style.backgroundColor = changeColor();
}
btn.addEventListener('click', change);
window.onload = change();
<h1 id="sq">Test Text for Example</h1>
<button id="button">Click</button>
I have a function which dynamically adds div, what i need is a button inside, which deletes this div. Eg: on click of a button, a div is added, with a button inside. On click of that button, the div is removed. Here's my code for addition of divs:
function newTextQuestion() {
var div = document.createElement('div');
div.style.borderLeft = "3px solid #00897b";
div.style.marginBottom = "20px";
div.style.paddingLeft = "10px";
div.style.backgroundColor = "white";
div.className = 'q';
div.setAttribute('data-type', '0');
var name = "random-" + parseInt(Math.random() * 1000000000);
div.innerHTML = '<h5>Tekstiküsimus:</h5><input class="text" name="' + name + '" type="text" placeholder="Küsimuse tekst..." oninvalid="this.setCustomValidity(\'\See väli on kohustuslik!\'\)" oninput="setCustomValidity(\'\'\)" required>';
document.getElementById('questionnaireDiv').appendChild(div);
}
--- EDIT ---
What i've tried so far:
function newTextQuestion() {
var div = document.createElement('div');
div.style.borderLeft = "3px solid #00897b";
div.style.marginBottom = "20px";
div.style.paddingLeft = "10px";
div.style.backgroundColor = "white";
var delbutton = document.createElement('button');
var delbuttontext = document.createElement('X');
delbutton.appendChild(delbuttontext);
delbutton.setAttribute("onclick", function() { $(this).parent().remove(); });
div.appendChild(delbutton);
div.className = 'q';
div.setAttribute('data-type', '0');
var name = "random-" + parseInt(Math.random() * 1000000000);
div.innerHTML = '<h5>Tekstiküsimus:</h5><input class="text" name="' + name + '" type="text" placeholder="Küsimuse tekst..." oninvalid="this.setCustomValidity(\'\See väli on kohustuslik!\'\)" oninput="setCustomValidity(\'\'\)" required>';
document.getElementById('questionnaireDiv').appendChild(div);
}
When you need event handling capabilities, don't create an element via .innerHTML, use the document.createElement() technique. To create the button, just follow the same technique that you had already started.
Also, it's best to work with CSS classes when you can instead of setting individual properties.
var parent = document.getElementById('questionnaireDiv');
function newTextQuestion() {
var div = document.createElement('div');
div.classList.add("newDiv");
div.classList.add("q");
div.setAttribute('data-type', '0');
var name = "random-" + parseInt(Math.random() * 1000000000);
var h5 = document.createElement("h5");
var input = document.createElement("input");
input.type = "text";
input.classList.add("text");
input.placeholder = "Küsimuse tekst...";
input.required = true;
input.addEventListener("invalid", function(){
this.setCustomValidity("\'See väli on kohustuslik!\'");
});
input.addEventListener("input", function(){
this.setCustomValidity("");
});
var btn = document.createElement("button");
btn.textContent = "Delete";
div.appendChild(h5);
div.appendChild(input);
div.appendChild(btn);
btn.addEventListener("click", function(){
parent.removeChild(div);
});
parent.appendChild(div);
}
newTextQuestion();
.newDiv {
border-left: 3px solid #00897b;
margin-bottom: 20px;
padding-left: 10px;
background-color:"white";
}
<div id="questionnaireDiv"></div>
I have the following code:
window.onload = function createDivs() {
for(var i = 1;i<29;i++) {
var div = document.createElement("div");
var body = document.getElementsByTagName("body")[0];
var n1 = document.createTextNode("Cell " + i);
var n2 = document.createTextNode(i + " Cell");
div.style.width = "100px";
div.style.height = "100px";
div.style.border = "1px solid red";
div.style.cssFloat = "left";
div.style.margin = "1px"
div.className = i;
body.appendChild(div);
}
div.onmouseover = function() {
this.appendChild(n1);
},
div.onmouseout = function() {
this.appendChild(n2);
}
}
what I want to acheive
on mouseover of each div, the div should have a text of cell 1, cell 2, ..... upto cel 28. But I am just getting Cell 28 on hover for each cell.
2. I also want to achieve that onmouseout, the cell should have "1 cell" as text, but its not working.
Any help is appreciated.
http://jsbin.com/iXuLEDE/7/edit?html,output
Your problem is coming from your closure over n1 and n2. The simplest solution to that is the following.
From this:
div.onmouseover = function() {
this.appendChild(n1);
}
To this:
div.onmouseover = (function(text) {
return function () {
this.innerHTML = text;
}
}(n1.textContent));
This way you are using a copy of the text node (by using it as a parameter to a function) rather than as a closure later on.
UPDATE
Just read the second part of your question, this should work:
div.onmouseover = (function(text) {
return function() {
this.innerHTML = text;
};
}("Cell " + i));
div.onmouseout = (function(text) {
return function() {
this.innerHTML = text;
};
}(i + " Cell"));
USING TEXT NODES
function createDivs() {
for(var i = 1;i<29;i++) {
var div = document.createElement("div");
var body = document.getElementsByTagName("body")[0];
div.style.width = "100px";
div.style.height = "100px";
div.style.border = "1px solid red";
div.style.cssFloat = "left";
div.style.margin = "1px"
div.className = i;
var n1 = document.createTextNode("Cell " + i);
var n2 = document.createTextNode(i + " Cell");
body.appendChild(div);
div.onmouseover = (function(n_text1, n_text2) {
return function() {
if (n_text2.parentNode == this) {
this.removeChild(n_text2);
}
this.appendChild(n_text1);
};
}(n1, n2));
div.onmouseout = (function(n_text1, n_text2) {
return function() {
if (n_text1.parentNode == this) {
this.removeChild(n_text1);
}
this.appendChild(n_text2);
};
}(n1, n2));
}
}
Fiddle here: http://jsfiddle.net/Mk5e5/
Please change the code like this
window.onload = function createDivs() {
for(var i = 1;i<29;i++) {
var div = document.createElement("div");
div.setAttribute("index", i);
var body = document.getElementsByTagName("body")[0];
div.style.width = "100px";
div.style.height = "100px";
div.style.border = "1px solid red";
div.style.cssFloat = "left";
div.style.margin = "1px"
div.className = i;
body.appendChild(div);
div.onmouseover = function() {
var n1 = document.createTextNode("Cell " + this.getAttribute("index"));
this.appendChild(n1);
} ,
div.onmouseout = function() {
var n2 = document.createTextNode(this.getAttribute("index") + " Cell");
this.appendChild(n2);
}
}
}
You should add event for each div in loop
Try to understand javascript closures, specially inside for loops. Check this excellent explanation in this blog post: http://www.mennovanslooten.nl/blog/post/62
Change your createDivs function to:
function createDivs() {
for(var i = 1;i<29;i++) {
var div = document.createElement("div");
var body = document.getElementsByTagName("body")[0];
div.style.width = "100px";
div.style.height = "100px";
div.style.border = "1px solid red";
div.style.cssFloat = "left";
div.style.margin = "1px"
div.className = i;
body.appendChild(div);
div.onmouseover = (function(value) {
return function() {
var n1 = document.createTextNode("Cell " + value);
this.appendChild(n1);
}
})(i);
div.onmouseout = (function(value) {
return function() {
var n2 = document.createTextNode(value + " Cell");
this.appendChild(n2);
}
})(i);
};
};
Your code doesn't work because when your onmouseover and onmouseout functions are executed, the value of your text variables is "cell 28." Also, your child removal was a little off, if I interpret your intentions correctly.
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title>JS Bin</title>
</head>
<body>
<script type="text/javascript">
function createDivs(n) {
for(var i = 1; i <= n; i++) {
var div = document.createElement("div");
var body = document.getElementsByTagName("body")[0];
div.style.width = "100px";
div.style.height = "100px";
div.style.border = "1px solid red";
div.style.cssFloat = "left";
div.style.margin = "1px"
div.className = i;
body.appendChild(div);
div.onmouseover = function() {
if (this.childNodes.length > 0) this.removeChild(this.childNodes[0]);
var n_text = document.createTextNode("Cell " + this.className);
this.appendChild(n_text);
},
div.onmouseout = function() {
if (this.childNodes.length > 0) this.removeChild(this.childNodes[0]);
var n_text = document.createTextNode(this.className + " Cell");
this.appendChild(n_text);
}
}
}
createDivs(28)
</script>
</body>
</html>
I also changed your if statement so you pass the number of cells you want instead of the number of cells +1.