manski
manski

Reputation: 181

Divs generated in javascript appearing with no height

Context: I'm working through the Odin Project and trying to make an etch-a-sketch board. The project asks for you to make a board that you can draw on when your mouse hovers over, but it has to be made out of a grid of small divs that you add to the DOM from your javascript.

Problem: When the divs get generated to make the grid, they appear with a width of x (user generated) but a height of 0. So you can't hover over them. I expect to see a large blue square but instead it is blank unless I go out of my way to add in a height value in the css. The divs are created in the for-loop of line 14 of the javascript file here: https://jsfiddle.net/krmanski/ry12xumq/9/

function generateCanvas(gridSize){
    //create the gridlines
    //divide canvas into A x A where A = the number provided by user
    let canvas = document.querySelector(".main-grid-container");
    canvas.style.gridTemplateColumns = `repeat(${gridSize}, 1fr)`;
    canvas.style.gridTemplateRows = `repeat(${gridSize}, 1fr)`;
    alert("canvas should be generated");


    let divsTotal = (gridSize * gridSize);
    for(let i = 0; i < divsTotal; i++){
        let div = document.createElement("div");
        div.classList.add("grid-item");
        div.style.backgroundColor="blue";
        
        //this will allow our divs to change color when hovered over
        div.addEventListener("mouseover", function(){
            div.style.backgroundColor="black";
        })

        canvas.appendChild(div);
    }
}

I have looked at other people's solutions on github and youtube and nearly all of them use the exact same code I do in my for-loop, and they apply no CSS at any point to tell their divs to have height. I am thinking of starting from a blank slate because I just can't figure out the problem but at this point I'm just idly curious what is the problem and why my divs are appearing with 0 height.

Upvotes: 1

Views: 73

Answers (3)

Mad7Dragon
Mad7Dragon

Reputation: 1313

For some reason, your line ( I tried to figure the reason out, but couldn't )

// style.insertRule(`.grid-item {height: ${gridSize}}`,0);

doesn't select grid-items. but I found that you selected them when you added grid-item class. so just add div.style.height = "100%"; after that.

//wait until the HTML and CSS are loaded before you run the javascript
document.addEventListener("DOMContentLoaded", function(){
    generateCanvas(16);
    console.log("dom content is loaded");
    
});

function generateCanvas(gridSize){
    //create the gridlines
    //divide canvas into A x A where A = the number provided by user
    let canvas = document.querySelector(".main-grid-container");
    canvas.style.gridTemplateColumns = `repeat(${gridSize}, 1fr)`;
    canvas.style.gridTemplateRows = `repeat(${gridSize}, 1fr)`;
    // alert("canvas should be generated");
    // style.insertRule(`.grid-item {height: ${gridSize}}`,0);

    let divsTotal = (gridSize * gridSize);
    for(let i = 0; i < divsTotal; i++){
        let div = document.createElement("div");
        div.classList.add("grid-item");
        div.style.backgroundColor="blue";
        div.style.height = "100%";
        
        //this will allow our divs to change color when hovered over
        div.addEventListener("mouseover", function(){
            div.style.backgroundColor="black";
        })

        canvas.appendChild(div);
    }
}

function selectSize(){
    //has the user type a number and returns that number, but only if it is between 0 and 100
    let userInput = prompt("What should be the size of the board?")
    let message = document.querySelector("#message")
    
    
    if (userInput == ""){
        message.innerText = "Please provide a number only";
    } else if(userInput < 0 || userInput > 100){
        message.innerText ="Please only provide a number between 1 and 100"
    } else {
        message.innerText =`You selected a ${userInput} x ${userInput} sized grid for your canvas`
        generateCanvas(userInput);
    } 

}


const buttonPress = e =>{
    //takes in the id of the button that was pressed.
    let buttonID = e.target.id;
    console.log(buttonID);
    alert(`button ${buttonID} was pressed`);
    switch(buttonID){
        case "modify-grid":
            
            selectSize();
            break;
        
        case "black":
            alert('you pressed black');
            break;

        case "red":
            alert('you pressed red');
            break;
        
        case "reset":
            alert('you pressed reset');
            break;
        
    }
}

//get all buttons and make them listen for a click to run a function
let buttons = document.querySelectorAll(".button");
buttons.forEach(button => button.addEventListener("click", buttonPress));
@import url('https://fonts.googleapis.com/css?family=Muli&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Comforter+Brush&display=swap');
@import url('https://fonts.googleapis.com/css?family=Quicksand&display=swap');


h3 {
    font-family: 'Quicksand', sans-serif;
    font-weight: 700;
    font-style: normal;
    letter-spacing: -.02em;
    color: rgb(15, 45, 0);
    font-size: 18px;
    line-height: 1.15;
  }

.header{
    display: flex;
    justify-content: center;
    align-items: center;
    padding: 10px;
    margin: 20px;
    border: solid;
    border-color: black;
    flex-direction: column;
}

.main-program-space{
    display: flex;
    justify-content: center;
    align-items: center;
    padding: 10px;
    margin: 20px;
    border: solid;
    border-color: black;
    flex-direction: column;
}

.buttons-flexbox{
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 10px;
    margin: 20px;
    border: solid;
    border-color: red;
    list-style: none;
    flex-direction: row;
    gap: 20px;
}

/* This will make our buttons look cool and change when hovered over */
.button {
  align-items: center;
  background-image: linear-gradient(144deg,#AF40FF, #5B42F3 50%,#00DDEB);
  border: 0;
  border-radius: 8px;
  box-shadow: rgba(151, 65, 252, 0.2) 0 15px 30px -5px;
  box-sizing: border-box;
  color: #FFFFFF;
  display: flex;
  font-family: Phantomsans, sans-serif;
  font-size: 20px;
  justify-content: center;
  line-height: 1em;
  max-width: 100%;
  min-width: 140px;
  padding: 3px;
  text-decoration: none;
  user-select: none;
  -webkit-user-select: none;
  touch-action: manipulation;
  white-space: nowrap;
  cursor: pointer;
  min-width: 150px;
  min-height: 50px;
}

.button:active,
.button:hover {
  outline: 0;
}

.main-grid-container{
    display: grid;
    justify-content: center;
    align-items: center;
    padding: 10px;
    margin: 20px;
    border: solid;
    border-color: red;
    width: 500px;
    height: 500px;
}

/* .grid-item{
    height: 12px;
} */

.bottom-text{
    display: flexbox;
    justify-content: center;
    align-items: center;
    padding: 10px;
    margin: 20px;
    border: solid;
    border-color: red;
}

.footer-flexbox{
    display: flexbox;
    justify-content: center;
    align-items: center;
    padding: 10px;
    margin: 20px;
    border: solid;
    border-color: black;
}

.footer{
    display: flexbox;
    justify-content: center;
    align-items: center;
    padding: 10px;
    margin: 20px;
    border: solid;
    border-color: red;
}
<body>
    <div class ="title header">
        <h3>The html is working but what about CSS</h3>
        <p id="message">(messages from main.js will print here)</p>
    </div>

    <div class="main-program-space">
        <ul class="buttons-flexbox">
            <li><button id="modify-grid" class="button modify-grid">Modify Grid</span></button></li>
            <li><button id="black" class="button black">Black</button></li>
            <li><button id="red" class="button red">Red</button></li>
            <li><button id="reset" class="button reset">Reset</button></li>
        </ul>

        <div class="main-grid-container">
            
        </div>

        <div class="bottom-text">
            <h3>XXXXX bottom text XXXXX</h3>
        </div>

    </div>

    <div class="footer-flexbox">
        <div class="footer">
            <h3>XXXXX footer XXXXX</h3>
        </div>
    </div>

</body>

Upvotes: 0

Professor Abronsius
Professor Abronsius

Reputation: 33813

Is this the sort of effect that you were after? The following uses css variables to determine width/height of the individual grid squares based upon simple arithmetic of the canvas with divided by the number of grid-items. The CSS variables are updated within the generateCanvas function and this can be extended to control the various colours presumably set by the buttons.

let active=true;

//wait until the HTML and CSS are loaded before you run the javascript
document.addEventListener("DOMContentLoaded", function() {
  generateCanvas();
  
  document.addEventListener('contextmenu',e=>{
    e.preventDefault();
    if( e.target.parentNode==document.querySelector(".main-grid-container") ){
      active=false;
    }
  })
  document.addEventListener('blur',()=>active=true);
  document.addEventListener('click',()=>active=true);
});



function generateCanvas(size=16) {
  // Find the doc root to access variables
  let root = document.documentElement;
  
  let canvas = document.querySelector(".main-grid-container");
      canvas.style.gridTemplateColumns = `repeat(${size}, 1fr)`;
      canvas.style.gridTemplateRows = `repeat(${size}, 1fr)`;
      
      // important to clear the grid otherwise it will grow 
      // on each invocation of this function!
      canvas.innerHTML = '';

  // calculate the size of the containg canvas
  let box = canvas.getBoundingClientRect();
  let w = box.width / size;
  let h = box.height / size;
  
  // update the variables with new sizes
  root.style.setProperty('--w', `${w}px`);
  root.style.setProperty('--h', `${h}px`);

  
  for( let i=0; i < Math.pow(size, 2); i++ ) {
    let div = document.createElement("div");
        div.classList.add("grid-item");
    canvas.appendChild(div);
  }
  
  
  // Rather than assign the same event listener to every grid square, use a `delegated`
  // event listener bound to the canvas.
  canvas.addEventListener('mouseover',e=>{
    let cn='grid-paint';
    if( active && e.target.classList.contains('grid-item') && !e.target.classList.contains( cn ) )e.target.classList.add( cn )
  })
}








function selectSize() {
  //has the user type a number and returns that number, but only if it is between 0 and 100
  let userInput = prompt("What should be the size of the board?")
  let message = document.querySelector("#message")


  if (isNaN( userInput ) ) {
    message.innerText = "Please provide a number only";
  } else if( Number(userInput) < 0 || Number(userInput) > 100) {
    message.innerText = "Please only provide a number between 1 and 100"
  } else {
    message.innerText = `You selected a ${userInput} x ${userInput} sized grid for your canvas`
    generateCanvas(userInput);
  }
  return true;
}




const setcolours=( fgcol='black', bgcol='blue' )=>{
    let root = document.documentElement;
          root.style.setProperty(`--fgcolour`,fgcol);
          root.style.setProperty(`--bgcolour`,bgcol);
    return true;
}


const reset=()=>{
  generateCanvas();
  return setcolours();
}




const buttonPress = e => {
  let buttonID = e.target.id;
  let alt=e.target.dataset.alt;
  
  switch(buttonID) {
    case "modify-grid":return selectSize();
    case 'blue':return setcolours(alt,buttonID);
    case "black":return setcolours(alt,buttonID);
    case "red":return setcolours(alt,buttonID);
    case "reset":return reset();
  }
}



//get all buttons and make them listen for a click to run a function
let buttons = document.querySelectorAll(".button");
    buttons.forEach(button => button.addEventListener("click", buttonPress));
@import url('https://fonts.googleapis.com/css?family=Muli&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Comforter+Brush&display=swap');
@import url('https://fonts.googleapis.com/css?family=Quicksand&display=swap');

/* 
  Two variables to dictate width and height of grid elements.
  These values are updated by javascript.
*/
:root {
  --w:1px;
  --h:1px;
  --bgcolour:blue;
  --fgcolour:black;
}

h3 {
  font-family: 'Quicksand', sans-serif;
  font-weight: 700;
  font-style: normal;
  letter-spacing: -.02em;
  color: rgb(15, 45, 0);
  font-size: 18px;
  line-height: 1.15;
}

.header {
  display: flex;
  justify-content: center;
  align-items: center;
  padding: 10px;
  margin: 20px;
  border: solid;
  border-color: black;
  flex-direction: column;
}

.main-program-space {
  display: flex;
  justify-content: center;
  align-items: center;
  padding: 10px;
  margin: 20px;
  border: solid;
  border-color: black;
  flex-direction: column;
}

.buttons-flexbox {
  display: flex;
  flex-direction: row;
  
  justify-content: space-between;
  align-items: center;
  gap: 10px;
  
  padding: 10px;
  margin: 20px;
  border: solid;
  border-color: red;
  list-style: none;
}


/* This will make our buttons look cool and change when hovered over */

.button {
  align-items: center;
  background-image: linear-gradient(144deg, #AF40FF, #5B42F3 50%, #00DDEB);
  border: 0;
  border-radius: 8px;
  box-shadow: rgba(151, 65, 252, 0.2) 0 15px 30px -5px;
  box-sizing: border-box;
  color: #FFFFFF;
  display: flex;
  flex:1;
  
  font-family: Phantomsans, sans-serif;
  font-size: 1rem;
  justify-content: center;
  line-height: 1rem;
  
  text-decoration: none;
  user-select: none;
  -webkit-user-select: none;
  touch-action: manipulation;
  white-space: nowrap;
  cursor: pointer;
  
  min-width: 130px;
  min-height: 50px;
}

.button:active,
.button:hover {
  outline: 0;
}

.main-grid-container {
  display: grid;
  justify-content: center;
  align-items: center;

  margin: 20px;
  border: none;
  width: 500px;
  height: 500px;
  
  padding:10px;
  border:1px solid black;
}

.bottom-text {
  display: flexbox;
  justify-content: center;
  align-items: center;
  padding: 10px;
  margin: 20px;
  border: solid;
  border-color: red;
}

.footer-flexbox {
  display: flexbox;
  justify-content: center;
  align-items: center;
  padding: 10px;
  margin: 20px;
  border: solid;
  border-color: black;
}

.footer {
  display: flexbox;
  justify-content: center;
  align-items: center;
  padding: 10px;
  margin: 20px;
  border: solid;
  border-color: red;
}







.grid-item {
  display: flex;
  flex: 1;
  margin: 0;
  background: var(--bgcolour);
  width: var(--w);
  height: var(--h);
}
.grid-paint{
  background:var(--fgcolour);
}
<div class="title header">
  <h3>The html is working but what about CSS</h3>
  <p id="message">(messages from main.js will print here)</p>
</div>

<div class="main-program-space">
  <ul class="buttons-flexbox">
    <li><button id="modify-grid" class="button modify-grid">Modify Grid</button></li>
    <li><button id="blue" data-alt='black' class="button blue">Blue</button></li>
    <li><button id="black" data-alt='blue' class="button black">Black</button></li>
    <li><button id="red" data-alt='yellow' class="button red">Red</button></li>
    <li><button id="reset" class="button reset">Reset</button></li>
  </ul>

  <div class="main-grid-container"></div>

  <div class="bottom-text">
    <h3>XXXXX bottom text XXXXX</h3>
  </div>
</div>

<div class="footer-flexbox">
  <div class="footer">
    <h3>XXXXX footer XXXXX</h3>
  </div>
</div>

Upvotes: 0

silvenon
silvenon

Reputation: 2197

Setting align-items: center on .main-grid-container is what prevents your divs from being stretched vertically. I recommend simply removing that declaration, the initial value normal will achieve the desired effect.

Upvotes: 2

Related Questions