This question already has answers here:
Align inline-block DIVs to top of container element
(5 answers)
CSS inline-block wrap issue with mixed text and empty div
(2 answers)
Closed 4 years ago.
Jsfiddle showing the issue: Fiddle
I have a few divs and inside they hold other divs (both created from js),
and an Event handler that shows text ('innerText') when clicked,
my problem is, the event handler makes the whole inner div to drop down, what is causing it?
HTML
<div class="container">
<div id="board"></div>
</div>
scc
.square{
height: 100%;
width: 50px;
border: 1px solid black;
display: inline-block;
padding-top: 2.3%;
box-sizing: border-box;
text-align: center
}
.row{
height: 50px;
width: 500px;
}
js
/* creating state */
var cellsArr = [];
var cell = {state: 'clean', dangerScale:0}
for(i=0;i<100 ; i++){
var cell = {state: 'clean', dangerScale:0};
cellsArr.push(cell)
}
var ranArr = [], bomNum = 20;
for(i=0; i<bomNum; i++){
ran = Math.floor(Math.random()*100);
ranArr.push(ran)
}
for(i=0; i<ranArr.length; i++){
cellsArr[ranArr[i]].state = 'dirty'
}
/* creating the dom */
var id = 0
for (var i = 0; i <= 9; i++) {
var divRow = document.createElement('div')
divRow.classList.add('row')
for (var j = 0; j <= 9; j++) {
var div = document.createElement('div')
div.classList.add('square')
div.id = id
div.style.cursor = 'pointer';
div.addEventListener('click',show)
id ++
divRow.appendChild(div)
}
document.getElementById("board").appendChild(divRow)
}
function show(ev){
ev.target.innerText = cellsArr[ev.target.id].state;
}
Related
I am currently doing the odin project Etch-A-sketch challenge.
I currently have it so that using JavaScript I create 16 row divs, with 16 grid squares inside each row div. So it is a 16 x 16 grid.
How do I make it so that when I put more grid squares into the container the whole grid stays the same size and the gird squares get smaller or larger in the container without it spilling over the container walls with flexbox?
Here is my codepen: https://codepen.io/Alex-Swan/pen/jOyMwzm
Javascript:
/* This function creates 16x16 grid or what ever input the user has given, the event listner at the
bottom of the function makes it that when a user hovers over a grid square it turns black.
*/
function fullGrid(e) {
for (let i = 0; i < e; i++) {
row = document.createElement("DIV");
container.appendChild(row);
row.className = "row";
for (let i = 0; i < e; i++) {
square = document.createElement("DIV");
row.appendChild(square);
square.className = "gridSquare";
}
}
for (let i = 0; i < gridSquare.length; i++) {
gridSquare[i].addEventListener("mouseover", () => {
gridSquare[i].className += " squareBlack";
});
}
}
CSS:
.container {
border: black solid 1px;
width: 400px;
height: 400px;
}
.row {
display: flex;
height: 6%;
}
.gridSquare {
border: #444242 solid 1px;
margin: auto;
height: 100%;
width: 33.3%;
}
.squareBlack {
background-color: black;
}
Fixed it!
In JavaScript I calculated to height by dividing the GridSquare amount by the 400px size of the container. Also i changed the CSS box-sizing to border box.
Javascript:
function fullGrid(e) {
for (let i = 0; i < e; i++) {
row = document.createElement("DIV");
container.appendChild(row);
row.className = "row";
for (let i = 0; i < e; i++) {
square = document.createElement("DIV");
row.appendChild(square);
square.className = "gridSquare";
square.style.width = "100%"; // <----- HERE
let height = 400 / parseInt(squareAmount); // <----- HERE
square.style.height = `${height}px`; // <----- HERE
}
}
for (let i = 0; i < gridSquare.length; i++) {
gridSquare[i].addEventListener("mouseover", () => {
gridSquare[i].className += " squareBlack";
});
}
}
I am trying to append a to the center of a 3x3 grid. Right now the tile is the last grid-item.
The divs are created using an event listener that triggers a function with a for loop.
function displayDino(){
for (var i = 0; i < dinoData.length; i++) {
const dinoDiv = document.createElement('div');
dinoDiv.className = 'grid-item';
dinoDiv.innerHTML = `<h3>${dinoData[i]["species"]}<h3><img src="images/${(dinoData[i]["species"].toLowerCase())}.png"><p>${dinoData[i]["fact"]}</p>`;
document.getElementById('grid').appendChild(dinoDiv);
}
}
I have another function that appends the div I want centered to the grid:
function displayHuman(){
const humanDiv = document.createElement('div');
humanDiv.className = 'grid-item';
humanDiv.innerHTML = `<h3>${human.name()}<h3><img src="images/human.png">`;
document.getElementById('grid').appendChild(humanDiv);
}
How can I generate this grid while making sure a specific div appears at the center of the grid every time?
Any help would be much appreciated. Thank you!
If the grid is always 3x3 and you want to center the human entry horizontally and vertically, just wait until you are at index 5, add the human, remember that you added him and continue iterating through the array.
function displayElements(){
var humanAdded = false;
for (var i = 0; i < dinoData.length; i++) {
const elemDiv = document.createElement('div');
elemDiv .className = 'grid-item';
if(humanAdded == false && i == 5){
elemDiv .innerHTML = `<h3>${human.name()}<h3><img src="images/human.png">`;
humanAdded = true;
i--;
}else{
elemDiv .innerHTML = `<h3>${dinoData[i]["species"]}<h3><img src="images/${(dinoData[i]["species"].toLowerCase())}.png"><p>${dinoData[i]["fact"]}</p>`;
}
document.getElementById('grid').appendChild(elemDiv);
}
}
My thoughts::: If you know where to put your single data in a grid.. just use grid-row, grid-column css for that grid-child... Just ignore the other grid-childs and just style that particular child... you can have more than one humans which you can put whereever you like this way...
var dinoData = ["Plateosaurus","Abelisaurus","Barsboldia","Litosoraus","Platicore","Manticore","Trynasoraus","Sicocoreus"];
var human = { name: "MEEEEEEEE"};
function displayDino() {
for (var i = 0; i < dinoData.length; i++) {
const dinoDiv = document.createElement('div');
dinoDiv.className = 'grid-item';
dinoDiv.innerHTML = `<h3>${dinoData[i]}<h3>`;
document.getElementById('grid').appendChild(dinoDiv);
}
}
function displayHuman() {
const humanDiv = document.createElement('div');
humanDiv.className = 'grid-item human';
humanDiv.innerHTML = `<h3>${human.name}`;
document.getElementById('grid').appendChild(humanDiv);
}
displayDino();displayHuman();
#grid{
display: grid;
grid-template-columns: auto auto auto;
}
.grid-item{
display: flex;
padding: 50px;
justify-content: center;
align-items: center;
}
.human{
grid-row: 2/3;
grid-column: 2/3;
}
<div id="grid">
</div>
I have a 16x16 grid of small squares. I have added a permanent "hover" effect to make the very first box turn red when I put my mouse over it. However, I want to add the same effect to all of the boxes on the page. I can't figure out how to do it - I have tried to add an event listener to the whole page and used target.nodeName and target.NodeValue, but to no avail. I have included the working version where the fix box turns red on mouseover.
var n=16; //take grid column value as you want
const bigContainer = document.querySelector('.bigContainer')
for(var i = 1; i < n; i++) {
bigContainer.innerHTML+='<div class="row">';
for(j = 0; j < n; j++) {
bigContainer.innerHTML+='<div class="smallBox">';
}
}
const smallBox = document.querySelector('.smallBox');
smallBox.addEventListener('mouseover', () => {
smallBox.classList.add('permahover');
});
.smallBox {
border: 1px solid black;
width: 20px;
height: 20px;
display: inline-block;
}
.permahover {
background: red;
}
h1 {
text-align: center;
}
.bigContainer {
text-align: center;
}
<h1>Etch-a-Sketch Assignment - The Odin Project</h1>
<div class="bigContainer">
</div>
The immediate problem you are having is that this is only querying, and subsequently adding an event listener to, one element.
const smallBox = document.querySelector('.smallBox');
smallBox.addEventListener('mouseover', () => {
smallBox.classList.add('permahover');
});
In the above portion of your code, querySelector only returns the first matching element. You may be looking for querySelectorAll here which returns a NodeList of matching elements.
You have two options (perhaps others if you want to restructure your code further). The naive approach is to, in fact, query for all of the cells and add event listeners to each of them.
var n=16; //take grid column value as you want
const bigContainer = document.querySelector('.bigContainer')
for(var i = 1; i < n; i++) {
bigContainer.innerHTML+='<div class="row">';
for(j = 0; j < n; j++) {
bigContainer.innerHTML+='<div class="smallBox">';
}
}
const smallBoxes = document.querySelectorAll('.smallBox');
[...smallBoxes].forEach(smallBox => {
smallBox.addEventListener('mouseover', () => {
smallBox.classList.add('permahover');
});
})
.smallBox {
border: 1px solid black;
width: 20px;
height: 20px;
display: inline-block;
}
.permahover {
background: red;
}
h1 {
text-align: center;
}
.bigContainer {
text-align: center;
}
<h1>Etch-a-Sketch Assignment - The Odin Project</h1>
<div class="bigContainer">
</div>
Another option is to use event delegation as you identified. Here is how you can leverage that. Note: this approach is a bit tricker for an aggressive event like "mouseover" as you may get false positive targets (like the outer container for example).
var n=16; //take grid column value as you want
const bigContainer = document.querySelector('.bigContainer')
for(var i = 1; i < n; i++) {
bigContainer.innerHTML+='<div class="row">';
for(j = 0; j < n; j++) {
bigContainer.innerHTML+='<div class="smallBox">';
}
}
bigContainer.addEventListener('mouseover', e => {
var target = e.target
if (target !== bigContainer) {
target.classList.add('permahover')
}
})
.smallBox {
border: 1px solid black;
width: 20px;
height: 20px;
display: inline-block;
}
.permahover {
background: red;
}
h1 {
text-align: center;
}
.bigContainer {
text-align: center;
}
<h1>Etch-a-Sketch Assignment - The Odin Project</h1>
<div class="bigContainer">
</div>
You need to use a delegation event, because all the small boxes don't exist on the page when the page is loaded (You can figure out in the inspector element that only your first box has the event listener).
So you listen the whole container (because it is always on the page on load)
bigContainer.addEventListener('mouseover', () => {
// Code for checking if we hovered a small div & if yes applying the style
});
...and then do a comparaison with the event.target (which will be the small div hovered)
if (event.target.matches('.smallBox')) {
event.target.classList.add('permahover');
}
var n=16; //take grid column value as you want
const bigContainer = document.querySelector('.bigContainer')
for(var i = 1; i < n; i++) {
bigContainer.innerHTML+='<div class="row">';
for(j = 0; j < n; j++) {
bigContainer.innerHTML+='<div class="smallBox">';
}
}
const smallBox = document.querySelector('.smallBox');
bigContainer.addEventListener('mouseover', () => {
if (event.target.matches('.smallBox')) {
event.target.classList.add('permahover');
}
});
.smallBox {
border: 1px solid black;
width: 20px;
height: 20px;
display: inline-block;
}
.permahover {
background: red;
}
h1 {
text-align: center;
}
.bigContainer {
text-align: center;
}
<h1>Etch-a-Sketch Assignment - The Odin Project</h1>
<div class="bigContainer">
</div>
You can use forEach method to loop through all boxes and add eventListener on each one.
If all of them have .smallBox class you can do it like this:
const smallBoxes = document.querySelectorAll('.smallBox');
smallBoxes.forEach(box => box.addEventListener('mouseover', () => {
smallBox.classList.add('permahover');
}))
I hope it helped you!
let smallBoxes = document.querySelectorAll('.smallBox');
[...smallBoxes].forEach(el => {
el.addEventListener('mouseover', e => e.target.classList.add('permahover'));
});
you should set the eventlistener to your DOM and ask if the trigger element are one of your elements which are that specific class. So you can handle every element with that class.
var n = 16; //take grid column value as you want
const bigContainer = document.querySelector('.bigContainer')
for (var i = 1; i < n; i++) {
bigContainer.innerHTML += '<div class="row">';
for (j = 0; j < n; j++) {
bigContainer.innerHTML += '<div class="smallBox">';
}
}
document.addEventListener('mouseover', function(e) {
if (e.target && e.target.className == 'smallBox') {
var target = e.target;
target.classList.add('permahover');
}
});
Working js fiddle: https://jsfiddle.net/nwukf205/
hope i could help you :)
if you got questions just ask
Have you tried the :hover selector? Not sure if you want specify any dynamic actions here, but it's easy to do basic stuff.
https://www.w3schools.com/cssref/sel_hover.asp
a:hover {
background-color: yellow;
}
I haven't tried your example myself but something similar to this has been answered here:
Hover on element and highlight all elements with the same class
This question already has answers here:
Image inside div has extra space below the image
(10 answers)
Why does my image have space underneath?
(3 answers)
Align inline-block DIVs to top of container element
(5 answers)
Closed 3 years ago.
I am trying to create a chess board.I am using nested loops to do that. The problem is that there is a gap between two horizontal rows of the block. Below I have create a snippet for 3x3 board.
const board = document.querySelector('#board');
const colors = ["black","gray"]
function start(){
for(let i = 0;i<3;i++){
let br = document.createElement('br')
for(let j = 0;j<3;j++){
let block = document.createElement('div');
block.classList.add('block');
let id = (i * 8) + j
block.id = id;
block.style.backgroundColor = colors[(id+i) % 2]
board.appendChild(block)
}
board.appendChild(br)
}
}
start()
.block{
height: 70px;
width: 70px;
display:inline-block;
}
<div id="board"></div>
I already head about solution using float:left instead of display:inline-block. How could I remove the gap?
I would also like to see if there is better code for creating chessboard?
The gap is there because the <br>. #board { font-size: 0; } will remove it.
You seem to be trying to create a table with divs. It's perfectly fine, apart from the fact that you'll need to manage spaces between the blocks with margins, if you ever need them.
You could create a table and use border-collapse: collapse
const board = document.querySelector('#board');
const colors = ["black", "gray"]
function start() {
for (let i = 0; i < 3; i++) {
let tr = document.createElement('tr')
for (let j = 0; j < 3; j++) {
let block = document.createElement('td');
block.classList.add('block');
let id = (i * 8) + j
block.id = id;
block.style.backgroundColor = colors[(id + i) % 2]
tr.appendChild(block)
}
board.appendChild(tr)
}
}
start()
.block {
height: 70px;
width: 70px;
}
#board {
border-collapse: collapse;
}
<table id="board"></table>
try to use flex
function start(n){
let s='';
for(let i = 0;i<n;i++){
s+='<div class="row">'
for(let j = 0;j<n;j++){
s+=`<div class="block ${(i+j)%2?'white':''}"></div>`
}
s+='</div>'
}
board.innerHTML=s;
}
start(3)
.block{ height: 70px; width: 70px; background: black }
.white { background: gray }
.row { display: flex }
<input type="range" min="1" max="8" oninput="start(this.value)" value=3 /><br>
<div id="board"></div>
I'd recommend using canvas. You can fill the screen with rectangles, each with sidelength width ,and starting position (i*width,j*width). Each rect can be filled with a colour, by specifying the fill colour before drawing. Look into a good HTML Canvas tutorial.
I am trying to make a chessboard using javascript and creating 64 divs with it.
The problem is, that it creates only the first div.
Here is the code:
div {
width: 50px;
height: 50px;
display: block;
position: relative;
float: left;
}
<script type="text/javascript">
window.onload=function()
{
var i=0;
var j=0;
var d=document.createElement("div");
for (i=1; i<=8; i++)
{
for (j=1; j<=8; j++)
{
if ((i%2!=0 && j%2==0)||(i%2==0 && j%2!=0))
{
document.body.appendChild(d);
d.className="black";
}
else
{
document.body.appendChild(d);
d.className="white";
}
}
}
}
</script>
As t-j-crowder has noted, the OP's code only creates one div. But, for googlers, there is one way to append multiple elements with a single appendChild in the DOM: by creating a documentFragment.
function createDiv(text) {
var div = document.createElement("div");
div.appendChild(document.createTextNode(text));
return div;
}
var divs = [
createDiv("foo"),
createDiv("bar"),
createDiv("baz")
];
var docFrag = document.createDocumentFragment();
for(var i = 0; i < divs.length; i++) {
docFrag.appendChild(divs[i]); // Note that this does NOT go to the DOM
}
document.body.appendChild(docFrag); // Appends all divs at once
The problem is, that it creates only the first div.
Right, because you've only created one div. If you want to create more than one, you must call createElement more than once. Move your
d=document.createElement("div");
line into the j loop.
If you call appendChild passing in an element that's already in the DOM, it's moved, not copied.
window.onload=function()
{
var i=0;
var j=0;
for (i=1; i<=8; i++)
{
for (j=1; j<=8; j++)
{
if ((i%2!=0 && j%2==0)||(i%2==0 && j%2!=0))
{
var d=document.createElement("div");
document.body.appendChild(d);
d.className="black";
}
else
{
var d=document.createElement("div");
document.body.appendChild(d);
d.className="white";
}
}
}
}
Although what T.J. Crowder writes works fine, I would recommend rewriting it to the code below, using a documentFragment, like Renato Zannon suggested. That way you will only write to the DOM once.
window.onload = function() {
var count = 5,
div,
board = document.getElementById('board'),
fragment = document.createDocumentFragment();
// rows
for (var i = 0; i < count; ++i) {
// columns
for (var j = 0; j < count; ++j) {
div = document.createElement('div');
div.className = (i % 2 != 0 && j % 2 == 0) || (i % 2 == 0 && j % 2 != 0) ? 'black' : 'white';
fragment.appendChild(div);
}
}
board.appendChild(fragment);
};
#board {
background-color: #ccc;
height: 510px;
padding: 1px;
width: 510px;
}
.black,
.white {
float: left;
height: 100px;
margin: 1px;
width: 100px;
}
.black {
background-color: #333;
}
.white {
background-color: #efefef;
}
<div id="board"></div>
function crt_dv(){
dv=document.createElement('div'),document.body.appendChild(dv)
};
crt_dv(),dv.className='white';crt_dv(),dv.className='black';
Also use: for(i=0;i<2;i++)