After two night's of experimentation, I swear to you that the
@ComputedProperty
annotation in Polymer.dart serves no purpose. No purpose whatsoever!Well, OK, it does something, but as far as my experiments have determined, it does exactly what a much simpler and syntactically cleaner Dart getter would do. Consider a
@ComputedProperty
and a vanilla getter that produce identical results in the <x-pizza-toppings>
Polymer element:@CustomTag('x-pizza-toppings') class XPizzaToppings extends PolymerElement { // ... List<String> model = toObservable([]); @ComputedProperty("model.length") int get numToppings => readValue(#numToppings); int get numToppings_old => model.length; // ... }The values of both will report the number of toppings that are included on a half or whole of pizza in the parent
<x-pizza>
element. To prove that both the getter and the much more verbose @ComputedValue
are IDENTICAL IN EVERY WAY, I include both in the <template>
:<link rel="import" href="../../../packages/polymer/polymer.html"> <polymer-element name="x-pizza-toppings"> <template> <p> <!-- ... --> (Currently: {{ numToppings }}, {{ numToppings_old }}) </p> </template> <script type="application/dart" src="x_pizza_toppings.dart"></script> </polymer-element>And, when I update the different sides of the pizza in the UI, these bindings are updated in exact unison:
But there must be a reason for
@ComputedValue
. There simply must be!Experimentation is clearly getting me nowhere, so I switch back to reading the actual code. And, thankfully, the code is beautiful. Well, documented, easy to follow for the most part. I could (and probably should) read through this all night long. But first, I must know.
And I finally have my answer from the
_PropertyAccessor
internal class which services both the @ComputedValue
and @published
annotations. In there, I find that, when these are updated, they perform the following: /// Updates the underlyling value and fires the expected notifications.
void updateValue(T newValue) {
var oldValue = _value;
_value = _target.notifyPropertyChange(_name, oldValue, newValue);
_target.emitPropertyChangeRecord(_name, newValue, oldValue);
}
There is even documentation expressing what I should have expected all along—that a changed record is emitted by the Polymer element. And, sure enough, such a record is emitted. I add a listener in the parent <x-pizza>
element:@CustomTag('x-pizza') class XPizza extends PolymerElement { // ... XPizzaToppings get firstHalf => $['firstHalfToppings']; XPizzaToppings get secondHalf => $['secondHalfToppings']; XPizzaToppings get whole => $['wholeToppings']; // ... XPizza.created(): super.created() { firstHalf.changes.listen((changes) { print(changes); }); /*** I previously tried this (I was so close) ***/ // firstHalf.numToppings.changes.listen((changeRecord) { // print("$changeRecord"); // }); } // ... }Which reports that a change has occurred:
[#<PropertyChangeRecord Symbol("numToppings") from: 0 to: 1>] [#<PropertyChangeRecord Symbol("numToppings") from: 1 to: 2>] [#<PropertyChangeRecord Symbol("numToppings") from: 2 to: 3>]I have my answer. And it is one that I really should have gotten to faster had I thought about it a bit more. Ah well, in the end I had some frustration but was rewarded with some pleasant code reading—and the answer to my question.
Day #145
No comments:
Post a Comment