Rechercher dans ce blog

samedi 2 novembre 2013

Les liaisons (ngModel)


Nous allons maintenant introduire un peu d'interaction à nos pages. Imaginez que vous entrez une valeur dans une zone de texte et que cette valeur est utilisée en temps réel pour modifier le DOM. C'est ce que nous allons réaliser à présent.

Directive ngModel


La directive ngModel permet de créer une liaison avec une zone de saisie. Voici un exemple (JSFiddle) :
<div ng-app>
  <input id="nom" type="text" ng-model="nom">
  <h1>Bonjour {{nom}} !</h1>
</div>
Avec la directive ngModel on a fait une liaison entre la zone de texte et une variable située dans le modèle (en fait le scope comme nous le verrons bientôt) qui a le même nom que celui prévu pour la directive. Autrement dit il est créé une variable nom dans le modèle. L'expression située dans la balise h1 est liée à cette variable et affiche sa valeur et se raffraichit dès que celle-ci change. Au final l'expression est mise à jour instantanément lorsque la valeur de la zone de texte est modifiée.

Case à cocher


La directive ngModel peut s'appliquer à tout contrôle. Voici un exemple avec des cases à cocher (JSFiddle) :
<div ng-app>
  <form ng-init="valeur1=true; valeur2=false">
    Valeur1 : <input type="checkbox" ng-model="valeur1"> 
{{valeur1}}<br>
    Valeur2 : <input type="checkbox" ng-model="valeur2">
{{valeur2}}
  </form>
</div>
On initialise les variables valeur1 et valeur2 avec la directive ngInit. Remarquez que la liaison est bidirectionnelle parce que la case qui concerne la valeur1 se retrouve cochée au départ. Ensuite la modification de la valeur de chaque case est immédiatement reportée dans la valeur de la variable correspondante.

Select


La directive ngModel peut s'appliquer aussi à un contrôle select, c'est juste un peu plus délicat à mettre en oeuvre. Prenons le cas d'une liste de ville (JSFiddle) :
<div ng-app>
  <div ng-init="villes=['Paris','Lyon','Marseille','Toulouse']">
    <select ng-model="valeur" 
ng-options="villes.indexOf(v) as v for v in villes">
      <option value="">-- Choisissez une ville --</option>
    </select>
    Valeur de l'option : {{valeur}}
  </div>
</div>
On initialise le tableau des noms de villes avec la directive ngInit. Ensuite la directive ngOptions permet de remplir la liste avec les valeurs du tableau des villes. La directive ngModel sert de liaison pour la valeur du choix, ici des nombres.

On vient de voir que la directive ngModel peut s'appliquer aussi à un contrôle select. Voyons un autre exemple, cette fois nous allons utiliser une expression pour changer une classe (JSFiddle) :
<div ng-app>
  <label for="texte">Choisissez la classe :</label>
    <select ng-model="classe" ng-init="classe='noir'">
      <option>noir</option>   
      <option>rouge</option>
      <option>vert</option>
      <option>bleu</option>
      <option>jaune</option>
    </select>
  <button type="button" class="{{classe}}">Classe "{{classe}}"
</button>
</div>
On a une liste avec des noms de classes. La directive ngModel établit une liaison entre la valeur sélectionnée et la classe appliquée au bouton. La valeur initiale de la liste est fixée grâce à la directive ngInit.

Le scope


Je vous ai dit qu'AngularJS respecte le modèle MVC, pour le moment on a rien vu de tel ! On a juste utilisé des procédures "magiques" pour obtenir des résultats. Pour rappel le modèle MVC est composé de ces 3 entités :
  • Le modèle qui est chargée de contenir les données, donc l'état de l'application
  • La vue qui est chargée d'afficher les informations pour l'utilisateur
  • Le contrôleur qui est chargé d'établir la relation entre le modèle et la vue, c'est un peu le chef d'orchestre.
Dans nos exemples jusqu'à présent on n'a pas créé de contrôleur et pourtant ça fonctionne. Pour le modèle on a vu que la directive ngInit permet d'initialiser des valeurs. La vue est générée à partir de la page HTML avec les doubles accolade mais sans qu'on sache vraiment comment ça se passe. On va donc regarder un peu dans la machine pour comprendre comment ça fonctionne...

Reprenons ce code qui fait une liaison entre un contrôle et un affichage :
<div ng-app>
  <input id="nom" type="text" ng-model="nom">
  <h1>Bonjour {{nom}} !</h1>
</div>
Si vous avez la curiosité de regarder le code généré vous allez trouver cela :
<div class="ng-scope" ng-app="">
  <input class="ng-pristine ng-valid" id="nom" ng-model="nom"
ng-init="nom='Toto'" type="text">
  <h1 class="ng-binding">Bonjour Toto !</h1>
</div>
On voit que quelques classes sont apparues : ng-scope, ng-pristine, ng-valid et ng-binding. Ces classes ont été créées lors de la compilation du code par AngularJS. Mais ce qu'on ne voit pas c'est qu'il a aussi été créé un scope. C'est un objet qui a pour fonction de :
  • observer toute modification du modèle
  • offrir un contexte d'exécution pour les expressions
Il est organisé de façon hiérarchique un peu à l'image du DOM. Si nous observons notre exemple au démarrage nous avons la création d'un scope racine. On peut le trouver en utilisant l'extension Batarang des outils de développement de Chrome :
$id: "003"
$parent: null
$root: h
__private__: Object
nom: "Toto"
this: h
__proto__: Object
On voit une propriété nom qui a pour valeur "Toto". Si vous explorez cet objet vous pourrez trouver d'autres informations comme par exemple les watchers. Mais il n'est pas très utile de fouiller tout ça étant donné que les scopes sont automatiquement créés ! On aura l'occasion d'explorer les scopes dans une phase ultérieure avec une application plus fournie. Si vous voulez déjà explorer un peu plus ce domaine vous pouvez consulter la documentation.

Aucun commentaire:

Enregistrer un commentaire