Eric Petela
Eric Petela

Reputation: 377

addEventListener for mouseover works within a function but not outside the function

I am making an etch-a-sketch and I am trying to use an addEventListener event of 'mouseover' to add a CSS class where the background of the square the mouse hovers over will turn black. I have a function that creates a single box and if I put the event listener inside this function it works, however if I try to do it outside the function it doesn't work

The function box creates a single box (which will get repeated using the addMultipleBox function) and adds a mouseover event. In this scenario the mouseover works correctly

function box() {
    let square = document.createElement('div')
    square.setAttribute('class', 'box')
    container.appendChild(square)

    square.addEventListener('mouseover', () => {
        square.classList.add('blackPen')
    })
}

//creates the etch a sketch board with multiple 'boxes'
function addMultipleBoxes() {
    for(let i = 0; i < 256; i++) {
        box()
    }
}

Now if I try and grab the class of 'box' outside the function and add an event listener to it nothing happens. I do have this code at the bottom so it's not like i'm trying to grab divs before they are created.

I'd like to be able to grab it outside so I can create another function that on a mouse click I remove the class of 'blackPen' which will remove the background color of black on the square, essentially wiping the board clean. Here is what I have for that

let boxx = document.querySelector('.box')

console.log(boxx)

boxx.addEventListener('mouseover', () => {
    boxx.classList.add('blackPen')
})

When I console.log 'Boxx' I get the <div class="box"></div>. If I console.log "square" above in the box function I get the same thing as Boxx.

Any insight would be much appreciated!

Upvotes: 0

Views: 2694

Answers (1)

Dave Pritlove
Dave Pritlove

Reputation: 2687

The box() function adds the class to each element as it is made, as required.

A reference made to an element using querySelector contains only one element - the first in the document with the specified selector. See https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector

This snippet illustrates the idea with four divs, all the same class.

let boxx = document.querySelector('.box')


boxx.addEventListener('mouseover', () => {
    boxx.classList.add('blackPen')
})
.box {
  display: inline-block;
  width: 70px;
  aspect-ratio: 1;
  background: yellow;
  border: 1px solid red;
}

.blackPen {
  background: black;
}
<p><b>mouseover applied to element got by querySelector</b></p>
<p>(move mouse over divs)</d>

<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>

<p>querySelector, returns the <em>first</em> Element within the document that matches the specified selector</p>

A reference to all elements with a given class can be made using querySelectorAll(), which returns a live node list with references to all the elements of the given selector. See: https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll

Having made the reference, you will still have to loop through them in order to add the event listeners required. node lists and html collections are array-like structures that can have individual members referenced by and index [0],[1], and so on.

This snippet illustrates adding a new class to each div in a node list formed using querySelectorAll:

let boxx = document.querySelectorAll('.box')



for (let i=0; i<boxx.length; i++) {

boxx[i].addEventListener('mouseover', () => {
    boxx[i].classList.add('blackPen');
    boxx[i].classList.remove('cancel');
});

boxx[i].addEventListener('click', () => {
    boxx[i].classList.add('cancel')
});

} // next i boxx element;
.box {
  display: inline-block;
  width: 70px;
  aspect-ratio: 1;
  background: yellow;
  border: 1px solid red;
}

.blackPen {
  background: black;
}

.cancel {
  background: yellow;
}
<p><b>mouseover applied to all elements got by querySelectorAll</b><br>(move mouse over divs)</d>

<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>

<p>A click event was also added to all elements, to replace the class added by the mouseover event<br>click boxes to see the effect</p>

Note that the node collection only needs to be made once to be used for any further manipulations. In the snippet a mouseover event adds a class to make the background black while a click event cancels it.

Upvotes: 0

Related Questions