I do not believe that Dart has an equivalent to jQuery's delegated events, but tonight I take a look. As the jQuery documentation states, delegated events are nice for two reasons: specifying handlers for elements not yet added to the page and significantly cutting down on the total number of handlers in some circumstances. It was while working with Backbone.js that I especially came to know and love delegated events, hence the desire for them in Dart.
In my comic book application, I am inserting a list of comic books into a static page via XHR:
After list is inserted, I attach delete handlers to each of those Delete links:
load_comics() { var list_el = document.query('#comics-list') , req = new XMLHttpRequest(); req.open('get', '/comics', true); req.on.load.add((res) { var list = JSON.parse(req.responseText); list_el.innerHTML = graphic_novels_template(list); attach_delete_handlers(list_el); }); req.send(); }What I would like to do is move that
attach_delete_handers()
function before the XHR request:load_comics() { var list_el = document.query('#comics-list') , req = new XMLHttpRequest(); attach_delete_handlers(list_el); req.open('get', '/comics', true); req.on.load.add((res) { var list = JSON.parse(req.responseText); list_el.innerHTML = graphic_novels_template(list); }); req.send(); }If the event handlers was in delegate mode, then this would still work. Unfortunately it does not. Clicking any of the links incurs the default behavior of the
<a>
tags—in this case requesting the current resource with a hash tag:The reason that I do not believe that Dart supports this is the manner in which event handlers are added. All elements have an
on
getter, which returns an ElementEvents. Since on
does not support any arguments, there is no mechanism to record a selector that might put the listener into delegate mode. The ElementEvents
object exposes a series of EventListenerList getters (e.g. click, mouseOver, etc) to which event listeners can be added. I see no room for delegation anywhere.This can be seen in my
attach_delete_handlers()
function, which iterates through each existing Delete link of the supplied UL list, attaching he same event listener to each:attach_delete_handlers(parent) { parent.queryAll('.delete').forEach((el) { el.on.click.add((event) { delete(event.target.parent.id, callback:() { print("[delete] ${event.target.parent.id}"); event.target.parent.remove(); }); event.preventDefault(); }); }); }If I call
attach_delete_handlers
before the XHR request, then the queryAll('.delete')
call will return an empty list and thus no handlers are attached.Since that won't work (unless I am overlooking something), let's try adding a handler to the UL parent element. That handler should look through all of the
.delete
links and handle the event if the event target is on of those:attach_delete_handlers(parent) { parent.on.click.add((event) { if (parent.queryAll('.delete').indexOf(event.target) == -1) return; print(event.target.parent.id); event.preventDefault(); }); }Sadly, when I click the delete link, I get the following:
Exception: Not impl yet. todo(jacobr) Stack Trace: 0. Function: 'FrozenElementList.indexOf' url: 'dart:htmlimpl' line:22497 col:5 1. Function: '::function' url: 'http://localhost:3000/scripts/comics.dart' line:59 col:43 2. Function: 'EventListenerListImplementation.function' url: 'dart:htmlimpl' line:23183 col:35Dang it. OK it is a new language. Things like that are bound to happen. Perhaps
some()
will work where indexOf()
did not:attach_delete_handlers(parent) { parent.on.click.add((event) { if (parent.queryAll('.delete').some((el) { el == event.target;})) return; print(event.target.parent.id); event.preventDefault(); }); }Now when I click a Delete link I get:
Exception: Not impl yet. todo(jacobr) Stack Trace: 0. Function: 'FrozenElementList.some' url: 'dart:htmlimpl' line:22434 col:5 1. Function: '::function' url: 'http://localhost:3000/scripts/comics.dart' line:59 col:40 2. Function: 'EventListenerListImplementation.function' url: 'dart:htmlimpl' line:23183 col:35Shakes fist at jacobr!
So
indexOf
does not work, nor does some
. I know that forEach()
works for certain, so...attach_delete_handlers(parent) { parent.on.click.add((event) { var found = false; parent.queryAll('.delete').forEach((el) { if (el == event.target) found = true; }); if (!found) return; print(event.target.parent.id); event.preventDefault(); }); }Not the prettiest code, but I can live with it until jacobr implements cleaner iterator methods.
With that working, I can add my XHR delete call to this psuedo-delegated event handler:
attach_delete_handlers(parent) { parent.on.click.add((event) { var found = false; parent.queryAll('.delete').forEach((el) { if (el == event.target) found = true; }); if (!found) return; print(event.target.parent.id); delete(event.target.parent.id, callback:() { print("[delete] ${event.target.parent.id}"); event.target.parent.remove(); }); event.preventDefault(); }); }And, now I can delete comics again:
That is not ideal, but at least it is possible. jQuery still has Dart beat in this respect, but I can live with this for now...
Day #273
No comments:
Post a Comment