How to remove divs inside a grid? - javascript

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>

Related

Page slows browser down when input is high

I am building an etch-a-sketch browser version for the odin project.
There is a prompt message that asks input from the user and creates a grid based on the input.
If the input is 15 that should give a 15x15 grid.
Unfortunately the higher the input the more time it takes for the page to load. Any ideas why?
const container = document.querySelector('#container');
const btn = document.querySelector('#btn');
/*
btn.addEventListener('click', () => {
squares.forEach(square => {
square.style.backgroundColor = 'white';
});
});
*/
btn.addEventListener('click', () => addGrid());
function addGrid() {
let content = document.createElement('div');
let input = prompt("Please enter the number of squares per side (2 - 100)");
while ((input == null || input > 100 || input < 2 || isNaN(input))) {
input = prompt("Please enter the number of squares per side (2 - 100)");
}
for (let i = 0; i <= input * input; i++) {
container.style.cssText = 'grid-template-rows: repeat(' + input + ' , 1fr); grid-template-columns: repeat(' + input + ', 1fr)';
content = document.createElement('div');
content.classList.add('square');
container.appendChild(content);
squares = container.querySelectorAll('.square')
squares.forEach(square => {
square.addEventListener('mouseenter', () => {
square.style.backgroundColor = 'black';
});
});
squares.forEach(square => {
square.addEventListener('mouseleave', () => {
square.style.backgroundColor = 'black';
});
});
}
return content;
}
<button id="btn">Click</button>
<div id="container"></div>
You need to move the event handlers outside the loop.
Also you need to use < instead of <= in the loop
Even better, delegate from container
Here is a working version - you could use calc() in the css to size the individual squares
Using delegated event handling
const container = document.getElementById('container');
const btn = document.getElementById('btn');
const reset = document.getElementById('reset');
const mclick = e => {
const tgt = e.target;
if (tgt.matches(".square")) tgt.classList.toggle("clicked");
}
const mhover = e => {
const tgt = e.target;
if (!tgt.matches(".square")) return; // not a square
tgt.classList.toggle("active",e.type==="mouseover")
}
const resetGrid = () => container.querySelectorAll(".square")
.forEach(sq => {
["clicked","active"]
.forEach(cls => sq.classList.remove(cls))
});
const addGrid = () => {
let content = document.createElement('div');
let input = prompt("Please enter the number of squares per side (2 - 100)");
while ((input == null || input > 100 || input < 2 || isNaN(input))) {
input = prompt("Please enter the number of squares per side (2 - 100)");
}
for (let i = 0; i < input * input; i++) {
container.style.cssText = 'grid-template-rows: repeat(' + input + ' , 1fr); grid-template-columns: repeat(' + input + ', 1fr)';
let content = document.createElement('div');
content.classList.add('square');
content.textContent = i
container.appendChild(content);
}
};
btn.addEventListener('click',addGrid);
container.addEventListener("mouseover",mhover);
container.addEventListener("mouseout",mhover);
container.addEventListener("click",mclick);
reset.addEventListener("click",resetGrid);
#container { display:grid; }
div.square { height: 50px; width: 50px; border:1px solid black;}
div.square.active { background-color: black;}
div.square.clicked { background-color: red;}
<button id="btn">Start</button><button id="reset">Reset</button>
<div id="container"></div>

How to make onclick select the div square the image is on not the image itself

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";

e.target removing wrong button?

So my code should remove the text and button that have the same data-index but right now it's only deleting the div with the correct data-index
I tried to do e.target.remove();
but that removes the latest button and not the one that was pressed
let div;
let k = 0;
let o = 0;
function addBookToLibrary(bookToAdd) {
myLibrary.push(bookToAdd);
div = document.createElement("div");
div.textContent = Object.values(bookToAdd);
div.dataset.index = k;
k++;
main.appendChild(div);
const remove = document.createElement("button");
remove.textContent = "remove";
remove.dataset.index = o;
o++;
main.appendChild(remove);
remove.addEventListener("click", (e) => {
let dataIndex = e.target.dataset.index;
let element = document.querySelector(`div[data-index="${dataIndex}"]`);
element.remove();
myLibrary.splice(dataIndex, 1);
})
}

Style all Elements of a div created via .createElement('div')

So I'm creating multiple new child divs inside another parent div with this code:
var parentDiv = document.querySelector('.parent-div')
const newDiv = document.createElement('div');
parentDiv.appendChild(newDiv);
So now I want to add an onlick event for every div I created, that resets the color for every other div inside the parent div, so that no multiple child divs are selected, and then set the color only for the clicked div to another color!
Any ideas?
var parentDiv = document.querySelector('.parent-div');
for (let i = 0; i < 10; ++i) {
const newDiv = document.createElement('div');
newDiv.className = "my-class";
newDiv.innerText = `Foo${i}`;
parentDiv.appendChild(newDiv);
}
parentDiv.onclick = (event) => {
document.querySelectorAll('.my-class').forEach((el) => {
el.className = "my-class";
});
event.target.className += " active";
}
.my-class {
color: red;
}
.active {
color: blue;
}
<div class="parent-div"></div>
let parentDiv = document.querySelector('.parent-div');
for (let x = 0; x < 10; x++) {
let newDiv = document.createElement('div');
newDiv.classList.add('see')
parentDiv.appendChild(newDiv);
}
parentDiv.addEventListener('click', (e) => {
if (e.target.tagName === 'DIV') {
e.target.style.backgroundColor = 'red';
}
})
Just to suggest a more robust and flexible way:
// Utility functions
const EL = (sel, EL) => (EL||document).querySelector(sel);
const ELS = (sel, EL) => (EL||document).querySelectorAll(sel);
const ELNew = (tag, prop) => Object.assign(document.createElement(tag), prop);
// Now...
// Get element (Use an ID, not a class)
const EL_parent = EL('#parent');
// Function to toggle "is-active" class
const toggleActive = (EL_target, EL_parent) => {
const EL_active = EL(".is-active", EL_parent);
if (EL_active) EL_active.classList.remove("is-active");
EL_target.classList.add("is-active");
};
// Function to create new child elements
const newChild = (content) => ELNew("div", {
className: "child",
innerHTML: content,
onclick() {
toggleActive(this, EL_parent);
}
});
// Create a couple of elements....
EL_parent.append(
newChild("1 Lorem"),
newChild("2 Ipsum"),
newChild("3 Dolor"),
);
.is-active {
background: gold;
}
<div id="parent"></div>
So just a better way, and to avoid sloppy code like className = or Event.target without the use of .closest(), as shown in the other answers.
I'm not sure if this is how you would want to do it for many reasons, but it might be beneficial for you to change the HTML value of the parent div. For example,
var parentDiv = document.querySelector('.parent-div')
parentDiv.innerHTML = parentDiv.innerHTML + "<div class='{class name}'></div>";
The approach proposed here is aware of which div was clicked the last time, changes its style accordingly and creates the onclick when the item is created.
var parentDiv = document.querySelector('.parent-div');
let lastDiv = undefined;
for (let i = 0; i < 10; i++) {
let newDiv = document.createElement('div');
newDiv.style.width = "100px";
newDiv.style.height = "100px";
newDiv.style.backgroundColor = "black";
newDiv.style.border = "1px solid white";
newDiv.onclick = function() {
if (lastDiv) lastDiv.style.backgroundColor = "black";
newDiv.style.backgroundColor = "green";
lastDiv = newDiv;
};
parentDiv.appendChild(newDiv);
}
<div class="parent-div"></div>

Trying to return .nextSibling div value

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;
}

Categories