1

Im trying to do homework assignment and confused why I'm getting error message(undefined is not an object (evaluating 'buttons[i].style')) any help appreciated Ive been trying to loop through the buttons array and add an Event Listener to each item in the list

var buttons = document.getElementsByClassName("quality");
for(var i = 0; i < buttons.length; i += 1){
buttons[i].addEventListener('click', function (i) {
    buttons[i].style.background = "red";
});
}



<!doctype html>

<html>
<head>
 <title>L.A. Hiking</title>
 <link rel="stylesheet" href="css/hiking.css">
 </head>

<ul id = "navbar">
    <li><a href="index.html" class= "selected">Home</a></li>
    <li><a href="contact.html">Contact</a></li>
    <li><a href="about.html">About</a></li>
</ul>
<body>

<div>
    <div class="blocks" id="selections">
        <ul id= "attr1">
            <li class="Instruction">Pick one:</li>
            <li class ="quality">Hard</li>
            <li class ="quality">Medium</li>
            <li class ="quality">Easy</li>
        </ul>

        <ul id = "attr2">
            <li class="Instruction">Pick one:</li>
            <li class ="quality">Hard</li>
            <li class ="quality">Medium</li>
            <li class ="quality">Easy</li>
        </ul>

        <ul id = "attr3">
            <li class="Instruction">Pick one:</li>
            <li class ="quality">Hard</li>
            <li class ="quality">Medium</li>
            <li class ="quality">Easy</li>
        </ul>
    </div>  
    <div class="blocks" id="results">
        <ul id = "choices">
            <li class="choice">Pick one:</li>
            <li class ="choice">Hard</li>
            <li class ="choice">Medium</li>
        </ul>
    </div>
</div>
<div id="button-container">
    <button>Go!</button>
</div>

<script src="javascript/hiking.js"></script>
</body>
</html>
Chris Wallace
  • 81
  • 2
  • 7

3 Answers3

1

The callback for addEventListener doesn't give you the index of the button clicked but an event object. You can then access the button using event.target:

for(var i = 0; i < buttons.length; i += 1){
    buttons[i].addEventListener('click', function (e) {
        e.target.style.background = "red";
    });
}

As per @Sgnl:

since you are binding to the event to the object itself you could also use context aka this so e.target.style.background = "red"; becomes this.style.background = "red";

for(var i = 0; i < buttons.length; i += 1){
    buttons[i].addEventListener('click', function () {
        this.style.background = "red";
    });
}
Community
  • 1
  • 1
Nelson Yeung
  • 3,262
  • 3
  • 19
  • 29
  • Also, since you are binding to the event to the object itself you could also use context aka `this` so `e.target.style.background = "red";` becomes `this.style.background = "red";` – Sgnl Jan 15 '17 at 02:13
  • This PhD guy nailed it, he saved my bus seater array –  Aug 17 '21 at 12:50
0
  1. document.getElementsByClassName("quality"); returns the collection of all the elements matching the class name quality in a NodeList object. From the code you posted, it seems that you are having the listitem and not the button element for the quality class name.

  2. More importantly, the addEventListener callback would pass in the event information in the parameter to the callback. The property event.target returns the element on which the event was registered, which in this case is the listItem[i]. So, you need to use the e.target as e.target.style.background = "red";

var listItems = document.getElementsByClassName("quality");
for(var i = 0; i < listItems.length; i += 1){
listItems[i].addEventListener('click', function (e) {
    e.target.style.background = "red";
});
}
<html>
<head>
 <title>L.A. Hiking</title>
 <link rel="stylesheet" href="css/hiking.css">
 </head>

<ul id = "navbar">
    <li><a href="index.html" class= "selected">Home</a></li>
    <li><a href="contact.html">Contact</a></li>
    <li><a href="about.html">About</a></li>
</ul>
<body>

<div>
    <div class="blocks" id="selections">
        <ul id= "attr1">
            <li class="Instruction">Pick one:</li>
            <li class ="quality">Hard</li>
            <li class ="quality">Medium</li>
            <li class ="quality">Easy</li>
        </ul>

        <ul id = "attr2">
            <li class="Instruction">Pick one:</li>
            <li class ="quality">Hard</li>
            <li class ="quality">Medium</li>
            <li class ="quality">Easy</li>
        </ul>

        <ul id = "attr3">
            <li class="Instruction">Pick one:</li>
            <li class ="quality">Hard</li>
            <li class ="quality">Medium</li>
            <li class ="quality">Easy</li>
        </ul>
    </div>  
    <div class="blocks" id="results">
        <ul id = "choices">
            <li class="choice">Pick one:</li>
            <li class ="choice">Hard</li>
            <li class ="choice">Medium</li>
        </ul>
    </div>
</div>
<div id="button-container">
    <button>Go!</button>
</div>

<script src="javascript/hiking.js"></script>
</body>
</html>
Abhinav Galodha
  • 9,293
  • 2
  • 31
  • 41
  • Also, since you are binding to the event to the object itself you could also use context aka `this` so e.target.style.background = "red"; becomes this.style.background = "red"; – Sgnl Jan 15 '17 at 02:29
0

In addition to everyone suggesting attaching an event to each li.quality element, you could also consider this pattern.

You can attach one event to the parent element (instead of having an event listener for each li.quality element) by taking advantage of Event Bubbling (see SO post here).

let selectionsElement = document.querySelector('#selections');

selectionsElement.addEventListener('click', function(event) {
  // stop event from bubbling further up the DOM tree
  event.stopPropagation();
  
  /*
    the `this` keyword will refer to the #selections element
    so we can't use it with this approach so we'll have to use `event`
  */
  
  // check if the element which triggered the event is li.quality
  if (event.target.classList.contains('quality')) {
    event.target.style.backgroundColor = 'red';
  }
});
<html>
<head>
 <title>L.A. Hiking</title>
 <link rel="stylesheet" href="css/hiking.css">
 </head>

<ul id = "navbar">
    <li><a href="index.html" class= "selected">Home</a></li>
    <li><a href="contact.html">Contact</a></li>
    <li><a href="about.html">About</a></li>
</ul>
<body>

<div>
    <div class="blocks" id="selections">
        <ul id= "attr1">
            <li class="Instruction">Pick one:</li>
            <li class ="quality">Hard</li>
            <li class ="quality">Medium</li>
            <li class ="quality">Easy</li>
        </ul>

        <ul id = "attr2">
            <li class="Instruction">Pick one:</li>
            <li class ="quality">Hard</li>
            <li class ="quality">Medium</li>
            <li class ="quality">Easy</li>
        </ul>

        <ul id = "attr3">
            <li class="Instruction">Pick one:</li>
            <li class ="quality">Hard</li>
            <li class ="quality">Medium</li>
            <li class ="quality">Easy</li>
        </ul>
    </div>  
    <div class="blocks" id="results">
        <ul id = "choices">
            <li class="choice">Pick one:</li>
            <li class ="choice">Hard</li>
            <li class ="choice">Medium</li>
        </ul>
    </div>
</div>
<div id="button-container">
    <button>Go!</button>
</div>

<script src="javascript/hiking.js"></script>
</body>
</html>
Community
  • 1
  • 1
Sgnl
  • 1,808
  • 22
  • 30