Ian Murray Ian Murray - 15 days ago 6
Javascript Question

Triggering a method after every element in a .each() loop has been processed

You'll have to forgive me if I show any kind of ineptitude here, jquery and java isn't my usual area of work. But here goes:

I have a page that shows a random list of items that are pulled from a server using an API call. The idea is that every time the user clicks "generate" a new list is produced and inserted into the page. This works but it's very fast and all the user sees is a list rapidly changing. To spruce things up I've decided to put some nice animations and effects in.

I've got a jquery function that loops through each element in the list of child elements and toggles the css style of the child element so that an effect from the animate.css library is applied. The problem is when I have another function that loads the new list and this is called immediately and therefore all of the css transitions are ignored; or rather they don't get a chance to run because the second method immediately triggers.

I've tried using a callback and had no joy, I've tried using deferred objects. No luck at all.

Here's the code I have so far:

function removeOldContent() {

$('#removableContent > div').each(function (index) {
var elm = $(this);
setTimeout(function () {
elm.toggleClass('customAnim', function () {
$(this).remove();
});
}, index * 150);
});
}

function getList() {
var rId = $('.tab-content').find('.active').data('d-id');
var serviceUrl = '/GetRandom/GetList';
$.ajax({
type: 'POST',
url: serviceUrl,
data: {
reportId : rId
},
success: function(data) {
$('#reportContainer').html(data).fadeIn('slow');
}
});
}


Ideally I'd like to be able to let removeOldContent() finish completely, after all the timeouts have run. And then trigger getList() to update the content. I'll work on making a nice transition for the inbound data but first I just need to get this working.

Any advice or pointers would be greatly appreciated.

***** Update ******

I've made a fiddle. Not giving me the same error as my dev env but should be close enough for you to see

https://jsfiddle.net/rdt1pfhk/9/

Answer

Your problem is with the timing of events. Your removeOldContent function uses a setTimeout function which in turn animates and removes the items from the DOM. Your getList() function was executing before the other function had finished. I put a quick untidy solution together using your fiddle. I return a jquery deferred object from you removeOldContent method and then only call the getList when that is resolved (and the older items removed from the dom). It is not the neatest but it will point you in the right direction. I updated your fiddle here: https://jsfiddle.net/rdt1pfhk/16/

function removeOldContent() {
    var deferred = new jQuery.Deferred();
    ....
    return deferred;
}

$(document).on('click', '.quickPick', function (e) {
    removeOldContent().then(function(){
       getList();        
    });
});