I'm playing around with implementing an event pool pattern in my javascript, similar to what is described here: http://www.michaelhamrah.com/blog/2008/12/event-pooling-with-jquery-using-bind-and-trigger-managing-complex-javascript/
I need to be able to set the context of the event's closure(s) when they are triggered, rather than when they are bound. Is there some method of combining $.trigger and $.proxy to do this?
I'm just going to put this here for anyone else googling, but its not the actual answer to the whole binding at trigger time part.
This is a workaround solution that wraps the binding function to set its context according to an argument supplied at trigger time. It's no good if you want to pass args at trigger time though.
EventPool = (function() {
function EventPool() {}
EventPool.Subscribe = function(event, fn) {
return $(this).bind(event, $.proxy(function(event, context) {
context = context != null ? context : this;
return $.proxy(fn, context)(event);
}, this));
};
EventPool.Publish = function(event, context) {
return $(this).trigger(event, context);
};
return EventPool;
})();
First off: Thank you for your answer to your own question. It brought me to my own solution which I thought I'd share with you and every other person searching for it.
It is a modification of yours that still permits passing additional arguments to your EventPool.Publish
method. Note that my case looks a lot different from yours. Also note that jQuery.proxy
does almost the same as Function.bind
. (Btw, I do realize that this answer is already 2 years old.)
The demonstration code can be found here.
function subscribe( ) {
var args = argsToArray(arguments), // Helper function to convert `arguments` object into array. Otherwise `Function.apply` won't accept it.
fn = args[args.length - 1], // The event handler is always the last argument passed to `jQuery.on`.
$this = $(this);
args[args.length - 1] = router.bind(this, fn); // Change handler to our context changer.
$this.on.apply($this, args); // Call jQuery().on() with modified arguments.
return this;
}
Function.bind
essentially does the same as jQuery.proxy
. We'll use this to memorize which handler to call in the end.
The router
function calls the actual event handler, changing its context.
function router( ) {
var args = argsToArray(arguments),
fn = args.shift(), // Remember, we prefixed `router` with the actual event handler.
evt = args[0],
context = evt.context || this;
// No need to reference the context twice.
delete evt.context;
fn.apply(context, args);
}
jQuery allows easily creating events using jQuery.Event
(function). We're retrieving a custom property called context
here to use as the actual context of the real handler. Fallback to the old this
context if unset / evaluates to false.
Ultimately we're manually calling the actual handler with all arguments that were passed to jQuery().trigger
.
For usage, check the linked fiddle.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With