Sunday, January 29, 2012

Removing DOM Elements with Dart (A Tale of Null)

‹prev | My Chain | next›

For the next couple of days, I hope to keep it simple as I push toward a usable alpha release for Dart for Hipsters. While mucking about with my Dart sample application, I notice that cancelling the create form was not removing the form element from the page.

To remove the element, I had been:
if (form_div) form_div.remove();
That is not how the removeChild() works in Javascript (operates on a parent node, removing the specified child). I had tried working off of the API reference for Dart's remove(), which does not require an argument.

It may not require an argument, but it does state that it renames removeChild(), which would seem to indicate that it does operate on the parent. So I give it a try:
if (form_div) form_div.parent.remove(form_div);
But that fails to work as well.

OK, this is getting a bit annoying. When annoying, break it down to simplest case, I add a test_remove() method:
main() {
  test_remove();
  // ...
}

test_remove() {
  var test_div = new Element.html('<div id="test"/>');
  document.body.nodes.add(test_div);

  test_div = document.query('#test');
  test_div.parent.remove(test_div);
}
For that, I get a not-too-helpful backtrace:
Exception: NoSuchMethodException - receiver: 'Instance of 'BodyElementWrappingImplementation'' function name: 'remove' arguments: [Instance of 'DivElementWrappingImplementation']]
Stack Trace:  0. Function: 'Object.noSuchMethod' url: 'bootstrap' line:356 col:3
 1. Function: '::test_remove' url: 'http://localhost:3000/scripts/comics.dart' line:17 col:25
 2. Function: '::main' url: 'http://localhost:3000/scripts/comics.dart' line:5 col:14
So there is no remove() method on the test_div Element/Node? Surely there is because it is in the documentation. Ah, but it's in there with zero arity. So maybe:
test_remove() {
  var test_div = new Element.html('<div id="test"/>');
  document.body.nodes.add(test_div);

  test_div = document.query('#test');
  test_div.remove();
}
And, indeed that does work. But wait, why did that fail to remove an element in my original version?
if (form_div) form_div.remove();
Ah, dang it. I have a conditional in there. Sure enough, if I switch my test case to include that conditional:
test_remove() {
  var test_div = new Element.html('<div id="test"/>');
  document.body.nodes.add(test_div);

  test_div = document.query('#test');
  if (test_div) test_div.remove();
}
Then the test DIV is not removed:


It turns out that Dart very much wants a boolean in its conditionals. Lacking a conditional, it would appear to assume false. I cannot say that I am a fan of this, especially since the only resolution seems to be comparing to null:
test_remove() {
  var test_div = new Element.html('<div id="test"/>');
  document.body.nodes.add(test_div);

  test_div = document.query('#test');
  if (test_div != null) test_div.remove();
}
Ew. Not even the old !!test_div trick works. I seem to be stuck with this less than desirable null comparison.

I may not like this conditional structure (hopefully that can change), but I do much prefer the simple remove() in Dart to the traditional child.parent.removeChild(child) dance. All-in-all, I am willing to call this a net win for Dart. But it's a narrow win.

Day #280

No comments:

Post a Comment