Opened 12 years ago
Closed 10 years ago
#9692 closed enhancement (fixed)
[patch/cla] Include trigger.js in Dojo Core
Reported by: | dante | Owned by: | dante |
---|---|---|---|
Priority: | high | Milestone: | 1.7 |
Component: | Core | Version: | 1.3.2 |
Keywords: | jburke | Cc: | Eugene Lazutkin |
Blocked By: | Blocking: |
Description
I have written a cross-browser trigger
function, available in plugd. It has been suggested as an addition to Core. It is already namespaced dojo.trigger() and it fires Dom and Obj events.
http://code.google.com/p/plugd/source/browse/trunk/trigger.js
is the current trunk version.
http://code.google.com/p/plugd/source/diff?path=/trunk/trigger.js&format=side&r=128
is the revision where I exposed dojo._trigger as a fast path to dom triggering.
http://code.google.com/p/plugd/source/diff?path=/trunk/trigger.js&format=side&r=129
adds custom IE event support and mouseenter/leave support in FF
Still proposed:
Mixing extra event properties into the dispatched event (being able to force a keyCode for example, or other arbitrary data)
Otherwise, it seems to work well. The try{}catch{} in the IE fireEvent branch is less than ideal, but was unable to determine a way to see if an event was native or otherwise.
the .replace to fix for mouseenter/leave is the best I could do.
Comments welcome.
Attachments (1)
Change History (28)
comment:1 Changed 12 years ago by
comment:2 Changed 12 years ago by
Custom events should take arguments, e.g.
jQuery(document).trigger('stuffHappened', ['Hello!']);
jQuery, MooTools?, Prototype and Ext support passing data with custom events. I don't see that it's possible to do this with dojo.trigger.
comment:3 Changed 12 years ago by
Why would it be useful to indirectly invoke a function using dojo.trigger?
// fire obj.method() in scope of obj dojo.trigger(obj, "method");
I can do this instead, which is easier/shorter and I can pass args.
obj.method(args);
comment:4 Changed 12 years ago by
re: arguments ... it "sorta" already does this (in the obj-firing case)
dojo.trigger(foo, "bar", 1,2,3,4,5); calls foo.bar(1,2,3,4,5);
the plan was to allow those args to be passed along to the event listeners as well, but I've not investigated the requirements in code to accomplish this. Another option was to simply mix an object into the event object passed around, perhaps something like meta
eg:
dojo.trigger("someId", "onclick", { a:"b" });
would trigger listeners like:
connect(node, "onclick", function(e){ e.a == "b" }); also note: dojo.publish/subscribe already passes along arguments like you describe. {{{ dojo.subscribe("/some/topic", function(){ console.dir(arguments); }); dojo.publish("/some/topic", [1,2,3,4,5]); }}} re name: not sure, but fire() sounds like an appropriate name. Would prefer to get the details of the implementation out before renaming. Task is also a simple search/replace, or worst case, alias, to preserve plugd users using the function already. with the availability of publish/subscribe and allowing _any_ non-namespaced custom event, I don't see the need to require/allow namespaced events. re: "why would it be useful" - simply to mimic all the other functions in dojo that allow the hitch pattern (eg connect, subscribe, etc) and work on either nodes or objects. This was the reasoning behind exposing _trigger on dojo, so experienced users could skip the various isFunction tests leading to deciding if it is a dom event or object event.
comment:5 Changed 12 years ago by
re: foo.bar(a) being easier to add args.
dojo.trigger(foo, bar.baz, 1, 2, 3, 4, 5)
is the same as:
bar.baz.apply(foo, [1,2,3,4,5]);
or w/ anonymous function, to create closure:
dojo.trigger(this, function(a,b){ }, this.a, this.b);
as opposed to:
dojo.hitch(this, function(a,b){ ... }, this.a, this.b)();
comment:6 Changed 12 years ago by
Do custom events bubble up the DOM tree (as in jQuery or Prototype)? Can I prevent the bubbling? Please mention this in the inline doc.
comment:7 Changed 12 years ago by
Having custom events that bubble would allow removing event stubs, which are used frequently in dijit.
Here’s an example of dijit.Tree event stubs that could be removed.
onClick: function(/* dojo.data */ item, /*TreeNode*/ node, /*Event*/ evt){ // summary: // Callback when a tree node is clicked // tags: // callback }, onDblClick: function(/* dojo.data */ item, /*TreeNode*/ node, /*Event*/ evt){ // summary: // Callback when a tree node is double-clicked // tags: // callback }
I could use this code instead (or in addition to event stubs):
dojo.connect(tree.domNode, "onClick", function(evt) { var item = evt.data.item; var node = evt.data.node; });
The 'onClick' event would have to be fired instead of calling the onClick() stub.
comment:8 Changed 12 years ago by
I'm pretty sure custom events would put an end to the empty stub technique.
http://www.sitepen.com/blog/2009/03/03/event-driven-design/
"Though dead simple, the concept of creating stub functions to act as connection targets is a handy tool to have at hand. Using it to fire your own events by spreading stubs throughout your code can make your systems very easy to extend."
Custom events are even simpler and more elegant because there's no need to create empty stubs.
comment:9 Changed 12 years ago by
re: custom events. I can mix in metadata into the event object no problem. Passing additional payload data is much more complicated (though i've not tried simply .apply on the fireEvent call, etc, but it isn't looking promising)
All browsers bubble custom events except IE. Even with createEventObject, the bubbles/cancleBubble property is not r/w, so no bubbling takes place. The only thing I can think of atm to accomplish this would be to iterate over node.parentNode firing _trigger from the new node each time to simulate bubbling, but that is a whole lot of cost ...
comment:10 Changed 12 years ago by
All browsers bubble custom events except IE.
I tried this jQuery code in IE6, and it works fine including bubbling and additional data being passed. I really hope you can get it done in Dojo :)
http://archive.dojotoolkit.org/nightly/dojotoolkit/dojo/tests/NodeList-manipulate.html
jQuery('#inputForm').bind('myEvent', function(evt, data) {alert(data);}); jQuery('#inputTextArea').trigger('myEvent', 'Hi there!');
comment:11 Changed 12 years ago by
For the .trigger in dojox.jq, I ended up having to call parent nodes to match the expected bubbling behavior in jquery:
http://bugs.dojotoolkit.org/browser/dojox/trunk/jq.js#L1147
It is ugly though.
comment:12 Changed 11 years ago by
Milestone: | 1.4 → future |
---|---|
Status: | new → assigned |
I don't want to walk to DOM to do this. Will need to come up with better API. not ready for core.
comment:13 Changed 11 years ago by
FYI: plugd/trunk trigger() function now handles custom bubbling in IE. still lacks curried data in all cases, but that could be next. as of r141
comment:15 follow-up: 22 Changed 11 years ago by
Neato! Some feedback:
1) In plugd source, it says this is supported:
dojo.trigger(d.global, function(){ /* stuff */ });
Is that just (function(){}).call(d.global)?
2) I am not sure the dojo.trigger on normal JS objects is that useful, seems simpler to just say obj.methodName() vs dojo.trigger(obj, "methodName"); If that saves some bytes to remove that support, then I would be OK with that.
3) The mixin of extraArgs, should that just be like an evt.data = extraArgs instead? That would allow extraArgs to have properties that may conflict with the event names, and avoid a mixin cost. Not sure if evt.data is safe to use, probably worth a spec check, but something like that.
4) For the NodeList? tie-in, it may be more efficient to create the event once, then pass that to some function that does the dispatchEvent/fireEvent work. That implies maybe splitting the existing _trigger into two functions perhaps. Will that work? Maybe we cannot reuse events across node.dispatchEvent() calls?
comment:16 Changed 11 years ago by
Thanks for the feedback @jbruke
1) yes.
2) I don't know that it is super useful, but is a minimal # of bytes to support the "pattern" that is put forth in other apis. eg: hitch.
dojo.trigger(obj, "method") === dojo.hitch(obj, "method")(); //but also obj.method(); // but cleaner than: var m = "methodName"; obj[m](); == d.trigger(obj, m); // also if you want to execute a method of a seperate obj in that scope: dojo.trigger(obj, other.method) == other.method.apply(obj, arguments); // with the bonus of currying. concat() is shorthand for more boilerplate. dojo.trigger(obj, other.method, 1) == other.method.apply(obj, arguments.concat(1))
3) Perhaps mixing into a defined member is best. maybe 'customData'? 'data' seems safe, but yah should check the spec. Seemed cool it just comes in as the event object though. how often are you connecting to an event of type and trying to overload that type?
4) you are probably right, I was going with the plain'ole _adaptAs things we use elsewhere for compactness. I'd already considered breaking _trigger into a 2 fn branch based on document.createEvent sniff (just as it is), but it doesn't really avoid the try{} when doing bubbling, and would increase the byte size significantly
comment:18 Changed 11 years ago by
about curried data, instead of:
dojo.trigger(foo, "bar", 1,2,3,4,5); // calls foo.bar(1,2,3,4,5);
how about:
dojo.trigger(foo, "bar", [1,2,3,4,5]); // calls foo.bar(1,2,3,4,5);
I think this is more inline with dojo.global
comment:20 Changed 11 years ago by
so after a long evening of attempting to get a stoppable propagation in IE, I came up with a small solution that involves adding a line to Base.
@@ -486,6 +487,7 @@ // Called in Event scope _stopPropagation: function(){ this.cancelBubble = true; + this._customStopper && this._customStopper(); },
by triggering this "customStopper", I am able to make the dom-_trigger function exit it's parent-traversal logic, simulating a real stopPropagation.
Any objections?
comment:21 Changed 11 years ago by
I'm OK with the change, although I prefer a more specific name verb-based name, _stopProp() or _customStopProp(), but that is just bikeshedding. None of them sound great.
comment:22 Changed 11 years ago by
Replying to jburke:
2) I am not sure the dojo.trigger on normal JS objects is that useful
This feature is available in jQuery and I find it useful. I'd like to have it in Dojo :)
$({}).bind("myEvent", function(evt, param) { alert(param); }).trigger("myEvent", "test")
comment:23 Changed 11 years ago by
Oh, I didn't think about calling trigger from a NodeList, I think James and I were envisioning doing a
dojo.trigger(context, function, arg);
rather than the current dojo way of
dojo.hitch(context, function, arg)();
or the native way of
function.call(context, arg);
Changed 11 years ago by
Attachment: | trigger.patch added |
---|
code, unit tests and patch to base/event.js with trunk at r21589
comment:24 Changed 11 years ago by
jQuery supports trigerring custom events on JavaScript? objects. Some developers use this feature although it's not documented, see this:
http://forum.jquery.com/topic/triggering-custom-events-on-js-objects
In my particular case, I'd like to write a Dojo adapter for Highcharts. Currently, there are jQuery, Prototype, MooTools? and Ext JS adapters available for Highcharts. Having the ability to trigger custom events on JS objects would help me write this adapter.
Thank you and I hope we will see this feature in the 1.6 release.
comment:25 Changed 10 years ago by
Cc: | Eugene Lazutkin added |
---|
comment:26 Changed 10 years ago by
Can this be marked as resolve since dojo/on.js include event dispatching support? Anything missing?
comment:27 Changed 10 years ago by
Milestone: | future → 1.7 |
---|---|
Resolution: | → fixed |
Status: | assigned → closed |
jep. doc pages seem in place, too. thanks!
I'm impressed that firing native events is supported, which e.g. is not supported in Prototype.
Prototype requires that custom events be name-spaced, see this example: http://ajaxian.com/archives/pseudo-custom-events-in-prototype-16
Would it be helpful to name-space custom events?
Also, in Prototype I can associate a payload with an event. Is this supported?
Finally, the name 'trigger'... no offense, but it's long and difficult to spell. Can you rename it to just dojo.fire?