Yonder
Yonder

Reputation: 739

Passing optional callback functions with parameters

I'm trying in different ways to create a small scrolling method which can take an optional effect callback function. Imagine I can run scrollToEl(el, flash) which would first scroll down to the element and the flash it. How would I normally go about this?

This is what I've done..but it's not really working.

scrollToEl : function(el, callback) {
    // flash the selected product
    var self = this;
    $('html, body').animate({
        scrollTop: el.offset().top - 50
    }, 1000, 'swing', callback); // how to pass el here as well paired with callback?
}

flash : function(el) {
    // flash the selected product
    el.animate({
        opacity : 0.4
    }, 100, 'swing', function() {
        el.animate({
            opacity : 1
        }, 1000, 'swing');
     });
},

I want to use it like this:

var el = $('#element');
scrollToEl(el, flash); // how to pass in to the callback function flash?

Upvotes: 2

Views: 2191

Answers (2)

Alnitak
Alnitak

Reputation: 339786

It would be more normal for a callback to have the affected element as this rather than as a parameter:

flash : function() {
    // flash the selected product
    $(this).animate({
        opacity : 0.4
    }, 100, 'swing', function() {
        $(this).animate({
            opacity : 1
        }, 1000, 'swing');
     });
}

and then use a closure that uses .call or .apply to bind el to this when it's invoked:

$('html, body').animate({
    scrollTop: el.offset().top - 50
}, 1000, 'swing', callback ? function() {
    callback.call(el);
} : undefined);

Upvotes: 2

T.J. Crowder
T.J. Crowder

Reputation: 1074168

You can use a closure:

scrollToEl : function(el, callback) {
    // flash the selected product
    var self = this;

    // Get completion callback if any
    var completion;
    if (callback) {
        completion = function() {
            callback(el); // See below if you prefer `el` to be `this` in the callback
        };
    }
    else {
        completion = $.noop;
    }
    $('html, body').animate({
        scrollTop: el.offset().top - 50
    }, 1000, 'swing', completion);
}

More about closures: Closures are not complicated

If you want the callback to receive the element as this, you can use jQuery.proxy instead of your own wrapper function:

scrollToEl : function(el, callback) {
    // flash the selected product
    var self = this;

    $('html, body').animate({
        scrollTop: el.offset().top - 50
    }, 1000, 'swing', callback ? $.proxy(callback, el) : $.noop);
}

It comes to the same thing, because proxy creates a function. But it doesn't introduce a closure over the context of the call to scrollToEl.

Upvotes: 3

Related Questions