I'm trying to create a 3x3 puzzle, grid of blocks of divs and each time the page refreshes, js creates and array of random order of numbers from 1-9 and uses them to create the 'blocks', gives them the corresponding id's and appends them to the container But i'm having issues, as not all the blocks are displayed. Some blocks (precisely 2 blocks) are still in the default 'absolute' position (0, 0) while the rest are okay.
Please can anyone help find out what's wrong ?
#randomOrder is and an array of 1-9 randomly ordered
# CSS Snippet :
.container{
width: 300px;
padding: 3px;
display: flex;
aspect-ratio: 1;
flex-wrap: wrap;
position: relative;
margin: 100px auto;
background: #777;
border-radius: 10px;
box-shadow: 0 0 0 5px #000;
}
.block{
width: 31%;
height: 31%;
margin: 1.5px;
display: flex;
font-size: 3rem;
cursor: pointer;
user-select: none;
background: #eee;
position: absolute;
border-radius: 10px;
align-items: center;
justify-content: center;
border: 2px solid #000;
box-shadow: 0 0 20px #555 inset;
}
# JS Snippet:
let r = 1, c = 1
let x = 4, y = 4
randomOrder.forEach(el => {
block = document.createElement('div')
block.classList.add('block')
block.id = "b" el
if(r <= 3){
if(c <= 3){
block.style.left = x 'px'
block.style.top = y 'px'
c
x = 98
}
else{
c = 1
x = 4
y = 98
r
}
}
if (el == 9) {
block.innerText = ""
}
else {
block.innerText = el
}
container.appendChild(block)
})
This is what I'm getting below :
But This Is What I'm Expecting : (But in any random order)
CodePudding user response:
There are these issues in your logic:
The inner
if
condition should beif (c < 3)
instead ofif (c <= 3)
, sincec
still gets incremented in thatif
blockThe assignment to
style.left
andstyle.top
should also happen when execution gets into theelse
block, so those two assignments should be made before theif
block
should be declared with avar
orlet
orconst
keyword. Now it is implicitly defined as a global variable which is not good practice, and not allowed when running in strict mode.
Not an issue, but the if (r <= 3)
really is not necessary -- this will always be the case.
With those remarks taken into account, the relevant code becomes:
const block = document.createElement('div')
block.classList.add('block')
block.id = "b" el
block.style.left = x 'px'
block.style.top = y 'px'
if(c < 3){
c
x = 98
}
else{
c = 1
x = 4
y = 98
r
}
There is however an easier way to determine x
and y
, using the remainder operator (%
) and the index you can get as argument in the forEach
callback.
Unrelated, but the final if..else
can be shortened with the conditional operator (? :
):
const container = document.querySelector(".container");
const randomOrder = [1, 2, 3, 4, 5, 6, 7, 8, 9];
randomOrder.forEach((el, i) => {
const block = document.createElement('div');
block.classList.add('block');
block.id = "b" el;
block.style.left = (4 98*(i % 3)) 'px'
block.style.top = (4 98*Math.floor(i / 3)) 'px'
block.innerText = el == 9 ? "" : el;
container.appendChild(block);
});
.container{
width: 300px;
padding: 3px;
display: flex;
aspect-ratio: 1;
flex-wrap: wrap;
position: relative;
margin: 100px auto;
background: #777;
border-radius: 10px;
box-shadow: 0 0 0 5px #000;
}
.block{
width: 31%;
height: 31%;
margin: 1.5px;
display: flex;
font-size: 3rem;
cursor: pointer;
user-select: none;
background: #eee;
position: absolute;
border-radius: 10px;
align-items: center;
justify-content: center;
border: 2px solid #000;
box-shadow: 0 0 20px #555 inset;
}
<div ></div>
Here is what the %
and Math.floor
expressions evaluate to for all the possible values of the index i
:
index i |
i % 3 |
Math.floor(i / 3) |
---|---|---|
0 | 0 | 0 |
1 | 1 | 0 |
2 | 2 | 0 |
3 | 0 | 1 |
4 | 1 | 1 |
5 | 2 | 1 |
6 | 0 | 2 |
7 | 1 | 2 |
8 | 2 | 2 |
So you can see that i % 3
represents a column index and Math.floor(i / 3)
a row index.