-1

Edit: This question is similar to others (as commented by @jonathan-lonowski), regarding how to attach event handlers to dynamically created elements. However, my problem was that I didn't perceive that part of how event handlers are being bound to specific elements at one time during script execution - rather I thought of the event handlers as listening to all events, independent of the elements. Not knowing the root of the problem, I also didn't know what terms to search by. In retrospect, I see the other questions regard the same problem.

I am struggeling to understand why jQuery won't handle a class-directed event, unless the event handler is placed inside another event handler.

This code below is inspired from the jQuery course on sololearn.com, but no explaination is given there of why the click-on-remove-button event handler is placed within the click-on-add-button event handler.

When I try to move the event handler block for the remove-button-class-click, so as to stand before or after the event handler block for the add-button-click, there's no response upon clicking a remove-button.

I suspected it failed to work because :this didn't refer to the correct object. But from experimenting with alert(), it seems to me that :this is refering to the select-action context which fires the anonymous function, and it shouldn't matter where the event handler i placed within the root $(function(){}); clause.

Maybe I am missing something obvious? I am new to jQuery, but the logic of the event handling doesn't seem clear to me. The tutorials that I've been to don't give me the answer. Thanks!

HTML part:

<html>
<head>
    <title>My To-Do List</title>
    <script src="https://code.jquery.com/jquery-3.1.1.js"></script>
</head>
<body>
    <div width="500px">
        <h1>My To-Do List</h1>
        <p>
            <input id="value" type="text" placeholder="New Item" autofocus />
            <button type="button" id="btn_add" class="action" name="add_btn">Add</button>
        </p>
        <p>
            <ol id="my_list">
                <!-- list-items get dynamically added here -->
            </ol>
        </p>
    </div>
</body>
</html>

JS part:

$(document).ready(function(){

$("#btn_add").on("click", function(){
    var val = $("#value").val();

    if (val !== "") {
        var new_e = $("<li></li>").text(val);
        $(new_e).append("<button class='rem' name='rem_btn'>X</button>");
        $("#my_list").append(new_e);
        $("#value").val("");

        $(".rem").on("click", function(){
            $(this).parent().remove();
        });

    }

});

});
  • I just responded to your answer @zer00ne ... the point was, why it had to be like this to work. – user1432846 Jan 08 '17 at 06:57
  • [Event binding on dynamically created elements?](https://stackoverflow.com/questions/203198/event-binding-on-dynamically-created-elements) – [Click event doesn't work on dynamically generated elements](https://stackoverflow.com/questions/6658752/click-event-doesnt-work-on-dynamically-generated-elements) – Jonathan Lonowski Jan 08 '17 at 08:07

1 Answers1

0

For any DOM event listener we must specify the element. SO we use .ready to ensure that DOM is rendered and we have that elements for which we want to bind events are rendered.

And coming to

but no explaination is given there of why the click-on-remove-button event handler is placed within the click-on-add-button event handler.

Since your dynamic elements are created only after click-on-add-button. So we are not writing an event handler for non-existing DOM elements (click-on-remove-button)

If you dont want write that in condition, just write this

$(document).on("click", ".rem", function() {
  $(this).parent().remove();
});

This will bind click listener to .rem elements in DOM. Since you are creating .rem element dynamically you need to bind that event on document and specific the selector.

$(document).ready(function() {

  $("#btn_add").on("click", function() {
    var val = $("#value").val();

    if (val !== "") {
      var new_e = $("<li></li>").text(val);
      $(new_e).append("<button class='rem' name='rem_btn'>X</button>");
      $("#my_list").append(new_e);
      $("#value").val("");
    }

  });

});

$(document).on("click", ".rem", function() {
  $(this).parent().remove();
});
<html>

<head>
  <title>My To-Do List</title>
  <script src="https://code.jquery.com/jquery-3.1.1.js"></script>
</head>

<body>
  <div width="500px">
    <h1>My To-Do List</h1>
    <p>
      <input id="value" type="text" placeholder="New Item" autofocus />
      <button type="button" id="btn_add" class="action" name="add_btn">Add</button>
    </p>
    <p>
      <ol id="my_list">
        <!-- list-items get dynamically added here -->
      </ol>
    </p>
  </div>
</body>

</html>

That you say that you bind 'listeners' to element clarify the issue a bit.

Let me explain with an example

Consider html

<a id="anchor">Element</a>

Pure JavaScript:

function someListener(event){
  console.log(event.target); //prints anchor element
}

document.getElementById("anchor").addEventListener('click', someListener); //event listener binded to anchor element

With Jquery:

$("#anchor").click(someListener); //same here binding click event listener for anchor element.

Here DOM element is <a />, and listener for click event is someListener.

In both the cases if we don't have anchor element in DOM. It raises exception. So make sure that element exists in DOM before binding an event listener for it.

Jyothi Babu Araja
  • 10,076
  • 3
  • 31
  • 38
  • What is the difference between your code and the OP's code? Besides this: `$(document).on("click", ".rem", function() {` vs. `$(document).on("click", function() {`? – zer00ne Jan 08 '17 at 06:34
  • That you say that you bind 'listeners' to element clarify the issue a bit. I thoght the event handlers where listeners independent of any actual elements in the DOM - just sitting there, so to speak. So, when you listen for any click-event on the document level, then you can bind the event handler to the 'rem' button class, if any? I didn't know that the jQuery.on() method could take three parameters, but I see that it works. Very cool that you posted your answer so that I could run the code and test it. :) – user1432846 Jan 08 '17 at 06:35
  • @zer00ne Instead of writing `listener` every time we have `click` on `button`. Since it's a class we can write it outside for dynamically created `DOM` elements. – Jyothi Babu Araja Jan 08 '17 at 07:47
  • @user1432846, Updated answer to address your question – Jyothi Babu Araja Jan 08 '17 at 08:03
  • @jyothi-babu-araja It seems to me like a strategy could be to add event handlers on the document level, and branch to different event handlers after that? – user1432846 Jan 08 '17 at 08:18
  • Not that in every case. We will bind to `document` when elements are created dynamically say with javascript. If we are sure that we have element rendered in `DOM` then we can directly bind to it. – Jyothi Babu Araja Jan 08 '17 at 08:20