Thursday, July 4, 2013

WebUI component lifecycle

Once again, I'm drafting a not-too-trivial web app with Dart. I have to say that the language really does feel nice, and while it's getting better each week, it's not so unstable to have to be learned again on each upgrade.

One major attraction of Dart is the WebUI library, which is still far from complete, but changes the whole app design so much that any other option feels hacky by comparison. Unfortunately, there's still many rough edges, and while the documentation is very clear and and readable, there's still some things that aren't well laid out, specially about the intended architecture.

So, these are the things I'm struggling with right now.  I guess i'll turn some of these into questions to post on the +Dart G+ page, but first I want to spill my doubts here:

1.- Create components 'on the fly'.
All the WebUI examples are about instantiating components simply by using the tags in some HTML. Behind the scene, the compiler generates some tedious-looking Dart code that does everything; but there doesn't seem to be an easy way to just create a new component from Dart code.  After finding some hints reading between the lines of some docs, and distilling from the generated code, I came up with something like this:

  /// Adds a component to the host.
  ///     [holder] is the container Element,
  ///     [comp] is the already-created component object,
  ///     [compname] is the tagname of the component.
  void insertComponent(Element holder, WebComponent comp, String compname) {
    comp.host = new Element.html('<${compname}></${compname}>');
    _lifecycleCaller = new ComponentItem(comp)..create();
    holder.children.add(comp.host);
    _lifecycleCaller.insert();
  }

To create the component, the calling code must first create an instance of the Dart object and call this function, with the correct tagname.  Which leads to:

2.- Why can't the component class publish it's tagname?
It would be as simple as adding a final tagname = "x-tag-name"; to the autogenerated class declaration. In fact, the tagname is already inserted as a constant several times; but only for internal use, never to return to the caller.

3.- Does every component need a ComponentItem nanny?
Also, do you see the _lifecycleCaller object created to insert the component? Well, this code in fact isn't a free-standing function, it's a method of a class I use to handle "component container" (or "holder" as called on the code).  There, I also have to store this caller and use it after removing the DOM element.  I guess it's fair, given the name: it's a life cycle method caller, so it has to stay around for the whole life cycle.  But it would be nicer if the three methods it implements were simply part of the WebComponent class, so i could just call comp.create();, comp.insert(); and comp.remove(); at the appropriate moments.  Even better if both .insert() and .remove() could be called automatically at the DOM insertion/removal.

In short, this is how I'd like to create a component and insert it to a holder element:

  var comp = new MyComponent(...);
  comp.create();
  var holder = query('#componentholder');
  holder.children.add(comp.host);

or even:

  var comp = new MyComponent(...);
  query('#componentholder').children.add(comp..create()..host);

which is even more readable.

While writing this, I get more and more the feeling that I'm getting needlessly complicated.  It doesn't seem to be an easier way already implemented (in part because the generated code does similar things), but I can't fight the feeling that maybe I don't need any of this.