Friday, May 30, 2014

Model Driven Polymer Attributes


Up tonight, a (hopefully) simple update of a Polymer feature.

Last night I was able to use attributes to set the initial toppings for a pizza in the <x-pizza> Polymer-based custom element:



Today, I would like to do the opposite: ensure that topping changes are reflected in the same attributes that are used to set the initial toppings. That is, if an <x-pizza> starts with:
<x-pizza toppings="pepperoni,sausage"></x-pizza>
And the user adds green peppers, then the attribute should report:
<x-pizza toppings="pepperoni,sausage,green peppers"></x-pizza>
Mercifully, this is fairly easy in Polymer. It also helps that the infrastructure is already in place in the backing x_pizza.dart backing class. The whole toppings attribute (toppings) and the first and second half attributes (toppings1 and toppings2) are already published in the backing class. I also have an updatePizzaState method that gets invoked whenever the model in my model driven view is updated:
@CustomTag('x-pizza')
class XPizza extends PolymerElement {
  // ...
  @published String toppings = '';
  @published String toppings1 = '';
  @published String toppings2 = '';

  XPizza.created(): super.created() {
    model = new Pizza()
      ..changes.listen(updatePizzaState);
    // ...
  }
  // ...
}
The above changes stream just works because the model class has all the observables in place:
class Pizza extends Observable {
  ObservableList<String> firstHalfToppings = toObservable([]);
  ObservableList<String> secondHalfToppings = toObservable([]);
  ObservableList<String> wholeToppings = toObservable([]);

  Pizza() {
    firstHalfToppings.changes.listen((_)=> notifyChange(_));
    secondHalfToppings.changes.listen((_)=> notifyChange(_));
    wholeToppings.changes.listen((_)=> notifyChange(_));
  }
}
Back in the MDV class, updatePizzaState needs only a new secondary method call, to the new _updateAttributes() method which simply assigns the three attributes::
  
  // ...
  updatePizzaState([_]) {
    _updateText();
    _updateGraphic();
    _updateAttributes();
  }
  // ...
  _updateAttributes() {
    toppings = model.wholeToppings.join(',');
    toppings1 = model.firstHalfToppings.join(',');
    toppings2 = model.secondHalfToppings.join(',');
  }
  // ...
And that does the trick nicely:



I am not sure that is the simplest solution possible, so I had hoped to drive some of this with tests. Unfortunately, testing turns out to be a little harder than expected. But that's a tale for tomorrow. For today, I am happy that updating attributes had no unexpected surprises.


Day #79

1 comment:

  1. Dart code is still difficult to read for me: all those ([]) and (_) and (',') and ({})....! Somebody should write a Dart Cheat Sheet for those enigmatic notations. For example: ([]) = ( new List() ).

    ReplyDelete