Go to Hackademy website

Introduction à AngularJS

Numa Claudel

Posté par dans la catégorie front

Vous avez très certainement entendu parler d’AngularJS, le framework de Google pour faire des SPA à l’instar de Ember et backbone.

AngularJS est un framework JavaScript qui étend le HTML pour le rendre dynamique, et permet de développer ses propres balises et attributs HTML. C’est un framework qui se veut extensible et qui pousse vers un développement structuré, en couches, le but n’étant pas d’ajouter de simples animations au DOM, mais bien d’apporter un aspect applicatif au front-office.

Penser son JavaScript avec AngularJS se fait donc différemment :

  • il ne faut pas concevoir sa vue pour la rendre dynamique, mais partir de son application JS pour la créer
  • penser son application JS en back-office/front-office, même si c’est une SPA
  • architecturer son application JS en différentes couches

Ce que je vous propose pour ce billet, c’est de faire un tour des premières notions intéressantes et nécessaires, pour commencer à utiliser AngularJS.

 Qu’est ce que AngularJS a de spécial ?

Les concepts qui pour moi caractérisent le plus AngularJS sont :

  • architecture MVC
  • data-binding bidirectionnel
  • injection de dépendance
  • routing
  • les tests

Le data-binding bidirectionnel est rendu possible grâce au scope. Le scope est le “liant” d’une application AngularJS, c’est lui qui contient les variables et fonctions qui font la liaison entre vues et contrôleurs (ou autres). Il permet donc aux données de pouvoir être mises à jour par les vues et par le modèle. L’injection de dépendances permet de charger certaines parties de l’application seulement quand c’est nécessaire. Et l’un des gros point fort d’AngularJS vient du fait que les applications écrites sont entièrement testables.

Comme un bon exemple vaut mieux qu’un long discours, je vous propose après ces quelques mots de passer aux illustrations.

 Hello World à la sauce AngularJS

Rien de tel qu’un petit Hello World pour commencer :

<!doctype html>
<html ng-app="helloApp">
  <head>
  </head>
  <body>
    <h1>Introduction à AngularJS</h1>

    <div ng-controller="helloCtrl">
      <h2>Hello world!</h2>
    </div>

    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.min.js"></script>
    <script src="app.js"></script>
  </body>
</html>

Une page HTML avec la délimitation de la zone d’action de notre application : ng-app=”helloApp” que j’ai positionné sur la balise html, la délimitation de la zone de notre contrôleur : ng-controller=”helloCtrl”, le chargement d’AngularJS, et de notre fichier d’application.

Le fichier d’application :

var helloApp = angular.module('helloApp', []);

helloApp.controller('helloCtrl', ['$scope', function ($scope) {

}]);

Rendre la page maintenant nous affiche bien sur “Hello World!”, mais ce n’est pas grâce à notre application. Par contre on peut déjà observer que la déclaration de notre contrôleur prend un paramètre : le scope. Voici donc notre première injection de dépendance (au passage les contrôleurs ont toujours au minimum le scope en dépendance). Mais au fait ce scope qu’est ce que c’est exactement ? Et bien c’est un objet fournit par AngularJS qui défini le contexte d’exécution d’un contrôleur.

Insérons maintenant une variable dans notre contrôleur qui contiendra “world” et affichons la dans la vue :

helloApp.controller('helloCtrl', ['$scope', function ($scope) {
  $scope.name = 'world';
}]);
<div ng-controller="helloCtrl">
  <h2>Hello {{ name }}!</h2>
</div>

L’interprétation de variable par la vue se fait par défaut avec {{ }}. Nous avons initialisé une variable name contenue par le scope dans notre contrôleur avec la chaîne de caractères “world”, puis nous l’avons placée dans notre vue (tout ce que contient le scope est accessible directement par la vue sans préfixer les variables). Maintenant rafraîchir la page nous affiche toujours “Hello world!”, mais cette fois dynamiquement.

La valeur de notre variable name est donc initialisée par le “back-office” (en quelques sorte) de notre application. Pour un data-binding bidirectionnel, nous devons alors pouvoir mettre à jour la valeur de cette variable dans notre vue. Et bien ajoutons un champ texte à celle-ci :

<div ng-controller="helloCtrl">
  <label>Nom :</label>
  <input type="text" ng-model="name">
  <br />
  <h2>Hello {{ name }}!</h2>
</div>

En ajoutant notre champ texte, j’ai également mis en place un attribut ng-model que fourni AngularJS sur celui-ci. En passant notre variable name à cet attribut, nous la relions à la valeur du champ texte. Si maitenant vous rafraîchisser la page, vous pouvez déjà remarquer que le champ texte contient “world”. Essayer de modifier sa valeur, et vous pourrez observer que “Hello world!” se met à jour en même temps.

Ce hello world nous permet aussi de découvrir 3 attributs qu’ajoute AngularJS au HTML : ng-app, ng-controller et ng-model. Ces attributs sont en fait appelés des directives, et je vous invite à jeter un œil à la documentation d’AngularJS pour voir la liste de celles disponibles de base. Sachez qu’il est tout à fait possible de compléter cette liste avec ses propres directives, mais je vous propose de parler de ce sujet dans un futur billet.

ng-hide, ng-show, ng-repeat

J’ai choisi de vous faire un petit exemple avec ces 3 directives que fournit AngularJS, car elles sont très souvent utiles. ng-show et ng-hide servent a cacher ou non une portion du DOM en fonction de l’évaluation de l’expression qui leur est fournie, tandis que ng-repeat itère sur une expression et génère la portion de DOM englobée dans la balise sur laquelle elle se trouve.

Notre contrôleur people contiendra une liste de personnes et initialisera l’affichage de cette liste :

var helloApp = angular.module('helloApp', []);

helloApp.controller('peopleCtrl', ['$scope', function ($scope) {
  $scope.people = [
    { "firstname": "Martin", "lastname": "Catty" },
    { "firstname": "Nicolas", "lastname": "Cavigneaux" },
    { "firstname": "Nicolas", "lastname": "Zermati" },
    { "firstname": "Victor", "lastname": "Darras" },
    { "firstname": "Jonathan", "lastname": "François" },
    { "firstname": "Numa", "lastname": "Claudel" }
  ];

  $scope.showPeople = true;
}]);

Et la vue :

<!doctype html>
<html ng-app="helloApp">
  <head>
  </head>
  <body>
    <h1>Introduction à AngularJS</h1>

    <div ng-controller="peopleCtrl">
      <label>Afficher les personnes ?</label>
      <input type="checkbox" ng-model="showPeople">
      <ul ng-show="showPeople">
        <li ng-repeat="person in people">
          {{ person.firstname }} {{ person.lastname }}
        </li>
      </ul>
      <p ng-hide="showPeople">Il n'y a personne de visible.</p>
    </div>

    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.min.js"></script>
    <script src="app.js"></script>
  </body>
</html>

Cocher ou décocher la checkbox change la valeur de la variable showPeople, grâce à ng-model, et ng-show et ng-hide se comportant de manière inverse, on a soit la liste des personnes affichées, soit notre message qui nous indique que personne n’est visible. Et comme vous pouvez le voir en inspectant le DOM résultant, nous avons bien une liste de li générée par ng-repeat.

Le routage

AngularJS fournit un système de routage qui permet d’appeler certains composants pour une route donnée. Prenons comme exemple nos deux dernières pages :

<!doctype html>
<html ng-app="helloApp">
  <head>
  </head>
  <body>
    <h1>Introduction à AngularJS</h1>

    <div id="menu">
      <ul>
        <li><a href="#/">Hello</a></li>
        <li><a href="#/people">Liste des personnes</a></li>
      </ul>
    </div>
    <hr />

    <div ng-view></div>

    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.min.js"></script>
    <script src="https://code.angularjs.org/1.2.16/angular-route.min.js"></script>
    <script src="app.js"></script>
    <script src="controllers.js"></script>
  </body>
</html>

Voila notre index.html avec en position centrale un div et la directive ng-view en attribut. Cette directive définie l’endroit où se “rendra” la vue, elle-même contenue dans un fichier récupéré en AJAX à l’url indiquée par le fichier de route. J’ai aussi chargé le module de routage d’AngularJS qui est nécessaire pour mettre en place des routes.

Le fichier de routes :

var helloApp = angular.module('helloApp', ['ngRoute', 'helloAppControllers']);

helloApp.config(['$routeProvider', function($routeProvider) {
  $routeProvider.
    when('/', {
      templateUrl : 'hello.html',
      controller: 'helloCtrl'
    }).
    when('/people', {
      templateUrl : 'people.html',
      controller: 'peopleCtrl'
    }).
    otherwise({
      redirectTo : '/'
    });
}]);

Voici le fichier principal de l’application, c’est donc lui qui défini les dépendances et les fichier nécessaires en fonction de l’URL. Comme vous pouvez le constater, notre application a deux dépendances : le module de routage d’AngularJS ngRoute et le nouveau module helloAppControllers qui n’est rien d’autre que le module qui va dorénavant contenir nos contrôleurs.

Les contrôleurs dans controllers.js :

var helloAppControllers = angular.module('helloAppControllers', []);

helloAppControllers.controller('helloCtrl', ['$scope', function ($scope) {
  $scope.name = 'world';
}]);

helloAppControllers.controller('peopleCtrl', ['$scope', function ($scope) {
  $scope.people = [
    { "firstname": "Martin", "lastname": "Catty" },
    { "firstname": "Nicolas", "lastname": "Cavigneaux" },
    { "firstname": "Nicolas", "lastname": "Zermati" },
    { "firstname": "Victor", "lastname": "Darras" },
    { "firstname": "Jonathan", "lastname": "François" },
    { "firstname": "Numa", "lastname": "Claudel" }
  ];

  $scope.showPeople = true;
}]);

Et enfin les 2 fichiers des vues partielles hello.html et people.html :

<div ng-controller="helloCtrl">
  <label>Nom :</label>
  <input type="text" ng-model="name">
  <br />
  <h2>Hello {{ name }}!</h2>
</div>
<div ng-controller="peopleCtrl">
  <label>Afficher les personnes ?</label>
  <input type="checkbox" ng-model="showPeople">
  <ul ng-show="showPeople">
    <li ng-repeat="person in people">
      {{ person.firstname }} {{ person.lastname }}
    </li>
  </ul>
  <p ng-hide="showPeople">Il n'y a personne de visible.</p>
</div>

Vous pouvez maintenant naviguer entre les 2 vues et observer que seule la partie centrale est remplacée.

Conclusion

On aura vu comment fonctionne AngularJS, sa syntaxe, et certains de ses concepts importants, mais ce n’est qu’un aperçu. Nous aurons le temps de discuter d’autres de ces aspects dans de futurs billets, mais en attendant j’espère vous avoir donné envie de découvrir ce framework.

L’équipe Synbioz.

Libres d’être ensemble.

Articles connexes

La création de services avec AngularJS

13/05/2014

Bonjour à tous, nous avons précédemment fait une petite introduction a AngularJS, avec certains concepts permettant de commencer à l’utiliser. Pour continuer sur ce schéma, je vous propose de découvrir ensemble comment créer et se servir des service…

AngularJS 2.0 changements notables

16/06/2015

La version 2.0 d’Angular a maintenant été annoncée depuis un moment comme une refonte complète, et en voyant les importants changements entre les 2 versions, on peut dire que nous avons un gros travail de mise à niveau à fournir. Alors autant prendr…

Introduction à Vue.js - construisons une Memebox

07/12/2017

Si vous êtes un tant soit peu comme moi, il y a fort à parier que votre communication en ligne est fortement axée sur le visuel. Mes collègues diraient plutôt que j’inonde les canaux Slacks et les merge requests avec des GIFs stupides, plutôt que de…

Afficher plus Afficher moins

Commentaires (14) Flux RSS des commentaires

  • 24/04/2014 à 14:14

    Stan

    C'est un bon aperçu d'Angular pour commencer. Je trouve un peu "dommage" que vous ne vous écartiez pas un peu du tuto que l'on retrouve sur leur site. Tout en restant basique, il serait bien d'aborder un peu plus les concepts d'Angular. Directives, Elements, l'aspect component etc ...

    En tout cas c'est une belle initiation !!

  • 24/04/2014 à 14:56

    Martin Catty

    Bonjour Stan, merci du feedback.

    On va attaquer ces concepts dans d'autres articles mais on voulait commencer par une introduction pour être cohérent et permettre à tous de mettre le pied à l'étrier avec Angular.

    La suite arrive donc, mais on est aussi preneur de contributions :)

  • 24/04/2014 à 16:34

    Patrick Ferreira

    Je suis d'accord avec l'approche de Synbioz , parler tout de suite des "directives", des "helpers" ou de la différence entre les différents types de "services" ça ne rendrait service à personne.

    Je vois de plus en plus de post sur StackOverflow avec des problèmes de scope non mis à jour, des "scope.apply" dans tous les sens sans trop comprendre ce qui se passe, des "services" qui pourrait être des "constants" et des "directives" qui pourrait être des "helpers" ou encore des "filter"
    Le problème c'est que la plupart des dev. on prit l'habitude de coder du jQuery-like et arrivent sur Angular avec les mêmes réflexes...

    Pour la prochaine tech-news et pour ne pas faire comme tout le monde, je prendrai comme axe :

    - Sensibilisation sur la syntaxe angularjs et les contraintes associées.
    * injection de dépendance vs minification de code : https://docs.angularjs.org/tutorial/step_05#a-note-on-minification
    * toutes les contraintes liées à IE : https://docs.angularjs.org/guide/ie
    * Un petit rappel sur le design pattern MVVM qui s'appuye sur le MVC mais qui a ses spécificités : http://addyosmani.com/blog/understanding-mvvm-a-guide-for-javascript-developers/
    * Fini les manipulation de DOM à la jQuery Style : https://docs.angularjs.org/tutorial/step_05#a-note-on-minification

    - Bref descriptif de tous les concepts : Template, Directives, Model, Scope, Expressions, Compiler, Filter, View, Data Binding, Controller, Dependency Injection, Injector, Module, Service

    - la V2 d'AngularJS est en route et ne sera pas compatible avec vos sources 1.x (ou du moins, pas sans un gros travail de refactoring)
    http://blog.zenika.com/index.php?post/2014/03/14/Premier-aper%C3%A7u-d-AngularJS-2.0

    Avec tout ça, on aura les bonnes bases pour bien écrire sa première application un peu plus évolué que le bon vieux "Hello {user.name}!" :-)

    (oops, c'est peut-être un poil long comme commentaire :-p)

  • 24/04/2014 à 16:37

    Patrick Ferreira

    Mince, un soucis de copier-coller... désolé

    * Fini les manipulation de DOM à la jQuery Style : http://stackoverflow.com/questions/14994391/how-do-i-think-in-angularjs-if-i-have-a-jquery-background

  • 24/04/2014 à 19:32

    Numa Claudel

    Merci pour ces quelques pistes intéressantes.

  • 01/10/2014 à 14:41

    Amaseb

    Bonjour,

    Merci pour cet article intéressant. Cependant je suis confronté un à un problème et ne sait absolument pas comment le résoudre. En effect les nombreux exemples sur les routes trouvés sur le net (dont celui sur cette page) ne fonctionnent pas sous IE9 (mais sous chrome et firefox). Sauriez-vous me dire pourquoi, et si une solution alternative existe?

  • 01/10/2014 à 15:47

    Numa Claudel

    Bonjour Amaseb,

    Sans être confronté au problème, il est difficile de savoir quel en est la cause exacte.
    Une hypothèse: IE9 ne semble pas supporter "history.pushState".
    Pistes à essayer:
    - changer le comportement par défaut d'un lien en retirant l'attribut href, et en appelant une fonction pour éventuellement nettoyer l'url, puis rediriger avec "$location.path()"
    - regarder du coté de cette librairie: https://github.com/browserstate/history.js

  • 01/10/2014 à 17:39

    optyler

    Je crois savoir qu'il y avait un soucis dans les version 1.2.x d'angular sur les routes. peut-être qu'une petite mise à jour de version suffirait ;-)

    Généralement, quand j'ai des soucis, j'essaie toujours de faire un plunkr minimaliste qui reprend la fonctionnalité qui ne marche pas (une sorte de test unitaire de la fonctionnalité) ça m'aide bien souvent à trouvez les causes du problème.

    Et si rien n'y fait, je copie colle mon plunkr sur stackoverflow et j'attend 5 minutes pour avoir la réponse :-p

  • 06/10/2014 à 12:39

    Amaseb

    Merci pour les conseils.
    Après avoir essayé plusieurs exemples, même simpliste, il semble effectivement que le système de route (dépendance avec "ng-route") ne soit pas compatible avec IE9 puique les vues ne s'affichent pas (avec les autres navigateurs tout fonctionne même IE11). J'ai essayé avec les nouvelles versions d'Angular mais ça ne résoud pas le problème. Un version plus ancienne sans les dépendances à ng-route fonctionne (exemple ici: https://www.youtube.com/watch?v=Uzs1avCbrrI), mais n'est pas appropriée à mon application. Du coup je suis un bloqué et ne sait pas comment faire pour résoudre ce problème d'affichage de vue.

  • 06/10/2014 à 14:29

    optyler

    Si t'as un plunkr sous la main je peux jetter un oeil :-p

  • 06/10/2014 à 14:58

    Amaseb

    Merci beaucoup.

    J'ai placé mon code ici http://stackoverflow.com/questions/26140575/angularjs-ng-route-not-working-on-ie9-the-views-are-not-displayed, mais je vais faire un plunkr (j'ai jamais utilisé ce site encore pour partager du code). Cependant une partie du contenu ne sera pas dispo puiqu'il est retrourné de la bdd en json par des fonctions coldfusion.

  • 06/10/2014 à 15:12

    optyler

    Hum... on pourrit un peu la news Numa Claudel là... mais c'est pour la bonne cause!

    plunkr c'est plus ou moins comme jsfiddle... l'intérêt c'est que tu peux "créer des fichiers" et donc faire des mocks de tes services sans trop pourrir ton code ;-)

    bref, on continue sur stackoverflow :-p

  • 09/11/2015 à 23:26

    varloteaux

    très bon tuto, simple et efficace pour débuter...
    merci aussi pour le bon exemple avec séparation des fichiers. sans oublier le fait d'avoir dit comment vous nommiez vos fichiers. dans le routage c'est important lol... tout le monde ne le fait pas... même dans les bouquins... voilà
    merci donc

  • 19/05/2016 à 19:49

    Stephane ABRO

    Tres bon tuto. je suis emu. tout nouvveau dans le devellopement angularjs Jquery et tout ca je me suis donne de faire des merveilles avec angularsj en une semaine quel qu'en soit le prix.

    Je crois que ce tutot m'aidera a apprehender plus facilement tous ces nouveaux concepts contrairement a openclassroom ou j'ai failli devenir fou telment qu'ils m'ont bombardes de tous les concepts a la fois. je pensais que j'etais idiot et que le developpement d'appli web cetait fini pr moi. Grace a vous ca commence a aller. merci infiniment

Ajouter un commentaire