I think MVVM is overkill for most Polymer elements. So tonight I apply it to an extremely simplistic Polymer element to confirm my bias.
I kid. I kid.
Several Patterns in Polymer readers have inquired about MVVM (Model-View-ViewModel) and I have replied that I think it likely overkill. But I have not really investigated—thoroughly or otherwise. I start with the simple case, not to quickly confirm my bias and move one, but to better help me get a grip on the necessary concepts. I tend to read about MV-whatever patterns and then lump them in the same place in my brain. Hopefully this will help.
The simple element remains the initial
<hello-you>
element in the book:I continue to use last night's Polymer 0.8 code, mostly so I can continue to get a feel for the new stuff. I have the feeling this may, inadvertently, be a reasonable choice for MVVM (though it is still overkill). The “Fabulousize Me” button point to a method in the backing class that updates colors in the view. That sounds very much like view logic instead of business logic, which should push the code in a View Model.
But I'm getting ahead of myself...
The view in a Polymer element is simple enough. It is the
<template>
for the Polymer element. For the <hello-you>
element, this is the view code:<link rel="import" href="../bower_components/polymer/polymer.html"> <polymer-element name="hello-you"> <template> <h2>Hello <span>{{your_name}}</span></h2> <p> <input value="{{your_name::input}}"> <input type=submit value="Fabulousize Me!" on-click="feelingLucky"> </p> <p class=help-block> <content></content> </p> </template> <script src="hello_you.js"></script> </polymer-element>The
your_name
property comes directly from the model. The ViewModel can proxy it, but it is the purview of the Model. The your_name
property is part of the business logic of <hello-you>
. The feelingLucky()
method on the other hand...The backing class currently looks like:
var colors = ['red', 'blue', 'green']; Polymer({ is: 'hello-you', your_name: '', feelingLucky: function() { var num = Math.floor(colors.length*Math.random()); this. querySelector('h2'). style.color = colors[num]; } });My first impression is that this is a ViewModel, not a Model. Certainly the
feelingLucky()
method is ViewModel code since it only interacts with the View. But if this is ViewModel, what does the Model look like?In this case, I think it is nothing more than:
function Person(name) { this.name = name; }Again, this is a very simplistic Polymer element, so it makes sense that the Model is simple. As the code evolves, I could add first and last name properties, a full name computed method, and more. Before I get to that, how can I get this into the Polymer ViewModel? I kind of want to declare a
you
property as: // ...
properties: {
you: {
type: Person
}
},
//...
That will not work, however since properties can only be native types like String and Object. Well, the most basic model would be just an Object, so I try:Polymer({ is: 'hello-you', properties: { you: { type: Object } }, // ... }In the View, I give direct access to this
you
Object: <h2>Hello <span>{{you.name}}</span></h2>
<p>
<input value="{{you.name::input}}">
<input type=submit
value="Fabulousize Me!"
on-click="feelingLucky">
When I try to enter a name in the <input>
field, however, I get:Uncaught TypeError: Cannot set property 'name' of undefinedHrm... even the simple Object version of the Model is not making this easy. Perhaps I need to initialize the
you
property?I try this in the
created()
callback: // ...
created: function(){
this.you = {name: ''};
}
// ...
But I get the following when loading the element:Uncaught SyntaxError: Unexpected identifierI am unsure why that fails. I can get that working by changing to the
ready()
lifecycle method, but I eventually realize this is not how Polymer wants me to do this. I should be creating a default value in the properties declaration:var colors = ['red', 'blue', 'green']; Polymer({ is: 'hello-you', properties: { you: { type: Object, value: {name: ''} } }, feelingLucky: function() { var num = Math.floor(colors.length*Math.random()); this. querySelector('h2'). style.color = colors[num]; } });With that, I have something moving toward MVVM. It does not feel like a real MVVM implementation—at least not without a method or two in the Model. Still, it is a baby step in the right direction. I am unsure how I want to get a real Model tomorrow, but I may start by creating another, UI-less Polymer object as the first try. If nothing else, this should make it easier to get observable properties and methods.
Day #23
No comments:
Post a Comment