Re: Better event listeners
On Mon, Jan 7, 2013 at 5:42 PM, François REMY <francois.remy.dev at outlook.com> wrote:
However, I've a few issues with your latest proposal:
There's no proposal yet, we're exploring options.
Not quite convinced about yours though as I'm pretty sure we want to continue minting lowercase event names and overall it seems way complex.
element.on.{EventType} doesn't scale much with custom events where prefixes are in place, i.e. "jquery:transform" or whatever other string used to create unobtrusive custom events or ... will it? Same is for element.on({EventType:cb|handler})
My best version of on follows same addEventListener signature except it returns the element itself and accepts an array of types as overload
element.on( type:string|string[], handler:Function|Object (with handleEvent), capture:Boolean (false by default) ):element
the counter part is semantically easy to remember ...
element.off( ... same as above ... ):element
the ability to reuse a single callback or object with handleEvent together with the ability to use arrays of event types makes state machine like event driven interaction a piece of cake, IMHO.
My 2 cents
I have to say I'm really surprised that efforts are spent offering an alternative to addEventListener/removeEventListener. I've been doing JavaScript development for almost 13 years and I never felt these 2 api were that bad.
What is the rationale behind trying to offer an alternative syntax? As Francois mentioned, where did capture flag go?
Also we spent years explaining people to not use inline onclick="function(e){}" and now it's suddenly ok to do an element.on({click: ….) . That's muddying the waters to say the least.
There are other issues that I'm not sure are being worked on: - How about a better way when your handlers are objects and not functions? The big problem with functions is removing the listeners, it has to be the same function object and there are countless leaks today of people not realizing that their removeEventListener, when they thought of doing it actually doesn't do anything. Using an object as a listener typically doesn't have that problem in a well organized code like MVC. An object has a role, it's here to stay, it's typically "this" in addEventListener/removeEventListener. But "handleEvent" is insufficient because then your handleEvent becomes a big switch. In our framework we adopted a very intuitive convention and do some event distribution ourselves: if anObject listen for a "click" in bubble mode for an event target with an identifier property of "submitButton" then we look for a method on the listener: handleSubmitButtonClick. We shift the routing out of everyone else's code, and reading your own code tells you exactly what's going on. A more generic way to do that would be to allow the listener registration to provide the name of the method he wants as a callback instead of "handleEvent".
- Perfornance. Event Delegation as a concept has been pushed because it's slow to install all these listeners upfront. Is that being worked on?
- Registering the same listener for multiple different events could be useful sometimes
- the API for creating and dispatching events are quite bad in the other hand, these need work.
Thanks,
Benoit
On Mon, Jan 7, 2013 at 12:00 PM, Anne van Kesteren <annevk at annevk.nl> wrote:
On Mon, Jan 7, 2013 at 5:42 PM, François REMY <francois.remy.dev at outlook.com> wrote:
However, I've a few issues with your latest proposal:
There's no proposal yet, we're exploring options.
Not quite convinced about yours though as I'm pretty sure we want to continue minting lowercase event names and overall it seems way complex.
For the Dart DOM we wanted to fix the naming conventions of events as well as fix some inconsistencies (dblclick is the only one that is abbreviated for example). I'm not convinced it was worth it. It did lead to issues where the .type of an event name diverged (or had to be fixed up internally) from the key in the event map.
One good thing that came out of the Dart experiment was the on property, which like François mentioned allows IDEs to autocomplete the known event types. Another neat thing was that the on property was also defined as a Map<string, EventListenerList> so one could do
indexing for custom events. The known events were simple defined as:
get mouseOver() { return this['mouseover']; }
so that the following two were equivalent:
element.on['mouseover'] === element.on.mouseOver
element.on['my-custom-event'].add((e) => { console.log(e); })
www.dartlang.org/articles/improving-the-dom/#events, api.dartlang.org/docs/bleeding_edge/dart_html/Element.html#on, api.dartlang.org/docs/bleeding_edge/dart_html/ElementEvents.html, api.dartlang.org/docs/bleeding_edge/dart_html/EventListenerList.html
-- erik
Date: Mon, 7 Jan 2013 18:00:59 +0100 From: annevk at annevk.nl To: francois.remy.dev at outlook.com CC: www-dom at w3.org; es-discuss at mozilla.org Subject: Re: Better event listeners
On Mon, Jan 7, 2013 at 5:42 PM, François REMY <francois.remy.dev at outlook.com> wrote:
However, I've a few issues with your latest proposal:
There's no proposal yet, we're exploring options.
Not quite convinced about yours though as I'm pretty sure we want to continue minting lowercase event names and overall it seems way complex.
No problem with that, we're here to discuss. As you note, this is still early exploration ;-) My concerns continue to hold, however.
If we can a solution that works well with autocompletio, where you can test the existence of an event before registering to it (in a way that enables polyfills) and that doesn't remove abilities from the current syntax, I'll be all right. If we don't match those criteria, however, I'm not sure this approach is worth pursuing.
To respond to Benoit's answer, I do think 'onclick' was a good approach that just missed the '+=' and '-=' operators of C#. Maybe adding support for them would be an alternative approach? Don't know how practical it's from an ECMAScript point of view, however. Proxying 'null' to support just '+' and '-' operators on it would be awsomely insane ^_^
no need to have the big switch in the object ... if you use that object to register the event you can simply handle that event through the object itself ... i.e.
var handler = { handleEvent: function (e) { thise.type; }, click: function click(){}, touchstart: function touchstart(){} ... };
anynode.addEventListener("click", handler, false);
or
Object.keys(handler).forEach(function add(key){ key !== "handleEvent"&& this.addEventListener(key, handler, false); }, element);
Said that, the problem with functions can be easily solved as well through bound methods: webreflection.blogspot.de/2012/11/my-name-is-bound-method-bound.html
In any case I agree with you add/removeEventlistener ain't that bad but is way too boring type that long name each time and you cannot add multiple events at once which is, with the object and handleEvent, boring as well so my proposal is same contract slightly improved ;-)
br
Sure, if you like "click" as a method name and you don't listen for "click" on different objects for different purpose because if you do, you're back to branching your click code.
Autocomplete is already there in some code editors and WebKitInspector so I don't buy the long name to type. Code is read a lot more than it is typed, I personally favor readability/understandability over typing speed / convenience. I really don't type well and my brain has alway been a limiting factor to what I type, not my hands, but maybe it's just me!
Adding a listener for multiple events at once only makes sense if you do the exact same thing in all cases and in my experience, it's not that frequent that I feel it would need it's own API.
Thanks,
Benoit
don't get anything you said ... first of all nobody taked about different objects, you can also create instances for that and you know what you are listening to, it's your object ... secondly I don't use your IDE and I don't use auto complete but even if I was, the combination of arrow down and tab or enter after typing the first char where "a" for addEventListener is probably not enough is already a longer procedre than using just element.on( ... try that with your iDE
on is also semantic and inline with DOM Level 0 prefix for inline events so nothing to learn
Finally, adding a listener for multiple events makes always sense if you use an object rather than a callback as shown in my example.
Last, but not least, you are missing the fact I agree with you addEventListener isn't that bad and I've only suggested a simplified and more powerful contract that is already common in all my use cases ... sure, these might be different from yours
br
I wonder if this is the moment where redemption can happen... Instead of trying to invent some kind of new approach, why not standardize on the massive, 16 lane, mega-highway cow-path just waiting to be paved:
on => addEventListener
off => removeEventListener
emit => dispatchEvent
I'd suggest Node's EventEmitter (and EventEmitter2) as a reasonable starting point for an ideal, "subclassable" EventTarget-like system.
I like the naming convention, I don't like node.js in the picture because of double argument with that error as first one each time rather than an e.type === "Error"
I also would like to show another example of handleEvent and remitEvent proposal I have described a while ago:
/**
- interface ObjectHandler implements EventListener {
-
void handleEvent(in Event evt);
-
void remitEvent(in Event evt);
-
attribute Object events;
- };
- @link www.w3.org/TR/DOM-Level-2-Events/events.html#Events-EventListener */var ObjectHandler = { handleEvent: function handleEvent(e) { var events = this.events, type = e.type ; if (events.hasOwnProperty(type)) { events[type].call(this, e); } }, // it could be called removeEvent too, as you wish remitEvent: function cancelEvent(e) { e.currentTarget.removeEventListener( e.type, this, e.eventPhase === e.CAPTURING_PHASE ); } };
(webreflection.blogspot.de/2012/01/introducing-objecthandler.html)
On Monday, 7 January 2013 at 19:15, Rick Waldron wrote:
I wonder if this is the moment where redemption can happen... Instead of trying to invent some kind of new approach, why not standardize on the massive, 16 lane, mega-highway cow-path just waiting to be paved:
on => addEventListener off => removeEventListener emit => dispatchEvent
I'd suggest Node's EventEmitter (and EventEmitter2) as a reasonable starting point for an ideal, "subclassable" EventTarget-like system.
The above are great options, but I'd cry tears of joy for just having a constructor on EventTarget. I guess if we can fix a whole bunch of issues in one go (...man, that leveraging selectors for choosing targets is so nice...), that would be great, but I'm worried about getting bogged down.
Thanks for bringing the case of event registration, this has been a pain in DOM/JavaScript for some time already and it's quite clear we can do better in this area.
However, I've a few issues with your latest proposal:
and - isn't creating an object bag a too high cost for an event registration? - how do you deal with private names and inherited properties?
What about resurrecting .{} instead?
Even if .{} isn't resurrected, I think an 'on' proxy still leaves you with a fairly good syntax:
If we define "element.on" as a proxy, we can event make it support unknown event names by returning an "event handler object" for the event whose name as been specified as property name.
That would leave us with two new WebIDL interfaces, and an updated one:
target is 'target' and whose 'name' is the required property name */ }
Another benefit is that you could pass an event to a function (now, you have to pass the target and the name, and use target.addEventListener/removeEventListenee(name, ...)).
Another benefit could be that now you can check for the existence of an event by doing if("EventName" in target.on), if we configure the proxy correctly (ie return true only if the event is builtin). New events always come with an uppercase first-letter name so that we can be sure there will be no conflict with future Object.prototype.* builtin properties (if there's not one already with the current names, which I believe is not the case).
Last but not least, you can get intellisense (autocompletion) once you typed "element.on." in any sufficiently good IDE/dev tool.
Best , François
-----Message d'origine---