trinathon trinathon - 1 month ago 6
Javascript Question

How do I preserve event listeners after sort?

I'm creating DOM elements then creating an array of JQuery objects with those DOM elements. After sorting the JQuery objects and re-appending them, the click event listener is gone. Is there a way to preserve the click listener?

for(var i=0; i<5; i++){
var div = $('<div>',{
id: i+"div",
class: 'list-item '+i,
html: "Item #"+i
});
div.data('i',i);
$('.news-layout-1').append(div);
div.on('click',function(){
alert($(this).data('i'));
});
}

$('.button').on('click',function(){
var items = [];
$('.news-layout-1').find('.list-item').each(function(index, item){
items.push(item);
});

items = items.sort(function(a,b){
var textA = $(a).html().toUpperCase();
var textB = $(b).html().toUpperCase();
return (textA > textB) ? -1 : (textA < textB) ? 1 : 0;
});

$('.news-layout-1').html('');

for(var i=0; i<items.length; i++){
$('.news-layout-1').append(items[i]);
}
});


http://jsfiddle.net/bhav4co6/5/

Answer

You're clearing the HTML, effectively removing the elements from the DOM, and they are just kept in memory, where they lose all associated data and events.

jQuery also uses .empty() internally when you do .html("") to make absolutely sure the elements, the data and the event listeners are removed.

If you just remove the line

$('.news-layout-1').html('');

you're fine, as the elements will just be moved, and keeps the event listeners

for (var i = 0; i < 5; i++) {
    var div = $('<div>', {
        id: i + "div",
        class: 'list-item ' + i,
        html: "Item #" + i
    });
    div.data('i', i);
    $('.news-layout-1').append(div);
    div.on('click', function() {
        alert($(this).data('i'));
    });
}

$('.button').on('click', function() {
    var items = [];
    $('.news-layout-1').find('.list-item').each(function(index, item) {
        items.push(item);
    });

    items = items.sort(function(a, b) {
        var textA = $(a).html().toUpperCase();
        var textB = $(b).html().toUpperCase();
        return (textA > textB) ? -1 : (textA < textB) ? 1 : 0;
    });

    for (var i = 0; i < items.length; i++) {
        $('.news-layout-1').append(items[i]);
    }
});
.list-item { cursor: pointer }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="news-layout-1">
</div>
<a href="#" class="button btn">
  Sort
</a>

As a sidenote, there's no need for an array or a loop to append, you can just do

$('.button').on('click', function() {
    $('.news-layout-1 .list-item').sort(function(a, b) {
        var textA = $(a).html().toUpperCase();
        var textB = $(b).html().toUpperCase();
        return (textA > textB) ? -1 : (textA < textB) ? 1 : 0;
    }).appendTo('.news-layout-1');
});