Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there an easier way of chaining different jQuery actions for different selectors then nested $.when?

In jQuery you can chain actions for the same selector very easily but if you want to use different selector for each action it requires nested $.when with more then two actions which is quite hard to read and maintain.

HTML:

<span id='a'>Hello</span>
<span id='b'>world</span>
<span id='c'>!!!</span>

CSS:

span {
    display: none;
}

JS: based on this: how to hide multiple items but only call the handler once?

var d = 500; // duration

// Execute in parallel.
//$('#a').show(d).hide(d);
//$('#b').show(d).hide(d);
//$('#c').show(d).hide(d);


$.when($('#a').fadeIn(d).fadeOut(d)).done(function () {
    $.when($('#b').show(d).hide(d)).done(function () {
        $('#c').slideDown(d).slideUp(d);
    });
});

jsfiddle (old)

jsfiddle-2

I thougt I could use the queue but it seems to work only for the same selector.

Is there a way to write it in a more maintainable manner like:

pseudocode

var myActions = [];
myActions.push(function(){...});
myActions.push(function(){...});
myActions.push(function(){...});
something.executeSequentially(myActions);

EDIT:

I updated the demo so that it's a little bit harder.

like image 342
t3chb0t Avatar asked Nov 29 '14 20:11

t3chb0t


2 Answers

If you really don't have to encounter for failures (and that's hardly possible with animations I suppose), you can use the following approach (kudos to @Esailija, as this solution is basically a simplified version of his answer):

var chainOfActions = [
    function() { return $('#a').fadeIn(d).fadeOut(d); },
    function() { return $('#b').fadeIn(d).fadeOut(d); },
    function() { return $('#c').fadeIn(d).fadeOut(d); },
];
chainOfActions.reduce(function(curr, next) {
    return curr.then(next);
}, $().promise());

Demo. There are three key points here:

  • each function in chain of actions already returns a promise (if not, you can 'promisify' it with returning the result of .promise() call instead)
  • at each step of reduce a chain is created, as each callback supplied into then() creates a new promise
  • the whole chain is initiated by supplying an empty promise as the initial value of reduce accumulator.
like image 80
raina77ow Avatar answered Oct 20 '22 07:10

raina77ow


Edit, Updated

var d = 500
, something = {}
, myActions = [];

myActions.push(
function (next) {
    $('#a').fadeIn(d).fadeOut(d, next)
});
myActions.push(
function (next) {
    return $('#b').show(d).hide(d, next)
});
myActions.push(
function () {
    return $('#c').slideDown(d).slideUp(d)
});

something.executeSequentially = function (arr) {
    return $(this).queue("fx", arr);
};
something.executeSequentially(myActions);

jsfiddle http://jsfiddle.net/guest271314/2oawa1zn/

like image 31
guest271314 Avatar answered Oct 20 '22 07:10

guest271314