I am usually pretty safe assuming that my assumptions are wrong. Unless they're not. Happily, this turned out to be the case with some code I was trying to force in Polymer.dart. Thanks to a reimplementation in the JavaScript version of the Polymer project, I now have a better understanding of bound variables in Polymer.
The problem arose when I tried to bind some
Pizza
model attributes in a <x-pizza>
element:<link rel="import" href="../bower_components/polymer/polymer.html"> <polymer-element name="x-pizza"> <template> <h2>Build Your Pizza</h2> <pre> {{model.firstHalfToppings}} {{model.secondHalfToppings}}</pre> <!-- ... --> </template> <script src="x_pizza.dart"></script> </polymer-element>Those attributes were not bound, at least not such that their changes were observed in the template. Interestingly, when an actual bound attribute, say a “pizza state” instance variable, was bound in the same
<pre>
element in my template, then the model attributes were updated:<link rel="import" href="../bower_components/polymer/polymer.html"> <polymer-element name="x-pizza"> <template> <h2>Build Your Pizza</h2> <pre> {{pizzaState}} {{model.firstHalfToppings}} {{model.secondHalfToppings}}</pre> <!-- ... --> </template> <script src="x_pizza.js"></script> </polymer-element>In fact, the model attributes in the template were updated whenever the
pizzaState
instance variable was updated. So it seems that including a truly bound variable inside a tag will force all bound variables—model or element—to update. That seems useful information to file away for another day. For today, I would like to see how the JavaScript library's solution of path expressions to watch for changes in a model translates into Dart. From last night's JavaScript, the solution was to observe three list attributes in the model:
Polymer('x-pizza', { observe: { 'model.firstHalfToppings': 'updatePizzaState', 'model.secondHalfToppings': 'updatePizzaState', 'model.wholeToppings': 'updatePizzaState' }, // ... });The
observe
block tells Polymer to call the updatePizzaState()
method (which updates pizzaState
for the template) whenever a change is seen in any of those lists.If there is an equivalent for the
observe
block in Polymer.dart, I cannot find it. What I wind up using instead is simple change listeners. For this to work, the model in my Model Driven View,
Pizza
, needs to be “observable.” Furthermore, since the properties in question are lists, I need a specialized “observable” instance of those lists. Both of these are established with judicious used of the @observable
annotation:@observable class Pizza { List<String> firstHalfToppings = toObservable([]); List<String> secondHalfToppings = toObservable([]); List<String> wholeToppings = toObservable([]); }With that, I can create something that looks like an
observe
block. If you squint:@CustomTag('x-pizza') class XPizza extends PolymerElement { // ... Pizza model; XPizza.created(): super.created() { model = new Pizza() ..firstHalfToppings.changes.listen(updatePizzaState) ..secondHalfToppings.changes.listen(updatePizzaState) ..wholeToppings.changes.listen(updatePizzaState); // ... } // ... }The double dot operator in Dart is a method cascade. It returns the original object instead of the return value of the method (or property lookup). Above, this allows me to ask for the
firstHalfToppings
, secondHalfToppings
, and wholeToppings
properties from the newly created Pizza
object. For each of these, I listen to the changes
stream for a change and update the “pizza state” accordingly.And that does the trick:
I can live with that method cascade solution. At least for tonight. It is a solution (and a relatively clean one at that), but I am not 100% certain that it is the solution for this in Polymer.dart. While digging through class documentation, I came across Polymer's
bind()
and bindProperty()
methods. Both use similar path expressions as those found in the JavaScript observe
block. I am not entirely sure that they operate in the same problem space, but that is a topic for another day. Like tomorrow!Day #997
No comments:
Post a Comment