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

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>

Related

How to change value of parent element to an element

I am trying to change the css property of the "node"-class by clicking on the div inside of it which got the class "expand".
When I click on the "expand" div inside the "note", I want to go to parent "note" for changing it size:
var text = document.getElementById("text");
var add = document.getElementById("add");
var notespace = document.getElementById("notespace");
var expand = document.getElementsByClassName("expand");
var notes = document.getElementsByClassName("note");
add.addEventListener("click", function () {
var textValue = text.value;
var p = document.createElement("p");
p.innerHTML = "<div class='note'>" + textValue +
"<br/><br/><div class='expand'> Expand </div></div>";
notespace.appendChild(p);
text.value = "";
for (var i = 0; i < expand.length; i++) {
expand[i].addEventListener("click", function () {
notes[i].style.size = "3000px";
})
}
})
You have to re-get the values of expand and notes, because after you add them to your html, the two variables expand and notes, dont know yet that you have added them and they don't contain them. ( you also have to removee the eventlistner otherwise you're gonna get a bugg at approximately twelve notes added :D because you will have too many eventListners on each element
var text = document.getElementById("text");
var add = document.getElementById("add");
var notespace = document.getElementById("notespace");
var expand = document.getElementsByClassName("expand");
var notes = document.getElementsByClassName("note");
add.addEventListener("click", function(){
var textValue = text.value;
var p = document.createElement("p");
p.innerHTML = "<div class='note'>" + textValue + "<br/><br/><div class='expand'> Expand </div></div>";
notespace.appendChild(p);
text.value = "";
for( var i = 0; i < expand.length; i++){
const note = notes[i];
expand[i].addEventListener("click", function() {
note.style.size = "3000px";
note.style.backgroundColor = "red";
});
}
})
#notespace {
width: 100%,
height: 100%,
background: grey,
}
<button type="button" id="add">add</button>
<input id="text"/>
<div id="notespace">
</div>
You can use the parentNode attribute :
for( var i = 0; i < expand.length; i++){
expand[i].addEventListener("click", function(){
this.parentNode.style.size = "3000px";
})
}
Or the closest() method :
for( var i = 0; i < expand.length; i++){
expand[i].addEventListener("click", function(){
this.closest(".note").style.size = "3000px";
})
}
Note that closest() is not supported on IE.

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

declaring variables in a foreach method javascript

Im pretty new to programming and im trying to develop a chrome extension. The website that im trying to manipulate has a div element and within this div are multiple divs and the number of these divs vary depending on the scale of the first div and the scale is draggable by the user. My problem is that, I need to declare each of these variables and have a mutation observer observe them for changes. So if a user has 8 div in there, each div should be declared as a variable and have a mutation observer observing it. Below is my code:
function tester() {
var child = document.querySelector("#__APP > div > div:nth-child(3) > div > div > div.react-grid-layout.layout > div:nth-child(5) > div > div.css-q57e4p > div > div > div.list-container.css-1kq4s3b > div.list-auto-sizer > div > div");
var childnodesofchild = [child.childNodes];
var divs = [];
console.log(childnodesofchild[0]);
childnodesofchild[0].forEach(consoler);
function consoler() {
//this is the problem
span1 = document.getElementsByClassName("text right")[0];
const observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
var spantext = span1.textContent;
var spandiv = span1.parentNode;
if (mutation.addedNodes) {
if (spantext > avg) {
spandiv.style.backgroundColor = "#E8E8E8"
spandiv.style.color = "black";
spandiv.style.opacity = "0.7";
}
if (spantext < avg) {
spandiv.style.backgroundColor = "black";
spandiv.style.color = "white";
spandiv.style.opacity = "1";
}
}
})
});
const options = {
childList: true,
subtree: true,
attributes: true,
characterData: true
};
observer.observe(span1, options);
}
}
I am still not 100% sure what your question is. But here, I wrote a quick example of how you can declare a few divs in a loop and mess with its properties in a loop. I hope this is helpful.
let colors = ['red','green','blue'];
let innerText = ['A','B','C'];
for (let i = 0; i < colors.length; i++) {
let testDiv = document.createElement('div');
testDiv.className = 'test';
testDiv.style = 'width: 100px; height: 50px; line-height: 50px; text-align: center; color: white;';
testDiv.style.backgroundColor = colors[i];
testDiv.innerHTML = innerText[i];
document.body.appendChild(testDiv);
}
document.getElementById('testBtn').onclick = function() {
let testDivs = document.querySelectorAll('.test');
for (let i = 0; i < testDivs.length; i++) {
testDivs[i].style.backgroundColor = colors[Math.floor(Math.random() * colors.length)];
}
}
<button id="testBtn">Change Div Colors</button>

How to remove divs inside a grid?

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>

.addEventListener - long list

I found few answer on my issue but probably I'm not so experienced to processes it to my case.
I have list of items generated to .html
<div id="grid">
by JavaScript
var div_block = "";
for (i = 0; i < 70; i++) {
div_block = div_block + '<div id="c' + i + '" class="card"></div>';
}
document.getElementById("grid").innerHTML = div_block;
for (i = 0; i < 70; i++) {
'var c' + i + ' = document.getElementById(c' + i + ');'
}
and it works fine.
I want to chose .addEventListner method to chose proper element but for 70 and more elements code:
c0.addEventListener("click", function () {revealCard(0);});
c1.addEventListener("click", function () {revealCard(1);});
...
cn.addEventListener("click", function () {revealCard(n);});
is huge and not elegant. Method I've tried didn't work
for (i = 0; i < 70; i++) {
'c'+i+'.addEventListener("click", function() { revealCard('+i+'); });'
}
How to build working addEventListener() for this?
Thanks a lot.
The problem you are facing can be solved by using the card class that you add on each of your card. Then, to refer to the right card, you can use the keyword this, which in the context of an addEventListener will refer to whichever DOM element received the click. You also won't need to generate a unique Id for each one of your div, which I think is a big plus.
Your code would look like this:
let div_block = "";
for (i = 0; i < 70; i++) {
div_block = div_block + '<div class="card"></div>';
}
const cards = querySelectorAll(".card");
cards.forEach(card => {
card.addEventListener("click", revealCard)
})
function revealCard(){
// Here, `this` refers to the card that was clicked
// So you can do what you want with it
console.log(this);
}
Slight modification to brk's answer, using a single event listener on the parent that will trigger for the events on the children
var div_block = "";
for (let i = 0; i < 5; i++) {
div_block += `<div data-attr="${i}" id="c${i}" class="card">Hello</div>`;
}
var grid = document.getElementById("grid");
grid.innerHTML = div_block;
grid.addEventListener('click', function (e) {
if (e.target.getAttribute('class') === 'card') {
revealCard(e.target.dataset.attr);
}
});
function revealCard(num) {
console.log(num)
}
<div id='grid'></div>
You can use dataset, that is while creating the dom add a dataset property.
Then use querySelectorAll to get all the div with class card and iterate over it to add event using addEventListener. On click of the element get the dataset value and pass to revealCard function
var div_block = "";
for (let i = 0; i < 5; i++) {
div_block += `<div data-attr="${i}" id="c${i}" class="card">Hello</div>`;
}
document.getElementById("grid").innerHTML = div_block;
document.querySelectorAll('.card').forEach(function(item) {
item.addEventListener('click', function(e) {
revealCard(item.dataset.attr)
})
})
function revealCard(num) {
console.log(num)
}
<div id='grid'></div>
There are multiple ways to do this, but I wouldn't use IDs and I wouldn't bind X event listeners. I would use event delegation and data-* attributes:
Build your list of elements:
const grid = document.getElementById("grid");
for (var i = 0; i < 70; i++) {
const child = document.createElement('div');
child.className = 'card';
child.dataset.index = i;
grid.appendChild(child);
}
Add an event listener to the grid element:
grid.addEventListener('click', function(event) {
let target = event.target;
// traverse up if clicked inside element
while (target.className !== 'card') {
target = target.parentNode;
}
if (target) {
revealCard(target.dataset.index);
}
});
const grid = document.getElementById("grid");
for (var i = 0; i < 70; i++) {
const child = document.createElement('div');
child.className = 'card';
child.dataset.index = i;
child.innerText = `Card ${i}`;
grid.appendChild(child);
}
grid.addEventListener('click', function(event) {
let target = event.target;
// traverse up if clicked inside element
while (target.className !== 'card') {
target = target.parentNode;
}
if (target) {
revealCard(target.dataset.index);
}
});
function revealCard(i) {
console.log(`Card ${i} revealed`);
}
<div id="grid"></div>
I found probably the easiest (shortest) solution:
for(var i=0;i<boardSize;i++){
document.getElementById('c'+i).addEventListener("click",function(){
revealCard(this.id.substring(1));
});
}
What do you thing?

Categories