What is the best way to attach a click event listener to dynamically generated child elements?

My parent container houses a variable number of elements generated by an API as the user inputs text. These elements, in turn, serve as parents to other child elements.

The goal is for an overlay with more details about a specific element to appear when the user clicks on it. Although this sounds straightforward, my attempts have been unsuccessful thus far.

I experimented with adding an event listener to the container using the following basic HTML template:

<ul>
  <li><span>Item 1</span><span>X</span></li>
  <li><span>Item 2</span><span>X</span></li>
  <li><span>Item 3</span><span>X</span></li>
  <li><span>Item 4</span><span>X</span></li>
</ul>

<form>
  <input type="text" id="test">
</form>

In this example, the UL serves as the parent element with LI elements as its children. However, the LI elements also act as parents to essential span tags displaying crucial information, making their removal impossible. The input field allows dynamic additions to simulate the API's behavior.

Despite trying to attach an event listener to the UL parent >>

 const items = ul.querySelectorAll('li');
items.forEach(item => item.addEventListener('click', function(e) {
console.log(this);
}));
});
});

I then attempted to add an event listener to each individual item but encountered a logging issue where clicking on one item would log multiple consecutive items. It feels like I am overlooking something crucial, and I am unsure of what that might be. Any assistance would be greatly appreciated!

Later edit: While I discovered a solution, it seems inelegant and susceptible to bugs if future changes are made (such as adding more children).

ul.addEventListener('click', e => {
const items = ul.querySelectorAll('li');
if(e.target.tagName === 'LI' || e.target.parentElement.tagName === 'LI') {
if(e.target.tagName === 'LI') {
e.target.remove();
} else if(e.target.parentElement.tagName === 'LI') {
e.target.parentElement.remove();
}
}
});

Answer №1

If you want to locate a parent element, the Element.closest() function can be helpful.

const ul = document.querySelector('ul');

ul.addEventListener('click', e => {
  let li = e.target.closest('LI');
  li.remove();
});

document.forms.newitem.addEventListener('submit', e => {
  e.preventDefault();
  let newitem = document.createElement('LI');
  newitem.innerText = e.target.test.value;
  ul.appendChild(newitem);
});
<ul>
  <li><span>Item 1</span><span>X</span></li>
  <li><span>Item 2</span><span>X</span></li>
  <li><span>Item 3</span><span><em>X</em></span></li>
  <li>Item 4 X</li>
</ul>

<form name="newitem">
  <input type="text" name="test">
</form>

Answer №2

If you are wondering why you keep getting events triggered every time you click on a line, it may be because you have added a click event to the ul element instead of the li element.

A simple solution would be:

let ul = document.querySelector("ul");

const items = ul.querySelectorAll("li");
items.forEach((item) =>
  item.addEventListener("click", function (e) {
    let getTargetRow = e.target.parentElement;
    if (getTargetRow.nodeName === "LI"){ 
     console.log("the line removed:",getTargetRow.textContent);
     getTargetRow.remove();
    }
  })
);
<ul>
    <li><span>Item 1</span><span>X</span></li>
    <li><span>Item 2</span><span>X</span></li>
    <li><span>Item 3</span><span>X</span></li>
    <li><span>Item 4</span><span>X</span></li>
  </ul>

  <form>
    <input type="text" id="test" />
  </form>

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

Angular FirebaseError Permissions Not Found or Inadequate

I'm encountering an issue with permissions while trying to enable users to read and write their own data using Firestore. Despite having set up the rules in my Firestore database, I keep receiving an insufficient permissions error. The rules I have i ...

Guide on displaying additional text fields in PHP with the use of the FOREACH statement

I have created a script that allows me to dynamically add and remove input text fields using container properties. This enables me to create multiple individual blocks for these input fields. $(function(){ $('.container > a').click(functi ...

Tips for utilizing the Hook API design pattern

I'm currently learning how to customize Material UI components. The tutorial provides the following Hook API code: import React from 'react'; import { makeStyles } from '@material-ui/core/styles'; import Button from '@materia ...

How to retrieve text values across various browsers using Vue.js

Whenever I type something in a text box, it displays the text value based on its ID. This code works perfectly when running it on my laptop at http://localhost:8080/. If I open the same website on my phone at http://xxx.xxx.x.xxx:8080/, it shows the same ...

Detecting click events in D3 for multiple SVG elements within a single webpage

My webpage includes two SVG images inserted using D3.js. I am able to add click events to the SVGs that are directly appended to the body. However, I have encountered an issue with another "floating" div positioned above the first SVG, where I append a dif ...

Issue: Attempting to access the `userName` property on an undefined object (`tem`), resulting in a TypeError while using flalist

A concern has arisen with the React Native Flatlist as it fails to render properly. What steps should be taken in this scenario? Below is the code snippet for reference: Image description available here import React, {useState, useEffect} from 'react ...

Newly inserted table columns aren't compatible with event listeners

My HTML table structure varies depending on the content of the uploaded CSV file. I have integrated a plugin called Dragtable to make the table columns draggable. Additionally, I have implemented methods to add rows and columns. Here is an example of the a ...

Numerous occurrences of Autodesk Forge Viewer

I am facing a challenge in implementing multiple instances of the Autodesk Forge Viewer (v6.2) on my webpage, each hidden within tabs. The goal is to show and hide the viewer with a loaded model as the user switches between tabs. Although I have managed ...

Displaying content on the <div> element

Looking for recommendations for a jQuery plugin or JavaScript solution that allows me to load a full "view" into a <div> when a user clicks on a link. The challenge I'm facing is that I have 8 pages, with the Homepage consisting of 3 divisions: ...

Is it possible to interact with Java SE jars using JavaScript?

I need to integrate an API that is written in Java with a Client written in JavaScript. Is there any way to use this API, possibly along with other Java-SE JARs, in Webstorm? Any assistance would be greatly appreciated. Thank you! ...

Issue with submitting a form within a React modal - lack of triggering events

I am utilizing the npm package react-modal (https://www.npmjs.com/package/react-modal) in my project. The issue I am facing is that when I click on 'Submit', nothing happens. The function handleSubmit</a> is not being triggered, as no conso ...

What is the best way to include additional information in yii activeform's ajax parameters?

My goal is to trigger an ajax request when a radio button is clicked. Below is the code I am currently working with: <?php echo $form->dropDownListRow($model, 'page', $pages, array('class' => 'span5', 'prompt&ap ...

Static file serving is malfunctioning

I created a basic node project to work on, but I'm struggling to serve an HTML file with its accompanying CSS styles. Previously, this exact code worked without any issues, but for some reason, it's not functioning now. I've tried searching ...

Navigating to a parent URL where the Angular configuration is set can be achieved by following these steps

My application revolves around a webpage created with the use of node and angular. On the root URL (/), I have incorporated a signup and login form without the use of Angular. Upon successful login, Angular scripts and configuration files are loaded on the ...

What's the trick to efficiently managing multiple checkboxes in an array state?

I have a lengthy collection of checkboxes that is not well optimized. I am trying to obtain the checked ones and store them in an array state. However, I am uncertain about how to handle this situation and I would appreciate some assistance. It should also ...

Include [op.and] in the Sequelize query object

I want to construct my Sequelize query object based on input parameters. It functions well for database keys, as shown in the example below: let query = { where: { id: 5 } } if (inputName) { query['where']['name'] = { nam ...

Choose from the select2 multiselect options and lock certain selected choices from being altered

I have coded a select dropdown with preselected options, some of which I want to keep fixed so that users cannot change them. To achieve this, I implemented the following code: <select id="select2-multiple" name="users" multiple="multiple" style="width ...

Unpacking arguments in Typescript functions

I have a function to update todo items in the database, like this: async function update({id, ...todoInfo }: ITodo) { const db = await makeDb() const foundTodo = await db.collection('todos').updateOne({ _id: transformId(id) }, { $set: { . ...

Enhancing the functionality of an existing framework through the integration of a

My coding style involves a lot of ASP.NET MVC and jQuery, particularly with ajax calls that return json. Lately, I've been tinkering with organizing my code structure by creating an object within the global object which contains success and fail callb ...

Using SVG sprites from external sources alongside child nodes

I am working on a website that contains multiple SVG icons and an SVG logo that need to be animated. To improve readability, I have implemented a sprite system using an external file. For loading the sprites, I am utilizing XMLHttpRequests at the start o ...