0

I am attempting to assign an onclick event listener to 100 div's that I created in a loop using only vanilla javascript. I have tried various methods that I googled online and cannot get any of them to work. I did read you can do this through a loop (couldn't get that to work either) but that it is bad practice. Thank you

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8"/>
    <title>Functions: Task 1</title>
    <style>
      body, html {
        width: 100vw;
        height: 100vh;
        display: flex;
        justify-content: center;
        align-items: center;
        margin: 0;
        padding: 0;
      }

      p, li {
        color: purple;
        margin: 0.5em 0;
        font-size: 300%;
        color: blue;
      }

      * {
        box-sizing: border-box;
      }

      .preview {
        width: 100vw;
        height: 100vh;
      }
    </style>
  </head>
  <body>
    <section class="preview">
    </section>
  </body>

<script src='java.js'></script>

</html>
let preview = document.querySelector('.preview');
preview.setAttribute('style', 'display: flex; justify-content: center; align-items: center; flex-wrap: wrap;')


function randomColor(input) {
    return Math.floor(Math.random() * 255) + 1;
}

for (i = 10*10; i > 0; i--) {
    let div = document.createElement('div');
    div.className = 'divClass';
    div.setAttribute('style', 'height: 10vh; width: 10vw;');
    div.style.backgroundColor = 'rgb(' + randomColor(255) + ', ' + randomColor(255) + ', ' + randomColor(255) +')';
    preview.appendChild(div);
}

let div = document.querySelector('div');
console.log(div.className);

document.querySelector('div').addEventListener('click', function (event) {

    function randomDivColor(input) {
        Math.floor(Math.random() * 255) + 1;
        document.getElementsByClassName('divClass').style.backgroundColor = 'rgb(' + randomColor(255) + ', ' + randomColor(255) + ', ' + randomColor(255) +')';
    }
})
wiomoc
  • 1,069
  • 10
  • 17
coe
  • 281
  • 1
  • 2
  • 12
  • 3
    you would `div.addEventListener(.......)` in that loop – Jaromanda X Nov 05 '20 at 01:46
  • Example: https://github.com/JBallin/pixel-art/blob/master/app.js – JBallin Nov 05 '20 at 01:48
  • The only non-loop method is to use [event delegation](https://stackoverflow.com/questions/24117369/vanilla-js-event-delegation-dealing-with-child-elements-of-the-target-element). – Phil Nov 05 '20 at 01:49
  • I put the event listener in the loop, it still is not working. There is something wrong with my event listener function I think – coe Nov 05 '20 at 01:52

2 Answers2

2

Simply use event delegation : any click on div belong to his parent section.preview, then check if the clicked element corresponds to your div (event.target)
sample code:

const preview = document.querySelector('.preview')
  ,   rColor  =()=>Math.floor(Math.random() *255) +1
  ;
for (i=100;i--;)
  {
  let div = document.createElement('div');
  div.style.backgroundColor = `rgb(${rColor()},${rColor()},${rColor()})` 
  preview.appendChild(div);
  }
preview.onclick=e=>  // get click event on any elements of section.preview  
  {
  if (!e.target.matches('div')) return  // reject other elements click
  e.target.style.backgroundColor = `rgb(${rColor()},${rColor()},${rColor()})` 
  }
body, html {
  width          : 100vw;
  height         : 100vh;
  display        : flex;
  justify-content: center;
  align-items    : center;
  margin         : 0;
  padding        : 0;
  }
* {
  box-sizing     : border-box;
  }
.preview {
  width          : 100vw;
  height         : 100vh;
  display        : flex; 
  justify-content: center; 
  align-items    : center; 
  flex-wrap      : wrap;
  }
.preview > div {
  height : 10vh; 
  width  : 10vw;
  }
<section class="preview"></section>
Mister Jojo
  • 20,093
  • 6
  • 21
  • 40
0

I can't comment but your function attached to your event listener doesn't do anything other than define a new function which isn't actually called. (Though I could be wrong, so please feel free to correct me). From what I understand, it seems you want it so when you click any div for it to change the colour of all of the 100 divs to a random colour?

I'm not sure how you'd do this without a loop but the event listener probably doesn't need to be on each individual div. It can most likely be in its parent. (The adjustments I have made don't include this but it's something you can look into). Though if you want to change ALL of the divs you'll have to iterate through each of them to change each of their colours.

I have also separated the function from the event listener to make it more readable in my opinion. Just added this here so it's easier for you to understand in case you don't understand the change I've done. E.g. When you click the Elem, it will do everything included in the function called doThis.

elem.addEventListener('click', doThis);
function doThis(){
    // Do something
}

The function randomColor outside of the event listener seems to not use the input so can be changed to this:

function randomColor() {
    return Math.floor(Math.random() * 255) + 1;
}
let preview = document.querySelector('.preview');
preview.setAttribute('style', 'display: flex; justify-content: center; align-items: center; flex-wrap: wrap;')

// Remove input - not used
function randomColor()
{
    return Math.floor(Math.random() * 255) + 1;
}

for (i = 10 * 10; i > 0; i--)
{
    let div = document.createElement('div');
    div.className = 'divClass';
    div.setAttribute('style', 'height: 10vh; width: 10vw;');
    div.style.backgroundColor = 'rgb(' + randomColor() + ', ' + randomColor() + ', ' + randomColor() + ')';
    preview.appendChild(div);
    // Add event listener on creation
    div.addEventListener('click', setAllDivsToRandomColor);
}

function setAllDivsToRandomColor (){
    // Get all divs
    const divList = document.querySelectorAll('.divClass');
    // Iterate (loop) through and set each to random colour
    divList.forEach( element => element.style.backgroundColor = 'rgb(' + randomColor() + ', ' + randomColor() + ', ' + randomColor() + ')');
}
Alvie Mahmud
  • 194
  • 1
  • 10