'Element is not triggered by change

The initial situation is an HTML table with two rows. A button can be used to add further rows via jquery. Interestingly, the newly added rows do not respond to .change(). Do you have any idea why?

<table>
    <thead>
        <tr>
            <th>Id</th>
            <th>Firstname</th>
            <th>Lastname</th>
            <th>Street</th>
            <th>City</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><input type="number" class="id"></td>
            <td><input type="text" class="firstname"></td>
            <td><input type="text" class="lastname"></td>
            <td><input type="text" class="street"></td>
            <td><input type="text" class="city"></td>
        </tr>
        <tr>
            <td><input type="number" class="id"></td>
            <td><input type="text" class="firstname"></td>
            <td><input type="text" class="lastname"></td>
            <td><input type="text" class="street"></td>
            <td><input type="text" class="city"></td>
        </tr>
    </tbody>
</table>
<button id="addItem">Add Item</button>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script>
    $("#addItem").click(function() {
        $('table tbody tr:last').after('  <tr>\n' +
            '            <td><input type="number" class="id"></td>\n' +
            '            <td><input type="text" class="firstname"></td>\n' +
            '            <td><input type="text" class="lastname"></td>\n' +
            '            <td><input type="text" class="street"></td>\n' +
            '            <td><input type="text" class="city"></td>\n' +
            '        </tr>');
    });

    $(".id").change(function () {
        console.log("changed")
    })
</script>


Solution 1:[1]

you should try using this code

$(document).on('change', 'elementSelector', callback);

element selector here is the rows. callback is the function that you want to run whenever the rows changes. It didn't work because the rows that you just made using jquery is was not on the dom when the jquery is initialized I guess.

Solution 2:[2]

There are two primary ways to address this.

  1. Assign Change Callback to the Element after it has been created / appended
  2. Delegate the change event using .on() to dynamic elements

Here is an example of each. First standard .change() assignment.

$(function() {
  function log(str) {
    console.log(str);
  }

  $("#addItem").click(function() {
    var target = $("table tbody");
    var row = $("<tr>").appendTo(target);
    var cells = [{
      type: "number",
      class: "id"
    }, {
      type: "text",
      class: "firstname"
    }, {
      type: "text",
      class: "lastname"
    }, {
      type: "text",
      class: "street"
    }, {
      type: "text",
      class: "city"
    }];
    $.each(cells, function(i, p) {
      $("<td>").appendTo(row);
      $("<input>", p).appendTo($("td", row).eq(i));
    });
    $("input:eq(0)", row).change(function(event) {
      console.log("Input Changed, row: " + row.index() + ", column: " + $(this).index() + ", New Value: " + $(this).val());
    });
  });

  $(".id").change(function() {
    console.log("Input Changed, row: " + $(this).closest("tr").index() + ", column: " + $(this).index() + ", New Value: " + $(this).val());
  })
});
<table>
  <thead>
    <tr>
      <th>Id</th>
      <th>Firstname</th>
      <th>Lastname</th>
      <th>Street</th>
      <th>City</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><input type="number" class="id"></td>
      <td><input type="text" class="firstname"></td>
      <td><input type="text" class="lastname"></td>
      <td><input type="text" class="street"></td>
      <td><input type="text" class="city"></td>
    </tr>
    <tr>
      <td><input type="number" class="id"></td>
      <td><input type="text" class="firstname"></td>
      <td><input type="text" class="lastname"></td>
      <td><input type="text" class="street"></td>
      <td><input type="text" class="city"></td>
    </tr>
  </tbody>
</table>
<button id="addItem">Add Item</button>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>

Here is a Delegate example.

$(function() {
  function log(str) {
    console.log(str);
  }

  $("#addItem").click(function() {
    var target = $("table tbody");
    var row = $("<tr>").appendTo(target);
    var cells = [{
      type: "number",
      class: "id"
    }, {
      type: "text",
      class: "firstname"
    }, {
      type: "text",
      class: "lastname"
    }, {
      type: "text",
      class: "street"
    }, {
      type: "text",
      class: "city"
    }];
    $.each(cells, function(i, prop) {
      $("<td>").appendTo(row);
      $("<input>", prop).appendTo($("td", row).eq(i));
    })
  });

  $("table > tbody").on("change", ".id", function(event) {
    console.log("Input Changed, row: " + $(this).closest("tr").index() + ", column: " + $(this).index() + ", New Value: " + $(this).val());
  });
});
<table>
  <thead>
    <tr>
      <th>Id</th>
      <th>Firstname</th>
      <th>Lastname</th>
      <th>Street</th>
      <th>City</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><input type="number" class="id"></td>
      <td><input type="text" class="firstname"></td>
      <td><input type="text" class="lastname"></td>
      <td><input type="text" class="street"></td>
      <td><input type="text" class="city"></td>
    </tr>
    <tr>
      <td><input type="number" class="id"></td>
      <td><input type="text" class="firstname"></td>
      <td><input type="text" class="lastname"></td>
      <td><input type="text" class="street"></td>
      <td><input type="text" class="city"></td>
    </tr>
  </tbody>
</table>
<button id="addItem">Add Item</button>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>

They each result in the same action. You can see that is a bit less code in the Delegate method.

In the end, it is your call which method you choose to use.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Phiard
Solution 2 Twisty