The solution to this is not to add the listeners in elements that will be removed/replaced (or that do not yet exist), but in an element prior to them in the hierarchy, whose existence is guaranteed at any time.
For example, your Ajax operation changes only the content of <ul>
, you can put the Listener in own <ul>
instead of putting in the individual listeners. In the latter case, you put in the body of the document, as it always exists and is ancestral to any other element. Like the click event "bubble" through the DOM hierarchy, the event can be captured at a higher level.
It’s called delegation of events, and jQuery offers a syntax for this that makes the operation very simple:
$('ul').on('click', '.clickLi', function(e) {
$(e.target).data("age")
});
The second parameter of .on()
is the selector of the target elements, which may or may not exist at the time when the Listener is created is added to the <ul>
.
Note also that within the function I changed $(this)
for $(e.target)
. That’s because $(this)
would be the list itself, the <ul>
, while $(e.target)
will be the element clicked (the <li>
with class clickLi
).
Follows a simple reproduction:
// Deixa de funcionar se os LI forem substituídos
$('.clickme').click(function(e) {
var $e = $(e.target);
$e.text(Math.random());
});
// Sempre funciona
$('ul').on('click', '.clickme', function(e) {
var $e = $(e.target);
$e.css('color', 'blue');
});
$('.breakThePage').click(breakThePage);
$('.fixThePage').click(fixThePage);
// Reinsere listeners para cada elemento
function fixThePage() {
$('.clickme').off();
$('.clickme').click(function(e) {
var $e = $(e.target);
$e.text(Math.random());
});
}
function breakThePage() {
var $ul = $('ul');
$ul.html(
'<li class="clickme">1</li>' +
'<li class="clickme">2</li>' +
'<li class="clickme">3</li>' +
'<li class="clickme">4</li>' +
'<li class="clickme">5</li>'
);
}
function dontBreakThePage() {
var $li = $('li:nth-child(3)');
$li.text('Changed o.O');
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li class="clickme">1</li>
<li class="clickme">2</li>
<li class="clickme">3</li>
<li class="clickme">4</li>
<li class="clickme">5</li>
</ul>
<button class="breakThePage">Eu quebro a página</button>
<button class="fixThePage">Eu conserto a página</button>
Thanks to @yamadapc for the functional example (I adapted what was in your edit suggestion).
– bfavaretto
Good idea, to use a different color instead of my many buttons. I tried to think of something like this, but it did not come to mind for some reason :)
– yamadapc