Being a typical aspect of Object Oriented Design, inheritance, and mixins, provide the means by which modular reuse patterns can be facilitated within a given system. Similarly, Polymer facilitates code reuse patterns by employing the notion of shared behaviors modules. Let’s take a quick look at how to leverage them in Polymer when using ES6 classes.
Implementing Behaviors
Implementing a Behavior is quite simple, just define an object within a block expression or an IIFE, and expose it via a namespace, or module loader of choice:
1 2 3 4 5 6 7 8 9 10 11 12 13 | 'use strict'; (() => { // define the behavior const SomeBehavior = { ... }; // add the behavior to a specific namespace ... const ns = (window.SomeNamespace = window.SomeNamespace || {}); ns.SomeBehavior = SomeBehavior; })(); |
some-behaviors.js
Then, include the behavior in a corresponding .html document of the same name so as to allow the behavior to be imported by subsequent elements:
1 2 3 | <script src="some-behaviors.js" type="text/javascript"></script> |
some-behavior.html
Extending Behaviors
After having defined and exposed a given Behavior, the Behavior can then be extended from element classes by defining a behaviors getter / setter
as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 'use strict'; // define element class ... class SomeElement { beforeRegister(){ this.is = 'some-element'; } // implement behaviors getter, returning an array of behaviors // which are to be extended ... get behaviors() { return [window.SomeNamespace.SomeBehavior] } // implement corresponding setter ... set behaviors(val) { this._behaviors = val; } } |
Once the behavior has been extended, simply import the behavior in the element’s template (or element bundle, etc.) and it is available to the template class:
1 2 3 4 5 6 7 8 9 10 | <!-- import behavior module --> <link rel="import" href="some-behavior.html"> <dom-module id="some-element"> <template> ... </template> <script src="some-element.js" type="text/javascript"></script> </dom-module> |
Implementing Multiple Behaviors
Similar to individual behaviors, multiple behaviors can also be defined and extended:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 'use strict'; (() => { // define first behavior ... const FirstBehavior = { properties: { first: { type: String, value: 'First Behavior' } } }; // add the behaviors to the given namespace ... const ns = (window.SomeNamespace = window.SomeNamespace || {}); ns.FirstBehavior = FirstBehavior; })(); |
first-behavior.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 'use strict'; (() => { // define second behavior ... const SecondBehavior = { properties: { second: { type: String, value: 'Second Behavior' } } }; // add the behaviors to the given namespace ... const ns = (window.SomeNamespace = window.SomeNamespace || {}); ns.SecondBehavior = SecondBehavior; })(); |
second-behavior.js
In certain cases, I have found it helpful to group related behaviors together within a new behaviors (array) which bundles the individual behaviors together:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | 'use strict'; (() => { // define first behavior ... const FirstBehavior = { properties: { first: { type: String, value: 'First Behavior' } } }; // define second behavior ... const SecondBehavior = { properties: { second: { type: String, value: 'Second Behavior' } } }; // define third behavior ... const ThirdBehavior = { properties: { third: { type: String, value: 'Third Behavior' } } }; // define a behavior which bundles the related behaviors ... const FourthBehavior = [ FirstBehavior, SecondBehavior, ThirdBehavior ]; // add the behaviors to a specific namespace ... const ns = (window.SomeNamespace = window.SomeNamespace || { 'FirstBehavior' : FirstBehavior, 'SecondBehavior' : SecondBehavior, 'ThirdBehavior' : ThirdBehavior, 'FourthBehavior' : FourthBehavior }); })(); |
Note: As can be seen in the FourthBehavior, a behavior can also be implemented as an Array of previously defined behaviors.
Extending Multiple Behaviors
As with extending individual behaviors, multiple behaviors can also be extended using a behaviors getter / setter
. However, when extending multiple behaviors in ES6, there are syntactic differences which one must take note of. Specifically, the behaviors getter
must be implemented as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | // define element class ... class CustomElement { beforeRegister(){ this.is = 'custom-element'; } // implement behaviors getter, returning an array of behaviors // which are to be extended via this._behaviors, or, assigning // and returning the array of behaviors to be extended should // this._behaviors be undefined ... get behaviors() { const ns = window.SomeNamespace || {}; return this._behaviors || (this._behaviors = [ ns.FirstBehavior, ns.SecondBehavior, ns.ThirdBehavior ]); } // implement corresponding setter ... set behaviors(val) { this._behaviors = val; } } |
And that’s basically all there is to it. Hopefully this article helped outline how Polymer Behaviors can easily be leveraged when implementing elements as ES6 classes. Enjoy.