Sunday, August 3, 2014

The PublishedProperty Polymer Dart Annotation


There seems to be a good amount of confusion surrounding the new @PublishedProperty annotation in version 0.12 of Polymer.dart. Fair enough, I am always good for piling on more confusion.

Consider my venerable <x-pizza> element. I might want to publish it with an attribute that specifies a specialty pizza name:
      <h1>Ye Olde Dart Pizza Shoppe</h1>
      <x-pizza special_name="Plain"></x-pizza>
In older version of Polymer.dart, I would have supported this with a @published annotation in the backing class like so:
@CustomTag('x-pizza')
class XPizza extends PolymerElement {
  // ...
  @published special_name;
  // ...
}
The new way of expressing this same intent is:
@CustomTag('x-pizza')
class XPizza extends PolymerElement {
  // ...
  @published
  String get special_name => readValue(#special_name);
  set special_name(String newValue) => writeValue(#special_name, newValue);
  // ...
}
This is… pretty ugly. My understanding is that there are “timing” issues that necessitate writing it like that, but unless I experience said issues, I would likely continue using the old version.

Anyhow, I am trying to play with the @PublishedProperty annotation. At first, I try using this like the regular @published annotation:
@CustomTag('x-pizza')
class XPizza extends PolymerElement {
  // ...
  @PublishedProperty
  String get special_name => readValue(#special_name);
  set special_name(String newValue) => writeValue(#special_name, newValue);
  // ...
}
But am greeted by a nasty error when trying to serve this element via pub serve:
Build error:
Transform ScriptCompactor on published_example|web/index.html threw error: The null object does not have a getter 'arguments'.

NoSuchMethodError: method not found: 'arguments'
Receiver: null
Arguments: []
dart:core-patch/object_patch.dart 45                                            Object.noSuchMethod
http://127.0.0.1:36253/packages/smoke/codegen/recorder.dart 268:44              _convertAnnotation
dart:_internal/iterable.dart 393                                                MappedListIterable.elementAt
dart:_internal/iterable.dart 214                                                ListIterable.toList
...
The actual error goes on for a long time. It takes me a bit of time to realize that the @PublishedProperty annotation has a required argument, which looks like an optional named parameter::
@CustomTag('x-pizza')
class XPizza extends PolymerElement {
  // ...
  @PublishedProperty(reflect: true)
  String get special_name => readValue(#special_name);
  set special_name(String newValue) => writeValue(#special_name, newValue);
  // ...
}
Which re-publishes the attribute back to the element itself. To verify this, I add a conditional in the updatePizza() method to change the specialty name if the first half of the pizza has one topping and it is pepperoni:
@CustomTag('x-pizza')
class XPizza extends PolymerElement {
  // ...
  updatePizzaState([_]) {
    var first = $['firstHalfToppings'].model;
    if (first.length == 1 && first[0] == 'pepperoni') {
      special_name = 'First Half Pepperoni';
    }
    // ...
  }
}
Sure enough, if I add pepperoni to the first half, the attribute changes back in the DOM from “Plain”:



To the new “First Half Pepperoni” special name:



If I switch back to the @published annotation, then even though special_name is still being updated, the published attribute no longer reflects the change. The value of the special_name attribute in the DOM always remains “Plain.”

Interestingly, @PublishedProperty(reflect: false) seems to behave the same as @published. I am unsure if there is a difference or if reflect: false is only meant as a similar looking alternative when some attributes require reflect: true. The documentation mentions something about serializing, but initial attempts at converting to something that might be serialized (like a List) do not seem to work.

I am not thrilled with the new annotation—especially the verbosity of the setter and getter. Still, the functionality is nice. I wonder if this might make it easier to synchronize changes between Polymer.dart and Angular.dart. Something to investigate another day.



Day #142

No comments:

Post a Comment