Javascript: cannot access "style" property for div elements in array - javascript

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

Related

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 can I implement click-and-hold drawing with plain JavaScript

I'm making a pixel art maker, and I can color individual divs in my grid; however, I want the user to be able to click, hold, and drag to continually draw. There've been similar questions to mine, but they seemed to need jQuery or not exactly apply to me.
https://jsfiddle.net/8okf4yg0/2/
//create cell listeners
function listenCells() {
let cell = document.querySelectorAll('.grid-square');
cell.forEach((cell) => {
cell.addEventListener('mouseenter', function() {
cell.style.backgroundColor = color;
});
});
}
is there someway to combine mouseenter and mousedown? Or is there a better solution?
Add mousedown and mouseup listeners to the parent container and have them toggle a flag variable.
Then check that flag before changing the cells.
Simple demo using a table
/* Flag to know if mosue is down on table */
let MDOWN = false;
const tbl = document.querySelector('table')
createRows();
['mousedown', 'mouseup'].forEach(eName => tbl.addEventListener(eName, () => MDOWN = !MDOWN));
function cellEnter() {
if (MDOWN) {
this.style.backgroundColor = 'black';
}
}
function createRows() {
for (let i = 0; i < 50; i++) {
const row = tbl.insertRow()
for (let j = 0; j < 50; j++) {
let cell = row.insertCell();
cell.addEventListener('mouseenter', cellEnter)
}
}
}
td {
height: 10px;
width: 10px;
border: 1px solid #ccc
}
table {
border-collapse: collapse;
}
<table>
</table>

Add a class iteratively with javascript

I'm creating a grid 16x16 with javascript. I also want the grid to do something when the mouse hover over each square. The problem is that I do not know how to add a class in a iterative way that every div get the same class.
Doing so, I would make jQuery do the action with one function applied to that class.
This is my present code
var contador = 1;
var outra = document.createElement('div');
outra.id = 'container';
document.body.appendChild(outra);
for (i=1;i<=16;i++){
for (j=1;j<=16;j++){
var divCreation = document.createElement('div');
var created = divCreation;
created.id = "numero"+ contador;
console.log(created.id);
created.textContent = ". ";
contador = contador + 1;
outra.appendChild(created);
}
}
$('#numero'+contador).hover(function(){
$(this).css('background-color','yellow');
});
If you want to give a specific class to your dynamically created elements, you can do it using className property.
Your code would be like this:
divCreation.className = "someClass";
Note:
I don't see why you are setting divCreation in a new variable, it's
just useless.
And instead of detecting hover with jQuery, you can just do it with css, look at my Demo below, or if you want to keep jquery you can use the class selector like this $('.box').hover(...).
Demo:
var outra = document.createElement('div');
outra.id = 'container';
var contador = 1;
document.body.appendChild(outra);
for (i = 1; i <= 16; i++) {
for (j = 1; j <= 16; j++) {
var created = document.createElement('div');
created.className = "box";
created.id = "numero" + contador;
created.textContent = ". ";
contador++;
outra.appendChild(created);
}
}
.box:hover {
background-color: yellow;
}
No need for use of ID for this at all...just use a common class. Also since using jQuery can create all this with a lot less code using by using it.
var $outra = $('<div>', { id: 'container'});
for (i = 1; i <= 16; i++) {
for (j = 1; j <= 16; j++) {
$outra.append( $('<div>', { class: 'box', text: '.'}) );
}
}
$('body').append($outra);
$('.box').hover(function() {
$(this).toggleClass('yellow');
});
.box {
width: 50px;
height: 50px;
display: inline-block;
border: 1px solid #ccc
}
.box.yellow {
background-color: yellow
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
You can use the attribute starts with selector
$('[id^=numero').hover(
or provide a class to the element and target the elements using the class
This will select all the elements whose id starts with the value you are specifying and attach a hover event.
And when you are using jQuery, why do you want to mix in both Vanilla JS and jQuery. You can just stick with one.
var contador = 1;
var $outra = $('<div/>', {
id: 'container',
class: 'container'
});
$('body').append($outra);
for (i=1;i<=16;i++){
for (j=1;j<=16;j++) {
var $divCreation = $('<div/>', {
id: 'numero' + contador,
text: '. ',
class: 'box'
});
$outra.append($divCreation);
contador = contador + 1;
}
}
$('[id^=numero').hover(function(){
$(this).css('background-color','yellow');
});
.container {
width: 200px;
height: 200px;
border: 1px solid green;
}
.box {
width: 20px;
height: 20px;
border: 1px solid black;
background: green;
float: left;
cursor: pointer;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

Using JavaScript to create and append nested div elements

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

JavaScript: creating an array of text boxes

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

Categories