Bilel Benamira
Bilel Benamira

Reputation: 33

jQuery : How to get an element by id which has been created in jQuery after DOM ready?

I'm a in the wonderful world of jQuery and today i faced a problem.

I have a list of app that user can select. To select an app they have to click on a button (id="add_app_#{app_id}"). When someone add an app i create a row on a table that list all selected apps. In this row (created in jQuery) there is a button (id="remove_app_#{app_id}") to remove the app from the table.

My issue is that i don't know how to get my remove_app button's click event (certainly because it's added to the DOM after the DOM is ready).

Though, i used .on() jQuery function...

Here is my code:

jQuery(function() {
    $('[id^=add_app_]').click(function() {
        var app_id, version_id;
        version_id = 0;
        app_id = this.getAttribute('data-app_id');

        $("#app_versions_" + app_id + " option:selected").each(function() {
            version_id = $(this).val();
        });

        hide_app_from_selector(app_id);
        display_app_in_table(app_id, version_id);
    });

    $('[id^=remove_app_]').on('click', function() {
        // I NEVER GET HERE !
        var app_id;
        app_id = this.getAttribute('data-app_id');
        remove_app_from_table(app_id);
        display_app_in_selector(app_id);
    });
});

Upvotes: 2

Views: 450

Answers (2)

James Donnelly
James Donnelly

Reputation: 128796

You can use the on() method to assign an event handler to an ancestor of a dynamically created element which exists when the method was first called. What you're doing by simply using $('[id^=remove_app_]').on(...) is assigning the event handler to that element which doesn't exist when called.

To rectify this, find an ancestor of your [id^=remove_app_] element which exists when you first assign the event handler and assign on() to that:

$('body').on('click', '[id^=remove_app_]', function() { ... });

With this particular code, you delegate the event handler to body (which presumably exists prior to calling your on() function) rather than assigning it directly to your dynamically created element. From jQuery's on() documentation:

When a selector is provided, the event handler is referred to as delegated. The handler is not called when the event occurs directly on the bound element, but only for descendants (inner elements) that match the selector. jQuery bubbles the event from the event target up to the element where the handler is attached (i.e., innermost to outermost element) and runs the handler for any elements along that path matching the selector.

To make your code as performant as possible, you'll want to assign the delegation to the closest ancestor which isn't dynamically created, for instance:

<div id="non-dynamic-container">
    ...
    <elem id="remove_app_123"></elem>
</div>
$('#non-dynamic-container').on('click', '[id^=remove_app_]', function() { ... });

Upvotes: 0

jAndy
jAndy

Reputation: 236152

Simple answer: You use Event delegation.

You can achieve that by passing a selector as second argument to jQuery's .on().

$( document.body ).on( 'click', '[id^=add_app_]', function() {
});

Instead of document.body you should use the closest shared parent possible to prevent unnecessary event bubbling.

Upvotes: 3

Related Questions