Les directives indispensables pour Angular.js /
donnons de super pouvoirs à notre HTML

04/03/2016

Angular nous permet de lier un comportement JS à un element HTML grace a des directives. Angular vient avec des directives natives qui sont indispensable pour construire notre applications, découvrons celles-ci.

Un point important à sous-lignée sur Angular c’est sur l’affichage des images. En effet si nous avions le chemin vers une image dans notre array de donnée nous serions tentés d’essayer de l’afficher comme ceci :

<img src="{{product.images[0].full}}"/>

Mais cela ne fonctionnera pas :/ ! Pourquoi me direz-vous ? En fait le navigateur va tout de suite essayer d’afficher l’image sans attendre qu’angular interprète l’expression et la remplace par le bon chemin.

Les petits gars de chez Google ont pensé à tout avec une directive prévue pour l’occasion, la directive ng-src pour afficher notre image nous devons donc faire.

<img ng-src="{{product.images[0].full}}"/>

Faites bien attention à utiliser des accolades pour qu’angular interprète bien la propriété

ng-src avec une boucle

Reprendre un petit exemple concret ne fait pas de mal alors nous allons voir comment faire une boucle pour afficher des images issues d’un sous array de notre controller.

(function() {
  var app = angular.module('gemStore', []);

  app.controller('StoreController', function() {
    this.products = gems;
  });

  var gems = [{
    name: 'Azurite',
    description: "Some gems have hidden qualities beyond their luster, beyond their shine... Azurite is one of those gems.",
    shine: 8,
    price: 110.50,
    rarity: 7,
    color: '#CCC',
    faces: 14,
    images: [
      "images/gem-02.gif",
      "images/gem-05.gif",
      "images/gem-09.gif"
    ]
  },{
    name: 'Zircon',
    description: "Zircon is our most coveted and sought after gem. You will pay much to be the proud owner of this gorgeous and high shine gem.",
    shine: 70,
    price: 1100,
    rarity: 2,
    color: '#000',
    faces: 6,
    images: [
      "images/gem-06.gif",
      "images/gem-07.gif",
      "images/gem-10.gif"
    ]
  }];
})();

<!DOCTYPE html>
<html ng-app="gemStore">
<head>
<link rel="stylesheet" type="text/css" href="bootstrap.min.css" />
<script type="text/JavaScript" src="angular.min.js"></script>
<script type="text/JavaScript" src="app.js"></script>
</head>
<body class="list-group" ng-controller="StoreController as store">
<!--  Product Container  -->
<div class="list-group-item" ng-repeat="product in store.products">
<h3>{{product.name}} <em class="pull-right">{{product.price | currency}}</em></h3>

<!-- Image Gallery  -->
<div class="gallery">
<div class="img-wrap">
<img ng-src="{{product.images[0]}}" />
</div>
<ul class="img-thumbnails clearfix">

<!-- ICI NOTRE BOUCLE -->

<li class="small-image pull-left thumbnail" ng-repeat="image in product.images">
<img ng-src="{{image}}" />
</li>

<!-- ICI NOTRE BOUCLE -->

</ul>
</div>
</div>
</body>
</html>


ng-click

Une autre directive tout aussi importante qu’essentielle, c’est ng-click qui permet assigner une valeur à une expression qu’Angular pourra interpréter. Vous comprendrez mieux ce concept avec l’exemple ci-dessous.

Imaginons que dans notre application de magasin en ligne nous voulions afficher des informations dans des tabs. Le principe d’une tab est que lorsque l’on clique sur le titre JavaScript cherche le contenu correspondant et l’affiche et cache les autres.

<section>
<ul class="nav nav-pills">
<li><a href ng-click="tab = 1"> Description</a></li>
<li><a href ng-click="tab = 2"> Specs</a></li>
<li><a href ng-click="tab = 3"> Reviews</a></li>
</ul>
{{tab}}
</section>

Que ce passe-t-il dans ce code ? En fait c’est très simple lorsque l’on clique sur Description / Specs / Reviews on assigne à l’expression tab une valeur, respectivement 1,2,3.
Vous remarquerez que dans notre exemple on affiche le contenu de l’expression {{tab}}, et quand un clique sur un élément avec la directive ng-click la valeur de tab change !

2-way- Data Binding

Mais c’est vraiment étrange que cette expression ce mette à jour, non ? C’est en fait un principe important sur Angular.js le 2-way- Data Binding. En fait à chaque fois que la propriété change Angular re-interprète l’expression.

conditionner dans une directive

Dans notre exemple précédent, vous avez dû remarquer que pour le moment nous n’affichions que l’expression après le click sur une tab. Mais maintenant nous voulons rendre la chose un peu plus concrète en affichant réellement les tables. Il faut donc que nous puissant dire à Angular :

« Quand je click sur une tab et que tab change de valeur, affiche la tab correspondante ».

Afficher / Cacher… Cela vous dit quelque chose ? Oui ! Il faut utiliser les directives ng-show !

ng-show permet de vérifier une condition il suffit de lui mettre cette condition en paramètre

<section>
<ul class="nav nav-pills">
<li><a href ng-click="tab = 1"> Description</a></li>
<li><a href ng-click="tab = 2"> Specs</a></li>
<li><a href ng-click="tab = 3"> Reviews</a></li>
</ul>

<div class="panel" ng-show="tab === 1">
<h1>1 </h1>
<p> {{product.description}} </p>
</div>

<div class="panel" ng-show="tab === 2">
<h1>2 </h1>
<p> {{product.description}} </p>
</div>

<div class="panel" ng-show="tab === 3">
<h1>3 </h1>
<p> {{product.description}} </p>
</div>

</section>

Ce qui nous donne, si tab à la valeur 2 alors affiche le contenu de cet élément html. Voilà ce que cela donne dans notre cas concret de pannel.

ng-init mettre en place une valeur par défaut à une expression

Dans notre exemple précédant, nous aimerions peut-être pouvoir afficher une tab au chargement de la page. Sans avoir à cliquer dessus. En suivant notre logique, il faudrait donc pouvoir assigner une valeur par défaut à tab… Angular propose une directive permettant de réaliser cela, c’est la directive ng-init

<section ng-init="tab = 1">
<ul class="nav nav-pills">
<li><a href ng-click="tab = 1"> Description</a></li>
<li><a href ng-click="tab = 2"> Specs</a></li>
<li><a href ng-click="tab = 3"> Reviews</a></li>
</ul>

...

</section>

Dans notre exemple ng-init nous permet d’assigner tab à une valeur de 1 dès le chargement de notre page.

ng-class ajouter / retirer une class en fonction d’une expression

Si vous avez l’habitude de faire de l’intégration , vous savez que nous avons souvent besoin d’ajouter des class en fonction de certaines conditions. C’est notamment le cas dans les pannels ou nous devons ajouter une class .active pour signifier le pannel courant. Angular nous permet de faire ce genre d’opération simplement avec ng-class.

Voilà comment elle fonctionne :

<li ng-class="{active:tab === 1}"></div>

En premier nous spécifions la class ici (active) en second l’expression à confronter avec notre condition.

<ul class="nav nav-pills">
<li ng-class="{active:tab === 1}">
<a href ng-click="tab = 1"> Description</a>
</li>
<li ng-class="{active:tab === 2}">
<a href ng-click="tab = 2"> Specs</a>
</li>
<li ng-class="{active:tab === 3}">
<a href ng-click="tab = 3"> Reviews</a>
</li>
</ul>

Pas de logique dans les vues…

Si vous regardez les exemple précédents, on commence à voir apparaitre de la logique dans nos vues (là où sont affichées les infos pour l’utilisateur). Et comme vous le savez, Angular.js est basé sur le modèle MVC (modèle / vue / controller).
Notre logique doit donc aller dans un controller pour éviter une bouillie de code incompréhensible.

Création d’un nouveau controller

La première étape est donc de créer une directive ng-controller sur notre élément :

<section ng-controller="PannelController as pannel">

  <ul class="nav nav-pills">
    <li ng-class="{active:pannel.isSelected(1)}">
      <a href ng-click="pannel.selectTab(1)"> Description</a>
    </li>
    <li ng-class="{active:pannel.isSelected(2)}">
      <a href ng-click="pannel.selectTab(2)"> Specs</a>
    </li>
    <li ng-class="{active:pannel.isSelected(3)}">
      <a href ng-click="pannel.selectTab(3)"> Reviews</a>
    </li>
  </ul>

  <div class="panel" ng-show="pannel.isSelected(1)">
    <h1>1 </h1>
    <p> {{product.description}} </p>
  </div>

  <div class="panel" ng-show="pannel.isSelected(2)">
    <h1>2 </h1>
    <p> {{product.description}} </p>
  </div>

  <div class="panel" ng-show="pannel.isSelected(3)">
    <h1>3 </h1>
    <p> {{product.description}} </p>
  </div>

</section>

la deuxième étape est de créer notre controller pour sa partie JavaScript.


app.controller("PannelController",function(){ this.tab = 1; this.selectTab = function(setTab){ this.tab = setTab; }; this.isSelected = function(checkTab){ if(this.tab === checkTab){ return true; } }) });

Explication, pour mettre notre class « .active » sur le bon élément on utilise la directive ng-class qui affichera la classe donnée en function d’une condition. Pour vérifier cette condition, on appelle dans notre controller la function (une function expression) de notre controller. Cette function vérifie si notre tab est actuellement sélectionné.

Par défaut c’est bien notre tab 1 qui est sélectionné, en étudiant notre controller on observe bien « this.tab = 1 » donc isSelected vérifie qu’elle est la valeur de tab.

selectTab est une function qui modifie la valeur de tab.