Attaching an Event Listener to an array

I am struggling with a homework assignment and don't understand why I am receiving an error message saying 'undefined is not an object (evaluating 'buttons[i].style')). Any help would be appreciated. I have been attempting 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>

Answer №1

When using the addEventListener method, you receive an event object as a callback instead of the index of the button clicked. To access the specific button clicked, you can use event.target:

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

As mentioned by @Sgnl:

If you are binding the event directly to the object itself, you can also utilize context (this) instead of e.target, like so: this.style.background = "red";

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

Answer №2

  1. document.getElementsByClassName("quality");
    retrieves all elements that match the class name quality in a NodeList. Based on your code snippet, it appears that you are targeting the listitem instead of the button element with the quality class.

  2. Furthermore, the callback function for addEventListener receives event information as a parameter. The property event.target points to the element where the event was triggered, which is the listItem[i] in this scenario. Therefore, you should utilize e.target like so:

    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>

Answer №3

Another approach to handling event attachment on li.quality elements is by utilizing a different pattern.

Rather than assigning individual event listeners to each li.quality element, you can opt for adding a single event listener to the parent element and leverage Event Bubbling (check out this SO post for more information).

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

selectionsElement.addEventListener('click', function(event) {
  // stop event from bubbling further up the DOM tree
  event.stopPropagation();
  
  /*
    With this method, the `this` keyword refers to the #selections element,
    so we need to use `event` in place of it.
  */
  
  // Check if the triggering element 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>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Can the operator pipeline generate interim observables in a manner akin to how filter, map, and reduce generate interim arrays?

I need some clarification regarding the efficiency of operator pipelines in RxJS. Based on my current understanding, each operator within the pipeline receives an observable and generates a new (potentially modified) observable to pass on to the next oper ...

Exploring VueJS watchers: How to get started?

Struggling to grasp the concept of Watchers in VueJS, particularly when trying to implement them for tracking tab changes and resetting values. Even though I have set up a watch with parameters like `oldValue` and `newValue`, their usage remains unclear to ...

Exploring the power of D3's nested appends and intricate data flow

Currently diving into the world of D3, I've encountered a perplexing issue that has yet to be resolved. Unsure if my confusion stems from a lack of familiarity with the library or if there's a key procedure eluding me, I feel compelled to seek gu ...

ng-include: Child scope access problem

I am currently facing an issue with my app while using DayPilot Scheduler. home.html: <div class="container-fluid"> <daypilot-scheduler id="scheduler" daypilot-config="schedulerConfig" daypilot-events="events"></daypilot-scheduler> ...

How can you make a dynamic 360 image that responds to mouse movements using three.js?

Is it possible to achieve a three.js effect similar to the one shown here? We have come across solutions that involve drag&drop for camera angle control, but we are interested in having the mouse position dictate where the camera points. For instance, ...

Include the component with the function getStaticProps loaded

I am currently working on a project using NextJs and I have created a component to load dynamic data. The component works fine when accessed via localhost:3000/faq, but I encounter an error when trying to import the same component into index.js. It seems l ...

Is there a way to split the text into distinct pages within a contenteditable area, similar to the functionality in Google Docs

I've been working on developing a specialized browser-based text editor and I've encountered a puzzling question. How can I detect and split long texts into separate pages, similar to how Google Docs handles pagination? I'm aware that Google ...

Leveraging Angular CLI in conjunction with the newest AspNetCore Angular 4 Single Page Application template

I'm currently experimenting with using Angular CLI alongside the latest JavaScriptServices AspNetCore Angular Spa template. In the past, I would simply copy and paste a .angular-cli.json file into my project's root directory, change "root" to "C ...

Guide to emitting a value using the composition API

I'm currently working with a datepicker component that is part of a form in my Vue3 app using the composition API. My challenge is how to pass a value from the datepicker component back up to the form component. Unfortunately, I've encountered ...

Uploading several files with Laravel and Vue JS in one go

Recently, I have been working on a project where I need to upload multiple image files using Vue JS in conjunction with Laravel on the server side. This is the snippet from my Vue template: <input type="file" id = "file" ref="f ...

Execute the validation directive using the digest cycle

This particular directive is designed to determine whether a given value exists within the associated datalist or not. It functions flawlessly when I input text into the field, but it fails to work properly if the datalist undergoes changes as a result o ...

Implement the useEffect() function to handle the loading of external JavaScript on the client-side, replicating the

I have encountered a challenge while trying to integrate a rich text editor into my NextJS project. Since there are no available React components for this specific editor and it operates solely on the client side, I am required to load the necessary JavaSc ...

One the year is chosen, it will be automatically hidden and no longer available for selection

<div ng-repeat="localcost in vm.project.localCosts" layout="column"> <md-select name="localcost_{{$index}}"ng-model="localcost.year" flex> <md-option ng-repeat="years in vm.getYears()" ng-value="years">{{years}}< ...

Generating a hyperlink to a specific user ID within a data table

I'm facing an issue with the formatting of my simple table when trying to navigate to user.id. Is there a better approach to this or should I consider moving LinkToUser? All styling has been removed to avoid any conflicts. import styled from 'st ...

Retrieve the $$state value from the Service Function

I am new to Angular and struggling to understand a function in my service. I have this code snippet: checkRoomNameStatus: function() { var promises = []; var emptyRooms = []; DatabaseService.openDB().transaction(function(tx) { tx.exec ...

Utilizing Django to access a JavaScript variable within server-side template code

I am faced with a challenge on a page that dynamically adds textboxes. In order to access the relevant context variable within these dynamically added text boxes, I need to utilize the 'i' variable in both my javascript and template code. Specifi ...

Unit testing promises in Angular using Jasmine

My goal is to create a unit test that demonstrates the process of combining two promises using $q.all in Angular, and then confirming that both promises are resolved simultaneously. describe("Application controller", function() { var scope; var ...

Server time dictates the operation of Moment.js

I've been working with Moment.js and it's functioning correctly, but I can't seem to figure out how to make it run on server time instead of local time. I've tried a few things, but haven't had any luck. I'm unsure of how to ...

The MongoDB .push operation is returning a null value

Take a look at the GitHub repository where I am actively working: https://github.com/Stick-z/first-media-app I'm currently in the process of creating a website and focusing on the backend development. One of my tasks involves setting up a jokes array ...

Utilize linear gradient effect in editing images and then convert them to base64 format using React

I have been working with the "canvas" library to edit an image via URL using linear-gradient, employing various methods. However, I am facing challenges in achieving the desired results so far. The methods I tried using canvas do not seem to work seamless ...