DEV Community

Cover image for Bind to Dynamically Added Elements with jQuery
nightwolfdev
nightwolfdev

Posted on • Originally published at nightwolf.dev

Bind to Dynamically Added Elements with jQuery

jQuery makes it pretty easy to bind to events for elements that are already present when the page loads. What if new elements are added after the page loads? How do you bind to dynamically added elements? Let’s learn how!

Table Example

Let’s say we have a table that has three columns:

  • First Name
  • Last Name
  • Action

In the Action column, there will be a Remove button with a class called remove.

<table>
  <thead>
    <tr>
      <th>First Name</th>
      <th>Last Name</th>
      <th>Action</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Jesse</td>
      <td>Pinkman</td>
      <td><button type="button" class="remove">Remove</button></td>
    </tr>
    <tr>
      <td>Saul</td>
      <td>Goodman</td>
      <td><button type="button" class="remove">Remove</button></td>
    </tr>
    <tr>
      <td>Gus</td>
      <td>Fring</td>
      <td><button type="button" class="remove">Remove</button></td>
    </tr>
  </tbody>
</table>
Enter fullscreen mode Exit fullscreen mode

Under the table, there will be an Add button with an id called add.

<button type="button" id="add">Add</button>
Enter fullscreen mode Exit fullscreen mode

Bind To Existing Elements

Before we can do anything, we have to make sure the page has actually finished loading.

$(function() {
  // Do stuff now that the page has finished loading
});
Enter fullscreen mode Exit fullscreen mode

When the Remove button is clicked, we want to remove the respective row. First, we have to select all Remove buttons. We can do this by looking for the remove class we put on each button.

$('.remove')
Enter fullscreen mode Exit fullscreen mode

Now let’s create an event listener and run a function called onRemove when the click event happens.

$(function() {
  $('.remove').on('click', onRemove);
});
Enter fullscreen mode Exit fullscreen mode

Take another look at where the button is in the DOM tree. It’s inside a <td> element, which is inside a <tr> element.

<tr>
  <td>
    <button type="button" class="remove">Remove</button>
  </td>
</tr>
Enter fullscreen mode Exit fullscreen mode

So if we wanted to remove the row (<tr>), we’d have to traverse up two elements in the DOM tree. jQuery makes this easy using the parent and remove methods.

Let’s create that onRemove function that will run when the click happens on any Remove button. The this keyword represents the respective button element that was clicked. If we wrap it in the jQuery selector, we’ll be able to use any of the jQuery methods. We want to move up two elements in the DOM tree, so let’s call parent twice and then call the remove method to remove the row!

function onRemove() {
  $(this).parent().parent().remove();
}
Enter fullscreen mode Exit fullscreen mode

Bind To Dynamically Added Elements

Remember that Add button under the table? We want to add a new row when it’s clicked. First, we have to select the Add button. We can do this by looking for the id of add we put on the button.

$('#add')
Enter fullscreen mode Exit fullscreen mode

Now let’s create an event listener and run a function called onAdd when the click event happens.

$(function() {
  $('#add').on('click', onAdd);
  $('.remove').on('click', onRemove);
});
Enter fullscreen mode Exit fullscreen mode

Let’s create that onAdd function that will run when the click happens on the Add button. We select the table and append a new row of html to it.

function onAdd() {
  $('table').append('<tr><td>Walter</td><td>White</td><td><button type="button" class="remove">Remove</button></td></tr>');
}
Enter fullscreen mode Exit fullscreen mode

If you try clicking on the Remove button on the newly added row nothing happens! That’s because we told jQuery to listen for click events on Remove buttons that were on the page already. We need to change that to listen for click events whether they were on the page already or added after the fact!

Let’s listen to the entire document for clicks on the remove class and run the onRemove function.

$(document).on('click', '.remove', onRemove);
Enter fullscreen mode Exit fullscreen mode

Now try clicking on the Remove button on a newly added row. The row is successfully removed!

By the way, you don’t have to select the entire document. You can narrow the search down to a parent container, which would be more efficient. For example, maybe add an id to the table called list. Then select the list id instead of the whole document.

$('#list').on('click', '.remove', onRemove);
Enter fullscreen mode Exit fullscreen mode

CodePen Example


Visit our website at https://nightwolf.dev and follow us on Facebook and Twitter

Discussion (4)

Collapse
lukeshiru profile image
Luke Shiru

Using vanilla JS, you can do this:

const tbody = document.querySelector("tbody");

tbody.addEventListener("click", ({ target }) =>
    target.classList.contains("remove")
        ? target.parentElement.parentElement.remove()
        : undefined,
);

document.querySelector("#add").addEventListener("click", () =>
    tbody.appendChild(
        Object.assign(document.createElement("tr"), {
            innerHTML: `
                <td>Walter</td>
                <td>White</td>
                <td>
                    <button type="button" class="btn btn-danger remove">Remove</button>
                </td>
            `,
        }),
    ),
);
Enter fullscreen mode Exit fullscreen mode

You could also just add the listener to the button itself when you add it:

const tbody = document.querySelector("tbody");

tbody.addEventListener("click", ({ target }) =>
    target.classList.contains("remove")
        ? target.parentElement.parentElement.remove()
        : undefined,
);

document.querySelector("#add").addEventListener("click", () => {
    const tr = Object.assign(document.createElement("tr"), {
        innerHTML: `
            <td>Walter</td>
            <td>White</td>
            <td></td>
        `,
    });
    const removeButton = Object.assign(document.createElement("button"), {
        className: "btn btn-danger remove",
        onclick: () => tr.remove(),
        textContent: "Remove",
    });

    tr.querySelector("td:last-child").appendChild(removeButton);

    tbody.appendChild(tr);
});
Enter fullscreen mode Exit fullscreen mode

Cheers!

Collapse
nightwolfdev profile image
nightwolfdev Author

Thanks! This was an example if jQuery was in use.

Collapse
jonrandy profile image
Jon Randy

You haven't actually binded to the new elements at all, rather you are using event delegation to handle the events further up - via event bubbling/propagation. No binding changes

Collapse
nightwolfdev profile image
nightwolfdev Author

Handle events might have been better than saying bind. Thanks!