Reputation: 5395
The summary of this question is: if we're using Event Delegation does it always have to be bound to an element that exists in the DOM on page load? Can we bind to a selector returned in an ajax response?
I'm using jQuery 3.2.1 and have been reading about Event Delegation: http://learn.jquery.com/events/event-delegation/
Using their example markup:
<ul id="list">
<li><a href="http://domain1.com">Item #1</a></li>
<li><a href="/local/path/1">Item #2</a></li>
<li><a href="/local/path/2">Item #3</a></li>
<li><a href="http://domain4.com">Item #4</a></li>
</ul>
I understand the point they're making about how if we added a 5th item to #list
with js, the following would only work for Items 1 - 4 because the 5th item didn't exist when .on
was called and therefore doesn't get the event handler:
$( "#list a" ).on( "click", function( event ) {
});
So the solution given is use a delegated event handler like this:
$( "#list" ).on( "click", "a", function( event ) {
});
In both of these cases they have targeted #list
because that's there on page load.
In my application, I am making an ajax request which would return the equivalent of the entire block of markup given at the start (i.e. everything including #list
) and appending it to a Bootstrap 3.3.7 modal window with an ID, #notifierModal
inside the default area for content which has a class of .modal-body
:
$.ajax({
url: $(this).attr('href'),
method: 'get'
}).done(function(response) {
$('.modal-body').html(response);
$('#notifierModal').modal('show');
});
I have this present on page load:
$( "#list" ).on( "click", "a", function( event ) {
console.log('something inside #list was clicked');
});
This does not work - presumably because #list
is not there on page load since it's appended to .modal-body
after the ajax request completes.
This does work - presumably because .modal-body
is present on page load:
$( ".modal-body" ).on( "click", "a", function( event ) {
console.log('something inside .modal-body was clicked');
});
So my question is two-fold:
If we're using Event Delegation does it always have to be bound to an element that exists in the DOM on page load? Is it possible to target a selector that's returned in an ajax response?
The reason this is a problem in my application is because I have other anchor tags inside .modal-body
which I don't want to be handled by the click
event given in my js. It seems impossible to target anchors inside #list
in this way? How could I write the js such that it only targets anchors inside #list
?
PS - I've read Event binding on dynamically created elements? but this seems to address binding on an element that existed on page load.
Upvotes: 0
Views: 450
Reputation: 370699
Yes, when you use event delegation to add a handler to a container, that container must exist first in order to add the handler.
The solution here is to provide a more precise selector string when using event delegation on your .modal-body
- rather than selecting any a
descendant, use the selector string #list a
instead to ensure that elements that trigger the listener must descend from #list
:
$( ".modal-body" ).on( "click", "#list a", function( event ) {
event.preventDefault();
console.log('something in the list was clicked');
});
function append() {
$( ".modal-body" ).append(`
<ul id="list">
<li><a href="http://domain1.com">Item #1</a></li>
<li><a href="/local/path/1">Item #2</a></li>
<li><a href="/local/path/2">Item #3</a></li>
<li><a href="http://domain4.com">Item #4</a></li>
</ul>
`);
}
setTimeout(append, 1500);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="modal-body"><a href="foo">something that shouldn't trigger listener</a>
</div>
Upvotes: 1