Friday, April 11, 2014

Not Just Composable, but Smaller, Composable Parts


Today, in my efforts to finish off Patterns in Polymer, I am (yet again) revisiting the approach that I took to model driven views (MDV).

Separate feedback reports have identified confusion and offered suggestions for that chapter. I have struggled with exactly how to go about addressing the issue, but I think that I have finally got it. Part, if not all, of the problem was that the element that I am currently using to drive the narrative in the chapter is too big. The element is the <x-pizza> Polymer element that I go on to use in an SVG chapter and the Strategy Pattern chapter on which I am currently working.

In the MDV chapter, the template alone is nearly 50 lines of HTML templating that starts with:
<polymer-element name="x-pizza">
  <template>
    <h2>Build Your Pizza</h2>
    <pre>{{pizzaState}}</pre>
    <p>
      <select class="form-control" value="{{currentFirstHalf}}">
        <option>Choose an ingredient...</option>
        <option value="{{ingredient}}" template repeat="{{ingredient in ingredients}}">
          {{ingredient}}
        </option>
      </select>
      <button on-click="{{addFirstHalf}}" type="button" class="btn btn-default">
        Add First Half Topping
      </button>
    </p>
    <!-- ... -->
  </template>
  <script type="application/dart" src="x_pizza.dart"></script>
</polymer-element>
(the JavaScript template is identical aside from the <script> tag being used.

At least one reader suggested breaking the thing up into a main <x-pizza> element and smaller <x-pizza-topping> elements, that latter holding the actual model describing the currently selected pizza toppings. As the reviewer correctly put it, this “would be more inline with the polymer ideal of small, composable elements.” Recently, I have done just that, which led to the Strategy Pattern.

But the question still remains, how do I introduce MDV without getting into a discussion of composition in the Polymer work in addition to MDV? The answer is so simple that I don't know why it didn't occur to me before: I will introduce only the <x-pizza-toppings> element in the MDV chapter. I can then compose it into the <x-pizza> element in the Strategy chapter.

The only other outstanding item on that chapter has to do with making classes and properties observable. A reader found that this did not work. I suspect that this was due to not importing the Polymer package (which I neglected to mention in the book). Given the re-organization that I have already done, I will almost certainly not wind up doing this, but it seems a good thing to know. In the Dart version of this element, I had been keeping the state in an actual object with a class and everything:
import 'package:polymer/polymer.dart';

@CustomTag('x-pizza')
class XPizza extends PolymerElement {
  // Polymer stuff that uses a Pizza model
}

@observable
class Pizza {
  List<String> firstHalfToppings = toObservable([]);
  List<String> secondHalfToppings = toObservable([]);
  List<String> wholeToppings = toObservable([]);
}
Before ripping this out and starting from scratch, I give it a try with the most recent version of Polymer.dart. I still works, though I get a warning:
[Warning from Observable on model_example|lib/elements/x_pizza.dart]:
package:model_example/elements/x_pizza.dart:61:1: @observable on a class no longer has any effect. It should be placed on individual fields.
And, indeed that works fine. The individual toppings properties are already observable by virtue of the toObservable() function wrapper. I remove the @observable annotation from the Pizza class:
class Pizza {
  List<String> firstHalfToppings = toObservable([]);
  List<String> secondHalfToppings = toObservable([]);
  List<String> wholeToppings = toObservable([]);
}
With that, I have no warnings and the example still works:



As I said, that is good to know, but I will now remove that class entirely, opting instead to use a simple list as my “model”:
@CustomTag('x-pizza-toppings')
class XPizzaToppings extends PolymerElement {
  // ...
  List<String> model = [];
  // ...
}
That is much easier to introduce, but still should serve to illustrate MDV nicely.




Day #31

1 comment:

  1. I did wonder about using @observable on the class since I earlier got that same warning.

    ReplyDelete