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