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

Nous parlerons de:

  • Comment faire rapidement une petite API REST avec NodeJS et Express
  • Comment faire des requĂȘtes GET avec le composant <polymer-ajax>
  • Comment faire des requĂȘtes POST avec le composant <polymer-ajax>

Cet article est beaucoup plus court que le précédent, mais reste incontournable si vous voulez réaliser des SPA ayant des interactions avec un serveur.

Pré-requis

Tout d’abord, il faut avoir lu le tuto prĂ©cĂ©dent : http://k33g.github.io/2013/12/07/POLYMER-1.html.

Ensuite, pour ce 2Ăšme Ă©pisode nous aurons besoin d’un serveur qui puisse nous renvoyer du flux json et auquel nous pourrons envoyer des donnĂ©es (nous allons stocker notre liste cĂŽtĂ© serveur). AprĂšs rĂ©flexion (utiliser Play, utiliser SparkJava, 
), j’ai donc dĂ©cidĂ© d’aller au plus simple : utiliser NodeJS et Express. Je pars du principe que vous avez installĂ© dĂ©jĂ  installĂ© NodeJS (et donc le gestionnaire de package npm).

Création du serveur

  • en mode console, installez Express : tapez sudo npm -g install express (sous Windows pas besoin de sudo)
  • puis crĂ©ez un rĂ©pertoire pour votre application (dans mon cas : 02-ajax)
  • dans ce rĂ©pertoire (cd 02-ajax), crĂ©ez un fichier package.json avec le contenu suivant

      {
        "name": "hello-polymer",
        "description": "hello-polymer app",
        "version": "0.0.1",
        "dependencies": {
          "express": "3.x"
        }
      }
    
  • ensuite, tapez npm install, les dĂ©pendances nĂ©cessaires pour faire tourner Express vont ĂȘtre installĂ©es
  • crĂ©er ensuite (toujours dans le rĂ©pertoire de votre application) un rĂ©pertoire public dans lequel vous pouvez copier l’ensemble des fichiers de l’article prĂ©cĂ©dent (index.html, le rĂ©pertoire components et son contenu, et faites de mĂȘme pour le rĂ©pertoire bower_components)

Vous devriez avoir l’arborescence suivante :

Alt "011.png"

CrĂ©ation de l’application Express

Rien de plus simple. Créez dans votre répertoire applicatif un fichier app.js avec le code suivant:

var express = require('express');
var app = express()

var buddies = [
  {name:"Bob Morane"},
  {name:"Doctor No"},
  {name:"Fox Mulder"},
  {name:"Lady Penelope"}
];

app.use(express.static(__dirname + '/public'));
app.use(express.json());
app.use(express.urlencoded());

app.get("/buddies", function(req, res){
  res.send(JSON.stringify(buddies))
});

app.post("/buddies", function(req, res){
  var buddy = req.body
  buddies.push(buddy)
  res.send(JSON.stringify(buddy))
});

app.listen(3000)

Pour lancer notre application, il suffira de lancer node app.js, vous pouvez tester dùs maintenant avec l’url http://localhost:3000 dans votre navigateur, vous arriverez sur le contenu de notre page index.html. Si vous avez le plugin Postman pour Chrome, vous pouvez tester votre “api” dùs maintenant (vous pouvez aussi utilisez curl).

# RequĂȘte GET

Alt "012.png"

# RequĂȘte POST

Alt "013.png"

Relancez la requĂȘte GET :

Alt "014.png"

Nous avons bien un nouvel enregistrement. Notre serveur est opérationnel. Nous pouvons retourner faire du Polymer.

<buddies-list> appelle le serveur

Alors souvenez-vous, notre “liste de copains” <buddies-list>avait le code suivant :

<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>

Nous souhaitons que notre liste soit “remplie” par les infos du serveur. Pour cela nous allons utiliser le composant <polymer-ajax> (qui a Ă©tĂ© installĂ© avec la commande bower install polymer-elements lors du 1er Ă©pisode)

  • Supprimez le code de la mĂ©thode ready
  • Dans <template> on ajoute le composant <polymer-ajax> en prĂ©cisant ses attributs et callbacks
  • Dans la mĂ©thode onReceive(response) dĂ©clenchĂ©e une fois que nous recevons les donnĂ©es du serveur, on affecte les donnĂ©es reçues Ă  la propriĂ©tĂ©s buddies du composant (propriĂ©tĂ© utilisĂ©e dans le template)
  • Remarque : dans le tag <polymer-ajax> vous remarquerez l’attribut auto, qui lance automatiquement la requĂȘte.

Votre code devrez ressembler Ă  ceci :

<polymer-element name="buddies-list">
  <template>
    <polymer-ajax id="xhr" auto handleAs="json" method="GET" url="buddies"
                  on-polymer-response="{{onReceive}}"
                  on-polymer-error="{{onError}}"
                  on-polymer-complete="{{onComplete}}">
    </polymer-ajax>
    <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(){

      },
      onReceive: function(response) {
        this.buddies = response.detail.response;
      },
      onError: function(error) { /*foo*/ },
      onComplete: function(data) { /*foo*/ },

      onNewBuddySignal : function(e, data, sender) {
        this.buddies.push(data)
        console.log("Sender : ", sender)
      }
    });
  </script>
</polymer-element>

Si vous ouvrez votre navigateur avec l’url http://localhost:3000/, vous devriez voir s’afficher la nouvelle liste.

Il ne nous reste plus qu’à gĂ©rer l’ajout de nouveaux “buddies”.

<hello-john-doe> parle aussi au serveur

Nous allons modifier notre composant <hello-john-doe> pour qu’il fasse des requĂȘtes de type POST vers notre serveur (pour ajouter des “buddies” Ă  la liste).

Notre code Ă©tait le 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";

        this.asyncFire(
          'polymer-signal',
          {
            name : "newbuddy",
            data : { name : this.name }
          }
        );
      }
    });
  </script>
</polymer-element>
  • LĂ  aussi nous allons utiliser le composant <polymer-ajax> mais avec method="POST" et sans attribut auto
  • Nous changeons la mĂ©thode clickMe : lorsque l’on appuie sur le bouton, on passe les informations { name : this.name } au seveur par le biais d’une requĂȘte POST.
  • La commande this.$.xhr.go(); sert Ă  dĂ©clencher l’appel ajax de type POST au serveur (oĂč xhr est l’id du composant <polymer-ajax>)
  • Une fois la rĂ©ponse du serveur obtenue, la mĂ©thode onReceive est dĂ©clenchĂ©e (callback), donc nous dĂ©clenchons le signal "newbuddy" avec asyncFire() (cette fois ci pas besoin de passer les donnĂ©es, il faut juste dĂ©clencher le signal).

Voici le code modifié :

<polymer-element name="hello-john-doe">
  <template>
    <polymer-ajax id="xhr" handleAs="json" method="POST" url="buddies"
                  on-polymer-response="{{onReceive}}"
    </polymer-ajax>
    <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.$.xhr.xhrArgs = {
          headers: { "Content-Type": "application/json"},
          body: JSON.stringify({ name : this.name })
        };

        this.$.xhr.go();
      },
      onReceive: function(response) {
        this.asyncFire(
          'polymer-signal', { name : "newbuddy" }
        );
      }
    });
  </script>
</polymer-element>

Allons juste modifier le code du composant <buddies-list> pour qu’il rafraĂźchisse la liste lors de l’ajout d’un Ă©lĂ©ment. Pour cela il suffit de modifier dans buddies-list.html la mĂ©thode onNewBuddySignal() (dĂ©clenchĂ©e par le signal “newbuddy”) de cette façon :

onNewBuddySignal : function(e, data, sender) {
  this.$.xhr.go();
}

Avec this.$.xhr.go();, on appelle la requĂȘte de type GET du composant.

Il ne vous reste maintenant plus qu’à tester.

Dernier petit rĂ©glage : rendons nos composants “paramĂ©trable”

Il suffit d’ajouter l’attribut url avec la valeur buddies dans le tag de dĂ©claration de chacun de nos composants dans notre page index.html :

<hello-john-doe url="buddies"></hello-john-doe>
<hr>
<buddies-list title="Buddies List" url="buddies"></buddies-list>

Ensuite pour chacun des composants, vous pouvez supprimer l’initialisation url="buddies" dans <polymer-ajax> et ajouter la ligne this.$.xhr.url = this.getAttribute("url"); dans la mĂ©thode ready().

Vous pouvez tester à nouveau. That’s all :)

Vous trouverez le code de l’exemple ici : https://github.com/k33g/polymer-les-mains-dans-le-cambouis/tree/master/02-ajax.

Piste de rĂ©flexion : j’ai embarquĂ© le composant <polymer-ajax> au sein de mes composants. Il pourrait ĂȘtre intĂ©ressant de les “extraire” et les rendre indĂ©pendants, et les faire communiquer avec les autres composants par l’émission et la rĂ©ception de signaux.

Bonne lecture.

blog comments powered by Disqus

Related posts