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 :
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.
Les concepts qui pour moi caractérisent le plus AngularJS sont :
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.
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 Introduction à AngularJS!</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 Introduction à AngularJS!</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.
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">
</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
.
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 Introduction à AngularJS!</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">
</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.
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.
Nos conseils et ressources pour vos développements produit.