I adore switching back and forth between the JavaScript version of Polymer and Polymer.dart. It has been a fantastic feedback mechanism for validating or, more frequently, disproving my thinking about Polymer. Tonight, I switch back to the JavaScript in the hopes that I can solidify my thinking on model driven views in Polymer.
In my Dart version, I have a
<x-pizza>
Polymer that builds up a pizza for order. It looks something like:And it works. More or less.
One thing that I was not quite able to figure out was why model attributes—specifically list model attributes—were not updating the values bound in templates. For instance, the
model.firstHalfToppings
and model.secondHalfToppings
values are not being updated in the template when they change in the model:<polymer-element name="x-pizza"> <template> <h2>Build Your Pizza</h2> <pre> {{model.firstHalfToppings}} {{model.secondHalfToppings}}</pre> <!-- ... --> </template>So let's see if I can make that work in a JavaScript version. Starting with the
index.html
page that contains my soon-to-exist-js-polymer:<head> <!-- 1. Load Polymer before any code that touches the DOM. --> <script src="bower_components/platform/platform.js"></script> <!-- 2. Load component(s) --> <link rel="import" href="elements/x-pizza.html"> </head> <body> <div class="container"> <h1>JS Bros. Pizza Builder</h1> <x-pizza></x-pizza> </div> </body>The template that goes into the imported
x-pizza-html
is nearly identical to the Dart version. What changes is, obviously, the script tag—which now points to a JavaScript version of the Polymer class:<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.js"></script> </polymer-element>There is nothing too out of the ordinary in that backing Polymer class—just the model assignment in the
ready()
lifecycle method:Polymer('x-pizza', { ready: function() { this.model = { firstHalfToppings: [] }; }, addFirstHalf: function() { this.model.firstHalfToppings.push(this.currentFirstHalf); }, // ... });The Polymer documentation recommends binding the model in
ready()
to avoid shared prototype state (ah, JavaScript). In addition to assigning the model, I also define a bound method that adds records to the
firstHalfToppings
list property of the model. Whenever this function is called, the model's firstHalfToppings
should change, which should update in the template. Only it did not in the Dart version of the Polymer.And it does not in the JavaScript version either:
No matter how often I click that button, the variable bound in that template never updates.
Interestingly, if I create a string attribute directly on my Polymer and update it whenever the
addFirstHalf()
method is called:Polymer('x-pizza', { ready: function() { this.model = { firstHalfToppings: [], secondHalfToppings: [] }; }, pizzaState: '', addFirstHalf: function() { this.model.firstHalfToppings.push(this.currentFirstHalf); this.pizzaState = this.model.firstHalfToppings.join(','); }, // ... });And if I bind this variable into the template inside the same tag as my list model attribute:
<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>Then, not only is the new bound variable updated in the template each time that method is called, but the list model attribute is also updated:
So it seems that the Dart version was behaving correctly. Or at least consistently.
The last thing that I try tonight is observing the list properties of the model. If nothing else, I would like to have single place to accumulate changes. This turns out to be fairly easy with Polymer's observe property:
Polymer('x-pizza', { ready: function() { this.model = { firstHalfToppings: [], secondHalfToppings: [] }; }, observe: { 'model.firstHalfToppings': 'updatePizzaState', 'model.secondHalfToppings': 'updatePizzaState' }, updatePizzaState: function() { this.pizzaState = this.model.firstHalfToppings.join(',') + "\n" + this.model.secondHalfToppings.join(','); }, // ... });The path expressions that serve as keys in the
observe
property establish change listeners for the specified properties. Polymer is able to resolve those strings into objects and properties, listening to the appropriate event source for a change. And, when a change does occur, the updatePizzaStat
method is invoked.That works just fine. I think I am fairly close to fully understanding this approach and how Polymer wants it done. I may switch back to Polymer tomorrow to make certain.
Day #996
No comments:
Post a Comment