0

I want to created bind event with all elements which will be generated dinamically.

Look at this code:

$('body').on('click', '.comment', () => { alert('Hello World'); });

It works only for first element. For example - if I click on the first comment, alert will display, but if I click in another it doesn't.

`const comments = document.querySelectorAll('.comment');

comments.forEach((comment) => {


    comment.addEventListener('click', (e) => {

      alert('Hello World');
    })

})

` OK. It works, but we have a loop here and I won't use it in this way becouse I have more complicated logic than display alert and this code crashed sometimes.So the first way will be the best for me but it works only for first element. Any idea?

Hellodas33
  • 13
  • 1
  • 1
    [How to create a Minimal, Reproducible Example](https://stackoverflow.com/help/minimal-reproducible-example) – ericmp Dec 20 '22 at 12:50
  • 1
    *"It works only for first element."* - I'm not able to replicate this behavior. Can you produce an example which does? – David Dec 20 '22 at 12:55
  • `$('body').on('click', '.comment', () => {` does work for dynamicly added elements – Carsten Løvbo Andersen Dec 20 '22 at 12:55
  • This answer provides additional details which may help: [Event Binding on Dynamically Created Elements](https://stackoverflow.com/questions/203198/event-binding-on-dynamically-created-elements) – freedomn-m Dec 20 '22 at 13:26

1 Answers1

1

Delegated events

Use event delegation, usually from a static parent:

document.querySelector("#allComments").addEventListener("click", (evt) => {

  const elTarget = evt.target.closest(".comment");
  if ( !elTarget  ) return; // do nothing.

  // Do something with elTarget  here
});

Basically follow this rules:

  • To get the #allComments parent delegator use evt.currentTarget
  • To get the exact clicked Element use evt.target (Attention! This might also be a .comment's child element)
  • To get the desired clicked .comment element use evt.target.closest(".comment")

Full example with dynamic elements:

// DOM utility functions:

const el = (sel, par) => (par || document).querySelector(sel);
const elNew = (tag, prop) => Object.assign(document.createElement(tag), prop);


// Delegated events
el("#comments").addEventListener("click", (evt) => {
  const elTarget = evt.target.closest(".comment");
  if (!elTarget) return; // Do nothing.
  // Else, do something:
  console.log(elTarget.textContent);
});

// Add dynamic child elements
el("#add").addEventListener("click", () => {
  el("#comments").append(elNew("div", {
    className: "comment",
    textContent: "Click me! " + Date.now()
  }))
});
<div id="comments"></div>
<button type="button" id="add">Add new</button>

Direct events

Alternatively, you could attach a click handler directly on the child - on creation:

// DOM utility functions:

const el = (sel, par) => (par || document).querySelector(sel);
const elNew = (tag, prop) => Object.assign(document.createElement(tag), prop);

// Create new comment with Direct events:
const newComment = (text) => elNew("div", {
  className: "comment",
  textContent: text,
  onclick() {
    console.log(this.textContent);
  },
});

// 
el("#add").addEventListener("click", () => {
  el("#comments").append(newComment("Click me! "+ Date.now()))
});
<div id="comments"></div>
<button type="button" id="add">Add new</button>

Resources:

Roko C. Buljan
  • 196,159
  • 39
  • 305
  • 313