Polymer : “les mains dans le cambouis”, Ă©pisode 1

Nous parlerons de:

  • Les prĂ©-requis et installation
  • Ecriture de 2 composants polymer
  • Communication entre composants polymer

Polymer est un nouveau framework javascript Ă  base de composants web Ă©crits par des dĂ©veloppeurs de chez Google. Il s’appuie donc sur la norme des Web Components et parie sur les Ă©volutions des navigateurs dans le futur (notamment sur l’implĂ©mentation du pattern Observer, comme le fait Angular). Polymer en attendant que ces Ă©volutions “arrivent” fournit les polyfills nĂ©cessaires. Polymer est tout jeune et en plein dĂ©veloppement (donc sujet Ă  modifications frĂ©quentes), mais il mĂ©rite que l’on s’y intĂ©resse (ne serait-ce que parce qu’il vient de chez Google) car il est assez simple d’accĂšs, aussi magique qu’Angular (mais probablement avec un temps d’apprentissage plus rapide). De plus Polymer est aussi portĂ© cĂŽtĂ© Dart et pourrait devenir la partie “IHM” d’Angular (Ă  vĂ©rifier).

Cet article ne va pas vous parler plus que ça du concept des “Web Components”. Je vous invite vivement à lire l’excellent article de @julienvey sur le sujet (en français en plus donc profitez-en) : http://www.infoq.com/fr/articles/polymer-nouveaux-standards-web.

Cet article va plutĂŽt ĂȘtre “pratico-pratique” pour vous mettre le pied Ă  l’étrier si vous avez envie de voir rapidement si Polymer est fait pour vous.

Tous les exemples présentés dans cet épisode et dans ceux à venir sont(seront) disponibles ici : https://github.com/k33g/polymer-les-mains-dans-le-cambouis.

Pour cet épisode vous trouverez tous les éléments ici : https://github.com/k33g/polymer-les-mains-dans-le-cambouis/tree/master/01-introduction

Pré-requis

1 serveur web

Tout d’abord, il vous faudra il vous faudra un serveur web. Pour ce 1er Ă©pisode, nul besoin de quelque chose de trĂšs compliquĂ©. Si vous ĂȘtes sous OSX ou Linux, une simple commande python -m SimpleHTTPServer dans votre rĂ©pertoire de travail fera l’affaire. Sinon vous pouvez aussi utiliser https://github.com/nodeapps/http-server, pour l’installer : npm install http-server -g et ensuite il suffit de lancer la commande http-server dans votre rĂ©pertoire de travail.

Il ne vous reste plus qu’à crĂ©er un rĂ©pertoire de travail que nous appellerons 01-introduction.

NĂ©anmoins n’importe quel serveur http, serveur d’application convient, d’ailleurs dans un prochain Ă©pisode nous utiliserons Polymer avec Play 2 Scala.

Installation de Polymer

Pour installer Polymer, le plus simple pour le moment est d’utiliser Bower. Pour l’installer, rien de plus simple : npm install -g bower (vous aurez compris qu’il sera plus pratique d’avoir installĂ© NodeJS sur votre poste, mĂȘme si vous pouvez reproduire toutes ces manipulation Ă  la main).

Pour “installer” Polymer :

cd 01-introduction
bower install polymer

Bower a crée un répertoire bower_components avec les librairies nécessaires dans 2 sous-répertoires platform et polymer.

Il ne vous reste plus qu’à crĂ©er une page index.html avec le code suivant :

<!DOCTYPE html>
<html>
<head>
  <title>01-introduction</title>
  <!-- Load Polymer -->
  <script src="bower_components/platform/platform.js"></script>
  <script src="bower_components/polymer/polymer.js"></script>

</head>
<body>

</body>
</html>

Nous sommes prĂȘts.

Premier composant Polymer (Polymer element)

Un composant Polymer se compose gĂ©nĂ©ralement d’une portion de code html et d’une portion de code javascript sous cette forme :

<polymer-element name="mon-composant">
  <template>
    <!-- foo -->
  </template>
  <script>
    Polymer("mon-composant",{
      ready: function(){

      }
    });
  </script>
</polymer-element>

La mĂ©thode ready() est dĂ©clenchĂ©e Ă  l’initialisation du composant. Maintenant, faisons le notre. Et ainsi vous disposez d’un nouveau tag html <mon-composant>.

Création du composant hello-john-doe

Dans votre répertoire de travail, créez un répertoire components puis dans ce sous-répertoire créez un fichier html hello-john-doe.html et saisissez le code suivant :

<polymer-element name="hello-john-doe">
  <template>
    <h1>Hello {{name}}</h1>
    <input value="{{name}}">
  </template>
  <script>
    Polymer("hello-john-doe",{
      ready: function(){
        this.name = "John Doe";
      }
    });
  </script>
</polymer-element>

Remarque : le nom d’un composant doit toujours ĂȘtre au minimum composĂ© de 2 parties sĂ©parĂ©es par un -.

DĂ©claration et utilisation du composant

Dans votre page index.html, il faut dĂ©clare votre composant au niveau de <head></head> de cette façon : <link rel="import" href="components/hello-john-doe.html"> et ensuite il suffira d’utiliser <hello-john-doe></hello-john-doe> dans votre page html, comme ceci :

<!DOCTYPE html>
<html>
<head>
  <title>01-introduction</title>
  <!-- Load Polymer -->
  <script src="bower_components/platform/platform.js"></script>
  <script src="bower_components/polymer/polymer.js"></script>

  <!-- my components -->
  <link rel="import" href="components/hello-john-doe.html">
</head>
<body>
  <hello-john-doe></hello-john-doe>
</body>
</html>

Maintenant vous pouvez lancer votre serveur web (ie: http-server) et appeler votre page dans votre navigateur : http://localhost:numero_de_port :

Alt "001.png"

Vous pouvez voir que la valeur de name a bien été initialisée à John Doe avec la méthode render(). Et si vous saisissez un nouveau nom, le contenu du tag <h1></h1> change automatiquement :

Alt "002.png"

Tips : AccĂ©der Ă  un composant de l’extĂ©rieur :

Ce n’est pas forcĂ©ment une bonne pratique, mais c’est bon Ă  savoir. Une fois votre composant dĂ©clarĂ© dans votre page html, c’est un composant du DOM Ă  part entiĂšre, donc si vous souhaitez y accĂ©der, vous pouvez procĂ©der de la maniĂšre suivante pour obtenir une rĂ©fĂ©rence Ă  celui-ci :

var helloJohn = document.querySelectorAll("hello-john-doe")[0]

Et ainsi, vous pouvez accéder à ses propriétés et les modifier, comme name dans notre exemple : helloJohn.name = "Actarus", et le changement dans le composant se fera automatiquement :

Alt "003.png"

Instances du composant hello-john-doe

DĂ©clarez un 2 Ăšme composant <hello-john-doe> dans votre page :

<body>
  <hello-john-doe></hello-john-doe>
  <hr>
  <hello-john-doe></hello-john-doe>
</body>

Ouvrez à nouveau la page avec votre navigateur, vous noterez que les 2 composants <hello-john-doe> fonctionnent de maniÚre indépendante :

Alt "004.png"

OnChange() et autres petites choses 


A tout propriĂ©tĂ© d’un composant Polymer, vous pouvez associer une mĂ©thode qui sera dĂ©clenchĂ©e Ă  chaque changement de la propriĂ©tĂ©, cette mĂ©thode prend comme nom, le nom de la propriĂ©tĂ© + Changed, donc dans le cas qui nous concerne ce sera nameChanged. Modifiez donc le code de notre composant de la maniĂšre suivante :

  • ajout d’un id au tag h1 : <h1 id="hello">Hello {{name}} </h1>
  • ajout d’une mĂ©thode nameChanged()
<polymer-element name="hello-john-doe">
  <template>
    <h1 id="hello">Hello {{name}}</h1>
    <input value="{{name}}">
  </template>
  <script>
    Polymer("hello-john-doe",{
      ready: function(){
        this.name = "John Doe";
      },
      nameChanged : function() {
        if(this.name != "John Doe") {
          this.$.hello.style.color = "red";
        } else {
          this.$.hello.style.color = "green";
        }
      }
    });
  </script>
</polymer-element>

Ouvrez Ă  nouveau la page avec votre navigateur :

Alt "005.png"

Vous noterez l’utilisation de $ qui permet d’accĂ©der automatiquement Ă  l’élĂ©ment d’id hello.

Ajoutons un “OnClick”

Proposons un peu plus d’action Ă  notre composant en lui ajoutant un bouton, et une mĂ©thode associĂ©e au “click” sur le bouton :

  • dans la partie “html” (donc Ă  l’intĂ©rieur de <template></template>), on ajoute : <button on-click=" {{clickMe}} ">Click Me!</button> oĂč clickMe dans ` {{clickMe}} ` est le nom de la mĂ©thode appelĂ© lorsque l’on clique sur le bouton
  • dans la partie “javascript”, on ajoute une mĂ©thode clickMe()

Nous obtiendrons le code suivant :

<polymer-element name="hello-john-doe">
  <template>
    <h1 id="hello">Hello {{name}}</h1>
    <input value="{{name}}">
    <button on-click="{{clickMe}}">Click Me!</button>
  </template>
  <script>
    Polymer("hello-john-doe",{
      ready: function(){
        this.name = "John Doe";
      },
      nameChanged : function() {
        if(this.name != "John Doe") {
          this.$.hello.style.color = "red";
        } else {
          this.$.hello.style.color = "green";
        }
      },
      clickMe : function() {
        this.$.hello.innerHTML="CLICKED";
      }
    });
  </script>
</polymer-element>

Ouvrez Ă  nouveau la page avec votre navigateur :

Alt "006.png"

DeuxiĂšme composant Polymer : une liste

Nous allons crĂ©er une 2Ăšme composant destinĂ© Ă  afficher une liste d’élĂ©ments, nous appellerons ce nouveau composant : <buddies-list></buddies-list>. Donc crĂ©ez un nouveau fichier buddie-list.html dans le rĂ©pertoire components avec le code suivant :

<polymer-element name="buddies-list">
  <template>
    <ul>
      <template repeat="{{buddies}}">
        <li>{{name}}</li>
      </template>
    </ul>
  </template>
  <script>
    Polymer("buddies-list",{
      ready: function(){
        this.buddies = [
          {name:"Bob Morane"},
          {name:"Doctor No"},
          {name:"Fox Mulder"},
          {name:"Lady Penelope"}
        ];
      }
    });
  </script>
</polymer-element>

Ensuite, déclarez votre composant dans index.html : <link rel="import" href="components/buddies-list.html"> et vous pouvez maintenant utiliser directement le nouveau tag : <buddies-list></buddies-list> :

<!DOCTYPE html>
<html>
<head>
  <title>01-introduction</title>
  <!-- Load Polymer -->
  <script src="bower_components/platform/platform.js"></script>
  <script src="bower_components/polymer/polymer.js"></script>

  <!-- my components -->
  <link rel="import" href="components/hello-john-doe.html">
  <link rel="import" href="components/buddies-list.html">
</head>
<body>
  <hello-john-doe></hello-john-doe>
  <hr>
  <buddies-list></buddies-list>
</body>
</html>

Ouvrez Ă  nouveau la page avec votre navigateur :

Alt "007.png"

Comme avec le composant prĂ©cĂ©dent, nous pouvons accĂ©der “de l’extĂ©rieur” Ă  notre composant pour par exemple lui ajouter des Ă©lĂ©ments :

document.querySelector("buddies-list").buddies.push({name : "Emma Peel"})

Alt "008.png"

Tips : jouons avec les attributs

Imaginez que vous déclarez votre nouveau composant de la maniÚre suivante :

<buddies-list title="Buddies List"></buddies-list>

Le simple fait d’avoir ajouter un attribut title dans la dĂ©finition du tag a crĂ©Ă© un propriĂ©tĂ© title pour notre composant buddies-list, accessible aussi bien au niveau du code html (au sein de la balise <template></template>) qu’au niveau du code javascript. Modifiez le composant buddies-list de la façon suivante :

  • ajout de <h2> {{title}} </h2>dans la section template
  • lecture de la valeur de title dans la mĂ©thode ready() : console.log("Title is ", this.title);
<polymer-element name="buddies-list">
  <template>
    <h2>{{title}}</h2>
    <ul>
      <template repeat="{{buddies}}">
        <li>{{name}}</li>
      </template>
    </ul>
  </template>
  <script>
    Polymer("buddies-list",{
      ready: function(){
        console.log("Title is ", this.title);
        this.buddies = [
          {name:"Bob Morane"},
          {name:"Doctor No"},
          {name:"Fox Mulder"},
          {name:"Lady Penelope"}
        ];
      }
    });
  </script>
</polymer-element>

Ouvrez Ă  nouveau la page avec votre navigateur :

Alt "009.png"

Nous avons donc maintenant un titre pour notre liste, que l’on peut paramĂ©trer Ă  partir d’un attribut dans le tag html correspondant au composant (<buddies-list title="Buddies List"></buddies-list>).

Les composants parlent au composants

Il serait intĂ©ressant maintenant que les Ă©lĂ©ments saisis dans le 1er composant puissent ĂȘtre ajoutĂ©s dans la liste du 2Ăšme composant lorsque l’on clique sur le bouton (j’imagine que vous m’aviez vu venir de loin 
). Il existe diffĂ©rentes mĂ©thodes pour communiquer entre composants de Polymer (Un peu de lecture par ici si vous le souhaitez : http://www.polymer-project.org/articles/communication.html), et ma prĂ©fĂ©rĂ©e est celle qui fonctionne Ă  base de signaux grĂące au composant <polymer-signals>. Pour l’utiliser nous allons devoir installer les “polymer elements” qui sont des composant Polymer supplĂ©mentaires, dont notamment <polymer-signals>.

Pour se faire, nous utiliserons Bower une fois de plus :

bower install polymer-elements

Une fois les nouveaux Ă©lĂ©ments installĂ©s, nous pouvons donc utiliser <polymer-signals>. Nous aurons donc un composant qui sera “l’emetteur de signal”, dans notre cas le composant <hello-john-doe></hello-john-doe> qui enverra le signal newbuddy et le rĂ©cepteur sera notre composant <buddies-list></buddies-list>.

Avant toute chose n’oublions pas de rĂ©fĂ©rencer <polymer-signals>:

<link rel="import"
        href="bower_components/polymer-elements/polymer-signals/polymer-signals.html">

Puis transformons <hello-john-doe></hello-john-doe> en emetteur.

L’emetteur

Modifiez le code de hello-john-doe.html de la façon suivante :

Nous ajoutons l’envoi d’un signal newbuddy Ă  l’aide de asyncFire() dans la mĂ©thode clickMe() :

<polymer-element name="hello-john-doe">
  <template>
    <h1 id="hello">Hello {{name}}</h1>
    <input value="{{name}}">
    <button on-click="{{clickMe}}">Click Me!</button>
  </template>
  <script>
    Polymer("hello-john-doe",{
      ready: function(){
        this.name = "John Doe";
      },
      nameChanged : function() {
        if(this.name != "John Doe") {
          this.$.hello.style.color = "red";
        } else {
          this.$.hello.style.color = "green";
        }
      },
      clickMe : function() {
        this.$.hello.innerHTML="CLICKED";

        this.asyncFire(
          'polymer-signal',
          {
            name : "newbuddy",
            data : { name : this.name }
          }
        );
      }
    });
  </script>
</polymer-element>

Nous passons donc à asyncFire() le nom du signal (name : "newbuddy") et les données à envoyer (data : { name : this.name }).

Il nous faut maintenant un récepteur, donc transformons <buddies-list></buddies-list>.

Le récepteur

  • Ajoutons dans la partie html du composant la dĂ©claration suivante <polymer-signals on-polymer-signal-newbuddy=" {{onNewBuddySignal}} "></polymer-signals> qui signifie que notre rĂ©cepteur s’abonne au signal newbuddyet qu’il dĂ©clenchera la mĂ©thode onNewBuddySignal() s’il “entend” le signal. Important : il faut bien respecter la notation on-polymer-signal-newbuddy avec le nom du signal bien orthographiĂ©, en 1 seul mot et en minuscules. Pour le nom de la mĂ©thode onNewBuddySignal() par contre vous faites comme vous le sentez.
  • Ajoutons la mĂ©thode onNewBuddySignal() dĂ©clenchĂ©e par le signal

Nous aurons donc le code suivant pour buddies-list :

<polymer-element name="buddies-list">
  <template>
    <polymer-signals on-polymer-signal-newbuddy="{{onNewBuddySignal}}"></polymer-signals>
    <h2>{{title}}</h2>
    <ul>
      <template repeat="{{buddies}}">
        <li>{{name}}</li>
      </template>
    </ul>
  </template>
  <script>
    Polymer("buddies-list",{
      ready: function(){
        console.log("Title is ", this.title);
        this.buddies = [
          {name:"Bob Morane"},
          {name:"Doctor No"},
          {name:"Fox Mulder"},
          {name:"Lady Penelope"}
        ];
      },
      onNewBuddySignal : function(e, data, sender) {
        this.buddies.push(data)
        console.log("Sender : ", sender)
      }
    });
  </script>
</polymer-element>

Donc, Ă  la rĂ©ception du signal newbuddy nous ajouterons les donnĂ©es envoyĂ©es par l’émetteur : this.buddies.push(data) (au passage remarquez que vous pouvez rĂ©cupĂ©rer une rĂ©fĂ©rence de l’émetteur via l’argument sender).

Il ne vous reste plus qu’à tester. Ouvrez à nouveau la page avec votre navigateur :

Alt "010.png"

VoilĂ !. Et de cette maniĂšre vous n’ĂȘtes pas obligĂ©s d’accĂ©der aux composants “par l’extĂ©rieur” puisqu’ils peuvent communiquer par “signaux”.

Bien sĂ»r, un composant peut ĂȘtre Ă  la fois Ă©metteur et rĂ©cepteur, s’abonner Ă  diffĂ©rents signaux, etc. 


C’est tout pour aujourd’hui. Cela vous laisse le temps de vous amuser un peu avec. Au prochain Ă©pisode, nous verrons comment “discuter” avec le serveur (nous parlerons d’ajax, json, REST, 
) mais aussi nous vĂ©rifierons si Polymer reste compatible avec les autres frameworks javascript (la question Ă©tant, puis-je continuer Ă  utiliser jQuery, Backbone, Underscore, 
).

Bonne Lecture (et bon WE Ă  tous) ;).

blog comments powered by Disqus

Related posts