Tuesday, January 31, 2012

Custom Events in Dart

‹prev | My Chain | next›

I have a deadline for the alpha release for Dart for Hipsters, but before I can get to that, I must appease the gods of my chain. I have yet to meet these gods, but they have been kind to me, so I must do what I can to keep them happy.

Last night I got started breaking my Ajax based Dart application into real View classes (somewhat along the lines of Backbone.js). Today, I hope to extract collection code from my view into a proper collection class.

The heart of the collection, the fetching from the backend datastore, I can already do:
class ComicsCollection {
  var list;

  ComicsCollection() {
  }

  // Be Backbone like
  fetch() {
    var req = new XMLHttpRequest();

    req.on.load.add(_handleOnLoad);
    req.open('get', '/comics', true);
    req.send();
  }

  _handleOnLoad(event) {
    var request = event.target;

    list = JSON.parse(request.responseText);

    // How to tell the view that I'm done?
  }
}
But how can I communicate to my view that the collection has loaded new data?

I would like to instantiate a collection and a collection view something along the lines of:
  var my_comics_collection = new ComicsCollection()
    , comics_view = new ComicsCollectionView(
        el:'#comics-list',
        collection: my_comics_collection
      );

  my_comics_collection.fetch();
In the collection view, I could then subscribe to the collection view's on-load event:
  ComicsCollectionView([el, collection]) {
    this.el = document.query(el);
    this.collection = collection;

    collection.on.load.add((event) {
      render();
    });
  });
To get that to work, I will at least need an on getter in the Collection:
class ComicsCollection {
  var list;
  var get on;

  ComicsCollection() {
    on = new CollectionEvents();
  }
}
I could probably re-use one of the DOM Events classes here, but it is not too hard to define my own:
class CollectionEvents implements Events {
  var load_list;

  CollectionEvents() {
    load_list = new CollectionEventList();
  }

  get load() {
    return load_list;
  }
}
I defined a load getter that returns an EventList object. This CollectionEventList class that I define will be the thing that holds event listeners. It needs to define two methods: add() to add listeners and dispatch() to send events to all listeners:
class CollectionEventList implements EventListenerList {
  var listeners;

  CollectionEventList() {
    listeners = [];
  }

  add(fn) {
    listeners.add(fn);
  }

  bool dispatch(Event event) {
    listeners.forEach((fn) {fn(event);});
    return true;
  }
}
No doubt I can be a little more elegant about that, but that should meet the spirit of what is needed. Amazingly, that does work. To be sure that I am not somehow faking it, I add another debugging on-load handler to listen for my custom event:
class ComicsCollectionView {
  var get el;
  var get collection;

  ComicsCollectionView([el, collection]) {
    this.el = document.query(el);
    this.collection = collection;

    collection.on.load.add((event) {
      render();
    });

    collection.on.load.add((event) {
      print("This really did fire in response to a custom event");
    });

    _attachUiHandlers();
  }

  // ...
}
And indeed, it does work:


Nice. That almost seems a little too easy. I will take a look at this in the fresh light of a new day to make sure that I am not cheating somehow. If custom event handlers in Dart really are this easy, then I am thrilled. Bust mostly I'm sleepy.


Day #282

0 comments:

Post a Comment