What I want to do is; without leaving the chain, execute some custom/external code (and continue) within the chain. Otherwise; in a deep chain, I will have to re-query for the DOM element to get back where I've left.
The method below allows to execute custom code inside a jQuery chain synchronously or asynchronously.
//Execute code inside a jQuery chain
$.fn.do = function (callback, async) {
if (typeof callback === 'function') {
if (async === true) {
this.queue(function() {
callback($(this));
$(this).dequeue();
});
} else {
callback(this);
}
}
return this;
};
Simplified Usage Example:
var results = {};
$('#some-elem')
.css({
//modify some styles here
})
.do(function($elem) {
//do some calculations.. tests here..
//save them to results object
}, false) //synchronous
.css({
//re-set the styles back to their initial state
});
This could be a longer chain where you could need to enter the do()
method multiple times.
So;
- Do you think the approach above is legitimate?
- Would you suggest an alternate? Why?
1 Answer 1
I guess this plugin could be useful, however I think you can drop the async part since it's not any harder to call queue
directly.
Also, I am not a huge fan of error swallowing or ignoring invalid calls since it makes the code harder to debug. If there's a call to do
without providing a callback, you should let the developer be notified.
I also like to allow defining the this
value for the callback function so that you do not need to use $.proxy
for that purpose.
Finally I allowed to return a value from the callback to change the target object for the rest of the chain. However I am not so sure about this feature since it could harm code comprehension but I am leaving it there as an idea.
Basically it would be as simple as:
!function($) {
$.fn.do = function (callback, thisArg) {
if (typeof callback !== 'function') {
throw new TypeError("the 'callback' argument must be of type 'function'");
}
return callback.call(thisArg || this, this) || this;
};
}(jQuery);
Note: I've defined the plugin within an IIFE so that it still works if $.noConflict()
was used.
-
\$\begingroup\$ +1 for
thisArg
. Though, I wouldn't modify the returned object since this is for keeping the chain. Sure you can callqueue()' easily;
async` acts like a shortcut there. Thanks. \$\endgroup\$Onur YILDIRIM– Onur YILDIRIM2013年10月20日 15:13:22 +00:00Commented Oct 20, 2013 at 15:13
.queue()
here - why are you adding a function to the defaultfx
queue (will be queued after animations when there are pending animations) if this version of the method is asynchronous? You can probably get rid of that. \$\endgroup\$do()
method) so I'm allowing for both async and immediate execution. (I'm also passing the corresponding jQuery element as an argument.) Does it make sense? \$\endgroup\$.css()
should wait untildo()
callsdequeue()
? \$\endgroup\$.css()
method is executed immediately and.do()
is called withfalse
param. And essentially,do(func, true)
(async) is only a shorhand forqueue()
which will execute when it's his turn in the queue. You might say that I'm only extending the.queue()
method with a sync execution capability. \$\endgroup\$queue
then this looks perfectly fine. I may take another look tomorrow but there isn't much code to cut out without losing a lot of readability. \$\endgroup\$