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>
Related
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>
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 would like to have an 8x8 matrix where I can click on each square and the color will change, for use in a project.
I have made a 2d array and the entire 8x8 "board" but now I want to change to color on click, although the only way I can think of is through heavy code, for example writing div[row][column] 64 times...
var div = new Array(8);
for(var i = 0; i<8; i++){
div[i] = new Array(8)
}
for (var i = 0; i < 8; i++) {
for (var j = 0; j < 8; j++) {
div[i][j] = document.createElement("div");
div[i][j].style.width = "50px";
div[i][j].style.height = "50px";
div[i][j].style.backgroundColor = "white";
document.getElementById("container").appendChild(div[i][j]);
}
var jump = document.createElement("br");
document.getElementById("container").appendChild(jump);
}
div[0][0].onclick = function(){
if(div[0][0].style.backgroundColor == "white"){
div[0][0].style.backgroundColor = "red"
d00 = 1
}
else{div[0][0].style.backgroundColor = "white"
d00 = 0
}
}
I don't wish to write the above 64 times, surely there must be a better way.
#container {
margin: auto;
width:400px;
height:400px;
}
#container div {
display:inline-block;
vertical-align:top;
outline: 1px solid black
}
You can attach the onclick event to the parent container and use event.target to get the div which triggered the event:
document.getElementById("container").onclick = function(event){
if(event.target.style.backgroundColor == "white"){
event.target.style.backgroundColor = "red";
}
else{
event.target.style.backgroundColor = "white";
}
}
Indeed, there is a better way.
Inside the for-loop you're already setting important properties of your DIVs. It's the perfect place to attach an click eventListener whose callback function will handle the color switching.
Modify the for-loop like this:
var divElement;
for (var i = 0; i < 8; i++) {
for (var j = 0; j < 8; j++) {
divElement = document.createElement("div");
divElement.style.width = "50px";
divElement.style.height = "50px";
divElement.style.backgroundColor = "white";
divElement.addEventListener("click", changeColor);
document.getElementById("container").appendChild(divElement);
}
and use this function to actually change the color:
function changeColor(e) {
if (e.target.style.backgroundColor == "white") {
e.target.style.backgroundColor = "red"
d00 = 1
} else {
e.target.style.backgroundColor = "white"
d00 = 0
}
}
e.target refers to the object that triggered the event.
Forgive me, I don't know the purpose of d00.
I’m creating a music player, and I ran into a problem with a for loop and an array. I have the following function in my main.js file
function CreateDatabaseArtists() {
for (n = 0; n < DatabaseArtists.length+1; n++) {
if (DatabaseArtists[n.toString()].name === "") {} else {
let NewArtistBtn = document.createElement("div");
NewArtistBtn.id = DatabaseArtists[n].artistgroup;
// NewArtistBtn.onclick = function() {OpenArtist(NewArtistBtn.id);};
NewArtistBtn.classList.toggle("column");
NewArtistBtn.setAttribute("style", "word-wrap: break-word; float: none; width: 150px; text-align:center;align-items:center; display: inline-block; white-space: nowrap; overflow: hidden; text-overflow:ellipsis;");
let ArtistIMG = document.createElement("img");
if (DatabaseArtists[n].ArtistArt == "") {
ArtistIMG.src = "https://iplock.weebly.com/uploads/9/5/7/3/95731436/p298.png";
ArtistIMG.style.borderRadius = "50%";
} else {
ArtistIMG.src = DatabaseArtists[n].ArtistArt;
ArtistIMG.style.borderRadius = "50%";
}
ArtistIMG.style.width = "150px"; ArtistIMG.style.height = "150px";
NewArtistBtn.appendChild(ArtistIMG);
let text = document.createElement("p");
text.innerHTML = "ahhh-humbug";
// DatabaseArtists[b].name;
ArtistIMG.setAttribute("aria-label", text.innerHTML);
NewArtistBtn.appendChild(text);
document.getElementById("artists").appendChild(NewArtistBtn);
}
}
}
And the part with
for (n = 0; n < DatabaseArtists.length+1; n++) {
if (DatabaseArtists[n.toString()].name === "") {}
Keeps failing, I get an error message saying that it cant find the variable for “name” even though in the array it is "name": "AJR", "explicit": false, "artistgroup": "ajr", "ArtistArt": ""
What am i supposed to do?
for (n = 0; n < DatabaseArtists.length+1; n++)
You are iterating past the end of the array, so the last loop will try to access the name property on undefined. The index should go from 0 to length - 1.
Honest bit of advice, why don't you break up the application, it's just easier to maintain that way. Also if you use a forEach method, you don't have to worry about index to the same extent as you would if you used a tradtitional for loop.
const defaultStyle = "word-wrap: break-word; float: " +
"none; width: 150px; text-align:center;align-items:center; " +
"display: inline-block; white-space: nowrap; " +
"overflow: hidden; text-overflow:ellipsis;";
const defaultImg = 'https://iplock.weebly.com/uploads/9/5/7/3/95731436/p298.png';
const appRoot = document.getElementById("artists");
const createImage = artist => {
const img = document.createElement("img");
const source = artist.ArtistArt === '' ? defaultImg : artist.ArtistArt;
img.src = source;
img.style.borderRadius = "50%";
img.style.width = "150px";
img.style.height = "150px";
return img;
};
const createButton = artist => {
const btn = document.createElement("div");
const img = createImage(artist);
const ptag = document.createElement("p");
ptag.innerHTML = "ahhh-humbug";
btn.id = artist.artistgroup;
btn.classList.toggle("column");
btn.setAttribute("style", defaultStyle);
btn.appendChild(img);
btn.appendChild(ptag);
return btn;
};
const createDatabaseArtists = () => {
databaseArtists.forEach(artist => {
if (artist.name !== '') {
appRoot.appendChild(createButton(artist));
}
});
};
I want to create div continuously and it should come on the next line if it reaches the outer div's width in JavaScript without using canvas and float.
for(i = 0; i < 20; i++) {
var ind = (Math.round(Math.random(0,2)*2));
var child = document.createElement("div");
child.setAttribute("id","div"+i);
child.style.backgroundColor=colors[ind];
maindiv.appendChild(child);
}
You can use display: inline-block; css property. Refer this
var maindiv = document.getElementById('parent');
for (var i = 0; i < 100; i++) {
var ind = (Math.round(Math.random(0, 2) * 2));
var child = document.createElement("div");
child.setAttribute("id", "div" + i);
child.setAttribute("class", "inline");
child.innerText = 'div';
//child.style.backgroundColor = colors[ind];
maindiv.appendChild(child);
}
.inline {
display: inline-block;
}
<div id="parent"></div>