ECMAScript 6 + BackBone + Polymer
Last time weβve used Handlebars (http://k33g.github.io/2014/07/15/ES6-IN-ACTION-WITH-VIEWS.html ), but my favorite framework is Backbone because of the models and collections. But I hate the system of views and templating and Iβm jealous of Angular or even Knockout . But fortunately, Polymer exists!.
First refactoring our Models and Collections
Always in the same project:
Update bower.json
We need Backbone and Polymer:
{
"name" : "es6-project" ,
"version" : "0.0.0" ,
"dependencies" : {
"uikit" : "~2.8.0" ,
"jquery" : "~2.1.1" ,
"traceur" : "~0.0.49" ,
"polymer" : "Polymer/polymer# ~0.3.3" ,
"core-elements" : "Polymer/core-elements# ~0.3.3" ,
"backbone" : "~1.1.2"
},
"resolutions" : {
"jquery" : "~2.1.1"
}
}
And type bower update
command.
Donβt forget to reference Polymer (platform.js
), Underscore and Backbone in your index.html
file:
<!-- 1. Load platform.js for polyfill support. -->
<script src= "bower_components/platform/platform.js" ></script>
<script src= "bower_components/jquery/dist/jquery.min.js" ></script>
<script src= "bower_components/underscore/underscore.js" ></script>
<script src= "bower_components/backbone/backbone.js" ></script>
<script src= "bower_components/traceur/traceur.js" ></script>
Then change a little bit the structure of our project.
Change directory structure of the project
we no longer need:
core
directory (and model.js
and collection.js
)
humans-list.js
but keep components/
directory
es6-project/
βββ node_modules/
βββ public/
| βββ bower_components/
| βββ js/
| | βββ app/
| | βββ models/
| | | βββ human.js
| | | βββ humans.js
| | βββ components/
| | | βββ ...
| | βββ main.js
| βββ index.html
βββ .bowerrc
βββ bower.json
βββ package.json
βββ app.js
Modify human.js
Modify your code like this:
Note 1: We can write class Human extends Backbone.Model
because object model of Backbone is fully compliant with ECMAScript 6 .
class Human extends Backbone . Model {
constructor ( args ) {
super ( args ) /* mandatory */
//Getters and Setters : properties
Object . defineProperty ( this , "firstName" , {
get : function (){ return this . get ( "firstName" )} ,
set : function ( value ) { this . set ( "firstName" , value ); }
});
Object . defineProperty ( this , "lastName" , {
get : function (){ return this . get ( "lastName" )} ,
set : function ( value ) { this . set ( "lastName" , value ); }
});
}
}
export default Human ;
Note 2: Object.defineProperty(this, "firstName", {/* foo */})
allows to define property firstName
, so now I can write bob.firstName
instead of bob.get("firstName")
or bob.firstName = "Bob"
instead of bob.set("firstName", "Bob")
(and it will be useful with Polymer templates ).
Modify humans.js
Modify your code like this:
import Human from './human' ;
class Humans extends Backbone . Collection {
constructor ( args ) {
this . model = Human ;
this . url = "/humans" ;
super ( args ) /* mandatory */
}
}
export default Humans ;
Create our Polymer component
Create two new files in components/
directory : humans-list.html
and humans-list.js
es6-project/
βββ node_modules/
βββ public/
| βββ bower_components/
| βββ js/
| | βββ app/
| | βββ models/
| | | βββ human.js
| | | βββ humans.js
| | βββ components/
| | | βββ humans-list.html
| | | βββ humans-list.js
| | βββ main.js
| βββ index.html
βββ .bowerrc
βββ bower.json
βββ package.json
βββ app.js
Content of humans-list.html
Define a Polymer component is very easy:
<link rel= "import" href= "../../../bower_components/polymer/polymer.html" >
<polymer-element name= "humans-list" >
<template>
<ul>
<template repeat= "{{humans}}" >
<li> {{firstName}} {{lastName}}</li>
</template>
</ul>
</template>
<script>
/* Load ES6 script */
System . import ( '../../js/app/components/humans-list' );
/* ok this part is weird, there is probably something to do about the path*/
</script>
</polymer-element>
Content of humans-list.js
Iβve decided to externalize the JavaScript code of the component because I want to write it with ECMAScript 6 grammar:
import Human from '../models/human' ;
import Humans from '../models/humans' ;
Polymer ( "humans-list" ,{
ready : function () {
this . humansCollection = new Humans ();
// subscribe to fetch event
this . humansCollection . on ({ "fetch" : this . update ()});
this . humansCollection . fetch (). done (() => { /* get all humans from database */
if ( this . humansCollection . size () == 0 ) { /* no human in database, then populate the collection */
var bob = new Human ({ firstName : 'Bob' , lastName : 'Morane' });
var john = new Human ({ firstName : 'John' , lastName : 'Doe' });
var jane = new Human ({ firstName : 'Jane' , lastName : 'Doe' });
/* save models */
bob . save (). done (
() => john . save (). done (
() => jane . save (). done (
() => this . humansCollection . fetch (). done ( /* fetch again */
console . log ( "humans created:" , this . humansCollection )
)
)
)
);
} else { /* display humans */
console . log ( "humans loaded:" , this . humansCollection );
}
})
},
update : function () { // called when collection is "fetched"
this . humans = this . humansCollection . models ;
}
});
Reference the component
Youβve just to add this in index.html
:
<link rel= "import" href= "js/app/components/humans-list.html" >
and you can use your component like this:
<humans-list></humans-list>
And β¦ Youβve just to refresh your page (Dontβ forget to run node app.js
).
The more I work with ES6 , the more I love it.
Next time, Iβll explain my workflow to βtranspileβ offline my project with Traceur and Gulp .
Have a nice day!
You can find source codes here : https://github.com/js-experiments/es6-project