skip to Main Content

Javascript newbie following Ania Kubow’s Javascript bootcamp video / card matching game tutorial (https://youtu.be/Xm4BObh4MhI?t=34702).

I’d like to request some help figuring out how to have an image change when hovered over, specifically within the Javascript code. For context, I’m making a card matching game based on the tutorial above, except it’s Pokemon themed. When the card/open Pokeball is hovered over, it should then change to a half-way closed Pokeball to show that it’s almost selected.

What’s in the HTML file in this section is literally just:

            <div class="section2"></div>

So it’s all in the Javascript where all of this comes from. Here is the main function. (Bolded is what I added myself.

    function createBoard() {
        for (let i = 0; i < cardArray.length; i++) {
        const card = document.createElement('img')
        card.setAttribute('src', 'src/images/pokeballOpen.png')
        card.setAttribute('data-id', i)
        card.addEventListener('click', flipCard)
**        card.addEventListener('mouseover', hoverPokeball)
        card.addEventListener('mouseout', unhoverPokeball)**
        container.appendChild(card)
        }
    }

Then I also have:

    function hoverPokeball() {
        card.setAttribute('src', 'src/images/pokeballMid.png')
    }

    // unhover over pokeball
    function unhoverPokeball() {
        card.setAttribute('src', 'src/images/pokeballOpen.png')
    }

I am 100% missing something simple here, and I would appreciate it if any of you could help me out.

2

Answers


  1. Use event.target to access the <img> element being hovered.

    function hoverPokeball(event) {
        event.target.src = 'src/images/pokeballMid.png';
    }
    function unhoverPokeball(event) {
        event.target.src = 'src/images/pokeballOpen.png';
    }
    
    Login or Signup to reply.
  2. The functions hoverPokeball and unhoverPokeball are not defined in the same scope as the card variable, and can therefore not reference it. I presume you get a ReferenceError.

    There are multiple ways to reference the (un-)hovered element in its listener:

    Passing the event object

    You can pass the event object to the listener (or rather, expect it). Its currentTarget property will refer to the respective card.

    Example:

    for (let i = 0; i < cardArray.length; ++i) {
      const card = document.createElement("img");
      // ...
      card.addEventListener("mouseover", hoverPokeball);
      card.addEventListener("mouseout", unhoverPokeball);
      // ...
    }
    
    // ...
    
    function hoverPokeball(event) {
      event.currentTarget/*...*/;
    }
    function hoverPokeball(event) {
      event.currentTarget/*...*/;
    }
    

    Sidenote:

    The target property refers to the the target from which the event is dispatched. The currentTarget property refers to the currently listening target, often a child of the dispatching target.

    In this case, card refers to an empty element; more specifically, to the void element <img>. Such elements do not have children, so the currentTarget and target properties will refer to the same target.

    You should prefer the currentTarget and target properties for the concepts of referring to the currently listening target and the dispatching target, respectively.

    In this case, we want to refer to card (the element to which we added the listener), so we should use the currentTarget property. It just so happens that card will always be the dispatching target as well due to it being an empty element.

    Passing the reference

    Similarly, you can pass the reference card to the functions. This requires some kind of closure for the specific reference, e.g. by using an anonymous function defined in the respective iteration or binding the reference as an argument.

    Example of binding as an argument:

    for (let i = 0; i < cardArray.length; ++i) {
      const card = document.createElement("img");
      // ...
      card.addEventListener("mouseover", hoverPokeball.bind(null, card));
      card.addEventListener("mouseout", unhoverPokeball.bind(null, card));
      // ...
    }
    
    // ...
    
    function hoverPokeball(card) {
      // ...
    }
    function hoverPokeball(card) {
      // ...
    }
    

    Using this in listeners

    In listeners, this is bound to refer to the listening target. You can use this for the listening target, since the respective card is that event target.

    Example:

    for (let i = 0; i < cardArray.length; ++i) {
      const card = document.createElement("img");
      // ...
      card.addEventListener("mouseover", hoverPokeball);
      card.addEventListener("mouseout", unhoverPokeball);
      // ...
    }
    
    // ...
    
    function hoverPokeball() {
      this/*...*/;
    }
    function hoverPokeball() {
      this/*...*/;
    }
    

    Note: You cannot bind a this context to arrow function expressions. This means that hoverPokeball and unhoverPokeball have to be defined as function declarations or function expressions for this to work. Read more in MDN’s section about this in handlers.


    Alternatively, you can query for the element in the functions, e.g. by their data-id attribute.

    Generally, I would recommend to use event delegation for a task like this.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search