POLYMER + TYPESCRIPT the marvelous couple


Polymer 1.0 - why I love component based approach

From last GoogleIO - Polymer 1.0 production ready has been announced

I use Polymer ( currently the 0.5) in my projects and love the component based 
development approach and I'm grateful  to webcomponent/polymer teams having ported such approach also in front end development

This is the  most important point for me and the main reason because i haven't used the more famous AngularJS
When evaluating AngularJS 1.x it was impressed in term of features but, except for the mysterious directives, it didn't promote a components approach but rather a way to better arrange a complex javascript projects giving to developers features that, until then, was exclusively provided by back-end frameworks

However the widely announced AngularJS 2 will rely on webcomponent and the main focus has been put on directive development, so my choice to follow the component based approach in front end development seems to go in the right direction 

Role of Object Oriented paradigm in component based approach

As you know the object oriented paradigm has been very important to push component based approach so, what missed me, was use the same language expressiveness to work in front end development. 
Here is where coming in scene Typescript. Typescript is a 'transpiler' (ie source-to-source compiler) that, as result of its compilation, produce pure and well written javascript. Typescript as language has all the features that allow us to use, in clear and easy way, object oriented and functional constructs, it anticipates the ecma6 features and promise to be compatible  with them.

For who doesn't know typescript yet, please take a look to TypescriptLang before continue, for the other ones let's start to coding

PolymerTS project

About typescript definitions, instead to use the official DefinitelyTyped, I've find out a very cool project on Github "PolymerTS" that has introduced the annotation concept relies on decorator feature provided by Typescript language. 
Again in my opinion the annotations increase the semantic of the code avoiding to deal with annoying boilerplate.

In this proof of the concept i've used :

Polymer Starter Kit

Using Polymer Starter Kit we generate a Basic, full featured, Polymer application. So open a shell, in chosen project's directory, and type:
> yo polymer
and then
> bower install 
after that,  install the PolymerTS stuff typing
> bower install polymer-ts --save

Create an Element

Now create a new element. For this article I create a simple timer element
 > yo polymer:element my-timer
Note: answer Y at question :
Would you like to include an import in your elements.html file?

Update Element's template

The above command will generate  file my-timer.html in app/elements/my-timer folder


<link rel="import" href="../../bower_components/polymer/polymer.html">
<dom-module id="my-timer">  
  <style>
  :host {
    display: block;
    }  
  </style>  
  <template>
    <div>Hello from <span>{{foo}}</span></div>  
  </template>
</dom-module>

<script>
(function() {  
  Polymer({
    is: 'my-timer',
    properties: {
      foo: {
        type: String,
        value: 'bar',
        notify: true
        }
    }  
  });
})();
</script>

In order to switch from javascript to typescript edit such file, remove explicit javascript and include an external file my-timer.js, moreover we will update template to reflect the timer appearances. 
The new my-timer.html now, will appear as shown below

<dom-module id="my-timer">
 <template>
 <p>
   from <span>{{start}}</span> is now: <span>{{count}}  </span>
 </p>
 </template>
</dom-module>
<script src="my-timer.js"></script>

Implement Element 

After we defined template within html file, now we go under my-timer directory and add a new file named my-timer.ts where, using amazing typescript, we will declare element and will implement its behaviour.  
After file creation type the code below:

@component("my-timer")
class MyTimer extends polymer.Base implements polymer.Element
{
   @property({ type: Number, value: 0 })
   public start: number;

   @property()
   public count: number;

   private timerHandle: number;

   ready() {
      console.log( this["is"], "ready!");

      this.count = this.start;
      this.timerHandle = setInterval(() => {
        this.count++;
      }, 1000);
   }

   detatched() {
      clearInterval(this.timerHandle);
   }
}

createElement( MyTimer );

Let analyse the code above:

@component - annotation

@component annotation is enough to declare the class as a webcomponent. The class itself has to implement polymer.Element, that mainly declare component lifecycle methods and extends polymer.Base in order to inherits the utility methods provided by Polymer implementation. (see declarations in polymer-ts.ts)

@component("my-timer"
class MyTimer extends polymer.Base implements polymer.Element

@property - annotation

@Property annotation is used to declare a public property of component and its characteristics providing some meta-informations.

   @property({ type: Number, value: 0 })
   public start: number;

   @property()
   public count: number;

The available meta-informations are declared in the following interface ( refer to polymer-ts.ts )

export interface Property { name?: string; type?: any; value?: any; reflectToAttribute?: boolean; readonly?: boolean; notify?: boolean; computed?: string; observer?: string; }

ready(), detached() - methods

Ready and detached are two methods related to component's lifecycle declared in polymer.Element interface ( refer to polymer-ts.ts ).  this contains the behaviour of our component that, simply, will show a timer starting from start value and updating count every sencond

ready() { console.log( this['is'], 'ready!'); this.count = this.start; this.timerHandle = setInterval(() => { this.count++; console.log( 'count', this.count); }, 1000); } detatched() { clearInterval(this.timerHandle); }

createElement - function

The createElement global function ( refer to polymer-ts.ts ) allows to create/setup the element. Such function is required before we can use the new element.

createElement( MyTimer );

Preparing to use Element(s)

Before to use our custom elements we have to do some steps required once only

Transpilation

first we have to transpile (ie source-to-source compilation)  the typescript to javascript.
This task is pretty straightforward using the atom-typescript package , it is enough right-click on typescript file, select build and magically will appear the javascript counterpart.

The first time that we will execute a transiplation will be created also the file tsconfig.json that  is the project file that keeps track of all your typescript's files, for make your life easier I suggest to move it in the project's root directory

Include polymerTS implementation

Now open the file element.html in app/elements folder and add, before the custom element declarations, the inclusion of polymerTS implementation as shown below

<script src="../bower_components/polymer-ts/polymer-ts.js"></script>

Use element


Now we are ready to use the new "my-timer" element. I want put such element in the mainToolBar , so open file index.html in app folder  and add my-timer element as child of paper-toolbar as shown below


<!-- Main Toolbar --> <paper-toolbar id="mainToolbar"> <paper-icon-button id="paperToggle" icon="menu" paper-drawer-toggle></paper-icon-button> <span class="flex"></span> <!-- Toolbar icons --> <paper-icon-button icon="refresh"></paper-icon-button> <paper-icon-button icon="search"></paper-icon-button> <my-timer start="1"></my-timer>



That's all , now run  > gulp serve  and we will have our app running with our element  on top-right of the header as shown below








Conclusion


Hope that you agree with me about the fact that  the  Web Componentization is a sort of revolution concerning web development.

The Javascript is the language that is driving such revolution (and not only concerning front-end development). 

On the other hand, Typescript and in the near future: ECMA6, fills the gaps respect other, more mature,  development languages allowing, finally, to implement with it "large" enterprise application.

Note:

Take note that PolymerTS is under active development and a lot of a new features are coming out like inline component. Currently  I'm using the release  0.0.9.

Code:

You can find the example in article on GITHUB, I've forked the original PolymerTS project and created the starterkit branch for the article. 





Comments

Popular posts from this blog

PlantText: The new "Online" UML Editor powered by PlantUML

PlantUML & Maven - Enrich your project's documentation