A constant eventListener, or almost this

4

I've always been in doubt as to this, as I remember doing my ajax test, and every time I updated it, I lost the event logged.

Example: A list of names

<script>
    $(document).ready(function(){
        $(".clickLi").click(function(){
            console.log($(this).data("age"));
        });
    });
</script>
<ul>
    <li class="clickLi" data-age="18">Nome 1</li>
    <li class="clickLi" data-age="6">Nome 2</li>
    <li class="clickLi" data-age="32">Nome 3</li>
</ul>

In this code, after clicking on a li, the age will be written to the console.

Ok, but if you had a button that ajax updated this list, you would lose the click function. How do I keep a listener in the list?

Thank you very much.

    
asked by anonymous 24.02.2015 / 21:06

1 answer

4

The solution to this is not to add listeners to elements that will be removed / replaced (or do not yet exist), but rather to an element prior to them in the hierarchy whose existence is guaranteed to anytime.

For example, if your Ajax operation only changes the content of <ul> , you can put the listener in <ul> itself instead of placing it in individual listeners. In the latter case, you put it in the body of the document, since it always exists and is ancestor of any other element. Because the click event "bubbles" through the DOM hierarchy, the event can be captured at a higher level.

This is called event delegation , and jQuery provides a syntax for this that makes the operation quite simple:

$('ul').on('click', '.clickLi', function(e) {
    $(e.target).data("age")
});

The second parameter of .on() is the target element selector, which may or may not exist at the moment the listener is created is added to <ul> .

Also note that inside the function I changed $(this) to $(e.target) . This is because $(this) would be the list itself, <ul> , while $(e.target) will be the clicked element ( <li> with class clickLi ).

A simple playback follows:

// 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><liclass="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>
    
24.02.2015 / 21:15