Tuesday, December 2, 2014

Prepping a Polymer Element for Release (Bower)


The best laid plans… are something I clearly know nothing about.

I had planned to try out my new <a-form-input> Polymer, which acts as a base element for other Polymer elements that want native <form> behavior, in a separate Polymer element. My thinking was to identify areas in which my organization structure might not work well in a reusable setting. I never got that far as I took a peak at how Core Elements solves this. Although I could not adapt their approach directly (each core-element is a subdirectory in the project's test harness), I did find my approach lacking.

But tonight I am going to use this element in a separate element. No distractions!

I start by updating my project's bower.json so that Bower will install <a-form-input> from my local filesystem (I will publish once this is working):
{
  "name": "plain_old_forms",
  "dependencies": {
    "polymer": "Polymer/polymer",
    "a-form-input": "/home/chris/repos/a-form-input"
  }
}
Annoyingly, Bower copies the repository when doing this instead of creating a symbolic link:
bower install
bower a-form-input#*          checkout master
bower a-form-input#*          resolved /home/chris/repos/a-form-input#7286265529
bower a-form-input#*           install a-form-input#7286265529

a-form-input#7286265529 bower_components/a-form-input
└── polymer#0.5.1
No matter, the only reason that I would want the symbolic link is to try changes to the library immediately in my project. But it's going to work the first time… because that always happens.

I am going to modify my old friend <x-pizza> to support native HTML forms. I start in the HTML definition, which needs to import the <a-form-input> definition and then extend it:
<link rel="import" href="../bower_components/polymer/polymer.html">
<link rel="import" href="../bower_components/a-form-input/a-form-input.html">
<polymer-element name="x-pizza" extends="a-form-input">
  <template><!-- ... --></template>
  <script src="x_pizza.js"></script>
</polymer-element>
The import path is Bower thanks to the Bower install. This should ensure that, assuming everything works, I am good to release this to general consumption. The extends attribute is how Polymer does "inheritance". With that, <x-pizza> should operate as a real live HTML form element. It should also add the name and value properties to the <x-pizza> backing class. I will need to update the value property inside of the backing class, so I move to that next.

The backing class requires only two changes—one obvious and the other the opposite of obvious:
Polymer('x-pizza', {
  attached: function() {
    this.super();
    this._updateGraphic();
  },
  // ...
  _updateText: function() {
    this.value = this.model.firstHalfToppings.join(',') + "\n" +
      this.model.secondHalfToppings.join(',') + "\n" +
      this.model.wholeToppings.join(',');
  },
  // ...
});
The obvious change is that I need to assign the text value of the pizza's toppings to this.value. This is an HTML form input now, so it needs to update the value property. The less obvious change is the need to call this.super() in the attached() lifecycle method. Without this, the method of the same name in the base element/class, <a-form-input> will not be invoked, which breaks everything. This being JavaScript, inheritance never comes naturally, so I always forget this… until everything breaks.

Last, I assign a name attribute to <x-pizza> element in the containing document like I would any other form element:
<!doctype html>
<html lang="en">
  <head>
    <!-- ... -->
    <script src="bower_components/webcomponentsjs/webcomponents.js"></script>
    <link rel="import" href="elements/x-pizza.html">
  </head>
  <body>
    <form action="test" method="post">
      <h1>Plain-old Form</h1>
      <input type=text name="plain_old_param">
      <x-pizza name="pizza_toppings"></x-pizza>
      <button>Order my pizza!</button>
    </form>
  </body>
</html>
With that… I have a working Polymer element that injects native HTML form values:



Submitting this form includes the value from <x-pizza>:
plain_old_param:Data from a regular input
pizza_toppings:pepperoni
sausage
green peppers
So this would appear to be working.

Which means it is time to create the public GitHub repository:
$ git remote add origin git@github.com:eee-c/a-form-input.git
$ git push -u origin master
...
To git@github.com:eee-c/a-form-input.git
 * [new branch]      master -> master
Branch master set up to track remote branch master from origin.
Then I prep for bower publishing by tagging:
git tag -a v0.0.1 -m "Tag version 0.0.1"
$ git push --tags
...
To git@github.com:eee-c/a-form-input.git
 * [new tag]         v0.0.1 -> v0.0.1
At this point I register with Bower:
$ ower register a-form-input https://github.com/eee-c/a-form-input.git
bower                          convert Converted https://github.com/eee-c/a-form-input.git to git://github.com/eee-c/a-form-input.git
...
bower a-form-input#*          resolved git://github.com/eee-c/a-form-input.git#0.0.1
[?] Registering a package will make it installable via the registry (https://bower.herokuapp.com), continue? Yes
bower a-form-input            register git://github.com/eee-c/a-form-input.git

Package a-form-input registered successfully!
Nice!

I modify the bower.json so that it points to this newly released version instead of my local repository:
{
  "name": "plain_old_forms",
  "dependencies": {
    "polymer": "Polymer/polymer",
    "a-form-input": "~0.0.1"
  }
}
And, after a quick reinstall (rm -rf bower_components; bower install), I again have a working native HTML form input—this time pulled from Bower. I still need a bit of documentation for this element on the GitHub page, but this looks to be ready for public consumption.


Day #12

No comments:

Post a Comment