Présentation AngularJS
Jean Detoeuf
Sommaire
- Introduction et besoin
- Utilisation basique d'AngularJS
- Tests unitaires
- Composants d'AngularJS
- Création de composants
Pourquoi un autre framework JS ?
Comment utiliser AngularJS
Comment bien l'utiliser avec les tests
Composants inclus et en créer
Jean Detoeuf
- Ingénieur concepteur/développeur
- Passionné de Java, Spring, Web, Javascript
- Adore plein de choses hype comme le growth hacking, nodeJS, la programmation reactive, fonctionnelle, le continuous delivery, sauter dans le vide et les choses qui vont vite
- Aime la bière, les voyages, le roller, courir
- Et les nouvelles technos en général
Sondage
Qui
- A déjà utilisé JavaScript ?
- A déjà utilisé jQuery ?
- A déjà utilisé un autre framework JavaScript ?
- A déjà entendu parler d'AngularJS ?
- A déjà utilisé AngularJS ?
- Est à l'aise avec AngularJS ?
Demander de lever la main. Si oui à la dernière, demander à partir !Intro
N'hésitez pas à poser des questionsBesoin
- Fonctionnement standard client/serveur avant 2005 : le serveur produit une page, le client en fait le rendu
- 2005 : Arrivée d'AJAX
- Des "bouts" de page peuvent être affichés à la demande : il n'est pas nécessaire de recharger une page à chaque action
- Aucune intelligence réelle côté client
La génération de page est statique et c'est le serveur qui fait tout
Arrivée d'ajax boulverse ce schéma
On évite au moins de recharger toute la page. Gain en temps de chargement ressenti
Bien mais on sent qu'on peut faire mieux
Evolution des interfaces web
J'ai présenté les deux premier modèles
C'est le troisième modèle qui est utilisé aujourd'hui
Le client a plus d'intelligence
Pourquoi on n'avait pas fait comme ça avant ?
- JavaScript existe depuis longtemps
- L'évolution de la puissance des terminaux (PC, mobile) permet de placer de l'intelligence côté client.
- Les moteurs JavaScript se sont améliorés à partir de 2008 (merci AJAX).
- Même les mobiles peuvent tirer parti de cette amélioration
- Framework JS développé par Google
- Première version 2009
- Fondé sur la programmation déclarative
- Architecture MVC ou plutôt MVVM
- Injection de dépendance
Pourquoi apprendre un framework JavaScript ?
- Vers un monde d'API
- Applications riches
- Applications pour mobiles et tablettes avec PhoneGap
- Présenter des données d'une manière plus simple et efficace
- Intelligence "rapide" côté serveur avec Node.js
Points forts
- Open Source
- Maintenu par Google
- Injection de dépendance
- Couplage faible entre présentation, données, composants métier
- Tests unitaires et bout en bout
- Compatible REST
- Compatible WebSockets
Points faibles
- Encore en évolution
- Ne fonctionne pas sur IE6, et adaptations à faire pour IE7 et IE8
- La gestion des fichiers peut vite devenir cahotique si on ne la maitrise pas.
- Validation à implémenter côté client
- Possibilité d'être remplacé un jour par DartJS
La gestion des fichiers est un pb qui concerne tous les FW JS récents
Concurrents
- Backbone.js
- Ember.js
- Knockout.js
- React.js
- Plusieurs frameworks qui gèrent le rendu HTML, les feuilles de style, voir même le Back Office
- JQuery n'est pas un concurrent, il est complémentaire
- La force d'AngularJS est de ne pas tout faire, de se concentrer sur le MVVM
Pourquoi AngularJS plutôt qu'un autre framework JavaScript ?
(Moi j'adore le jQuery, ça marche très bien...)
Des frameworks JavaScript il en sort tous les jours
Plutôt que de vous donner la preuve, c'est internet qui va le faire
Utilisation d'AngularJS
Bases
Maintenant que vous êtes convaincus, voici les bases
Installation
- Aller sur angularjs.org
- Télécharger la dernière version et l'inclure dans sa page web
-
Ou utiliser le CDN Google pour l'inclure dans sa page web
<html ng-app="myApp">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.min.js"></script>
</head>
<body>
</body>
</html>
Installation très simple
Evaluations
- Une évaluation permet d'afficher une valeur
- Exemple : {{1+1}} affiche 2
<html ng-app="myApp">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.min.js"></script>
<script type="text/javascript">
var myApp = angular.module('myApp', []);
</script>
</head>
<body>
Réponse : {{ 7 * 6 }}
</body>
</html>
Démonstration
Injection de dépendances 1/2
- Permet l'inversion de contrôle
- Fonctionne par module
- Un module peut dépendre d'autres modules
- Il est alors possible de faire appel aux méthodes de ces modules
- Permet la séparation de considérations
- Code testable unitairement (un module représente une fonctionnalité et les autres modules peuvent être mockés)
Injection de dépendances 2/2
- L'injection se fait simplement en l'ajoutant à la liste des dépendances du module
- Puis le module peut être utilisé en paramètre d'une fonction
angular.module('myApp', ['Clock','Bell']);
var ringMyBell = function($scope,Clock,Bell){...}
controleur
- Conteneur permettant de gérer des variables
- En JavaScript, des variables peuvent être des fonctions
- Les variables d'un controleur sont contenue dans son $scope
- Le $scope permet l'étanchéité des variables au sein du controleur
<html ng-app="myApp">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.min.js"></script>
<script type="text/javascript">
var myApp = angular.module('myApp', []);
myApp.controller('MyCtrl', function MyCtrl($scope) {
$scope.reponse = 42;
});
</script>
</head>
<body ng-controller="MyCtrl">
Réponse : {{ reponse }}
</body>
</html>
Démonstration
Répéteur
- ng-repeat permet d'itérer sur une liste (ie. foreach)
<html ng-app="myApp">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.min.js"></script>
<script type="text/javascript">
var myApp = angular.module('myApp', []);
myApp.controller('MyCtrl', function MyCtrl($scope) {
$scope.elems = [0,1,1,2,3,5,8,13];
});
</script>
</head>
<body ng-controller="MyCtrl">
{{elems.length}} premiers éléments de la suite de Fibonacci :
<ul><li ng-repeat="elem in elems track by $index">{{elem}}</li></ul>
</body>
</html>
Démonstration
Filtres 1/3
- Permet de modifier le rendu d'une valeur
- Peut s'appliquer sur des listes
- Exemple de filtres :
- filter
- orderBy
- limitTo
- date
- currency
- json
- lowercase
- uppercase
- number
Filtres 2/3
<html ng-app="myApp">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.min.js"></script>
<script type="text/javascript">
var myApp = angular.module('myApp', []);
myApp.controller('MyCtrl', function MyCtrl($scope) {
$scope.technos = ['JavaScript', 'HTML', 'CSS', 'Java'];
});
</script>
</head>
<body ng-controller="MyCtrl">
Technologies :
<ul><li ng-repeat="techno in technos">{{techno}}</li></ul>
Technologies Java* :
<ul><li ng-repeat="techno in technos | filter:'Java'">{{techno}}</li></ul>
</body>
</html>
Démonstration
Filtres 3/3
- Possibilité de créer ses propres filtres
- Permet de factoriser un comportement
<html ng-app="myApp">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.min.js"></script>
<script type="text/javascript">
var myApp = angular.module('myApp', []).filter('truncate', function () {
return function (text,length) {
return (text.length<=length)?text:(String(text).substring(0,length)+'...');
};
});
myApp.controller('MyCtrl', function MyCtrl($scope) {
$scope.blah = 'blah blah blah blah blah blah blah blah blah';
});
</script>
</head>
<body ng-controller="MyCtrl">
<table>
<tr><td>Avant filtre</td><td>{{blah}}<td/></tr>
<tr><td>Après filtre de taille 18</td><td>{{blah|truncate:18}}<td/></tr>
</table>
</body>
</html>
Démonstration
Binding bidirectionnel 1/3
- Vue vers Modèle : Certains composants permettent de modifier le modèle à partir de la vue
- Modèle vers Vue : Toute modification du modèle entraine la modification de la vue associée
- AngularJS est assez intelligent pour savoir quels sont les composants affectés par une modification
- Chaque mise à jour de la vue à partir du modèle s'appelle un digest
- AngularJS optimise le digest pour le rendre très perfomant, voir instantané
Binding bidirectionnel 2/3
Binding bidirectionnel 3/3
<html ng-app="myApp">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.min.js"></script>
<script type="text/javascript">
var myApp = angular.module('myApp', []);
myApp.controller('MyCtrl', function MyCtrl($scope) {
$scope.nom = 'le monde';
});
</script>
</head>
<body ng-controller="MyCtrl">
Bonjour <input ng-model="nom"/><br/>
Comment ça va, {{nom}} ?
</body>
</html>
Démonstration
Ressources
- Angular gère nativement le REST
- Il est possible d'effectuer n'importe quelle requête HTTP
- Définir une vraie ressource HTTP avec paramétrage de l'URI (ie. /user/:id ou /post/:name)
<html ng-app="myApp">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.min.js"></script>
<script type="text/javascript">
var myApp = angular.module('myApp', ['ngResource']);
myApp.factory('AngularJsIssues', function($resource){
return $resource('https://api.github.com/repos/angular/angular.js/issues');
});
myApp.controller('MyCtrl', function MyCtrl($scope,AngularJsIssues) {
$scope.issues = AngularJsIssues.query();
});
</script>
</head>
<body ng-controller="MyCtrl">
<table>
<tr>
<th>Id</th>
<th>State</th>
<th>Title</th>
</tr>
<tr ng-repeat="issue in issues">
<td ng-bind="issue.id"></td>
<td ng-bind="issue.state"></td>
<td ng-bind="issue.title"></td>
</tr>
</table>
</body>
</html>
Démonstration
Utilisation d'AngularJS
Tests
Introduction
- Quoi ? des tests automatisés en JavaScript ??
- Tests unitaires et tests bout en bout (E2E)
- Lancement des tests avec
- Les tests peuvent être lancés sur plusieurs navigateurs
- Karma peut aussi faire les tests sur un port (ie. mobile ouvert sur un port d'écoute)
Exemple
- Unit tests : Test d'un module
- End-to-end tests : Test de plusieurs modules
- Les interfaces peuvent être bouchonnées (voir angular.mock.inject)
- Tous les exemples de cette présentation ont leur test
'use strict';
describe('myApp', function(){
var curModule;
beforeEach(curModule = module('myApp'));
describe('myApp module', function(){
it('should have a module', function() {
expect(curModule).not.toBeNull();
});
});
describe('Controller', function(){
var scope, ctrl;
beforeEach(inject(function($rootScope, $controller) {
scope = $rootScope.$new();
ctrl = $controller('MyCtrl', {$scope: scope});
}));
it('should have a controller', function() {
expect(ctrl).not.toBeNull();
});
});
});
Utilisation d'AngularJS
Fonctions avancées
Directives 1/2
- Utiliser des nouveaux tags
- Utiliser des nouveaux attributs
<alert>Alerte !</alert>
<datepicker min="minDate" show-weeks="showWeeks"/>
Directives 2/2
- Possibilité de créer ses directives
- Comme si on réécrivait du HTML
- Peut être "compilé"
<twitter-tweet-page/>
<google-plus-page/>
<facebook-like-page/>
<twitter-direct-message user="@thebignet"/>
<twitter-followers user="@thebignet"/>
<github-last-commit user="thebignet" project="pres-angularjs"/>
router
- Permet de lier à une URI une vue et un controleur
- /users affiche la vue imbriquée users.html avec le controleur UserCtrl
ui-router
- Meilleur que le routeur intégré à AngularJS
- Permet de gérer des états plutôt que des URI
- Plusieurs vues/controleurs pour un URI
- Vues imbriquées
- Directive pour une navigation plus simple
Vues
- Avec le routeur intégré à AngularJS
myApp.config(['$routeProvider',
function($routeProvider) {
$routeProvider
.when('/users', { templateUrl: 'users.html', controller: 'UserCtrl' })
.otherwise({ redirectTo: '/' });
}]);
<div ng-view></div>
Vues
myApp.config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise("/");
$stateProvider.state('users', { url: "/users", templateUrl: "users.html" })
});
<div ui-view></div>
Animations
- Basé sur des évènements liés à des directives
- Suite à l'ajout/suppression d'un élément à une liste
- Suite à la modification d'une valeur
- AngularJS applique des classes CSS spécifique avant et pendant l'action
- Toutes les transitions CSS3 sont utilisables
jQuery
- Version allégée de jQuery inclue dans AngularJS
- Peut être surchargée par la version complète
- La version allégée ne contient pas les sélecteur css et c'est pour votre bien car ce n'est pas la philosophie d'AngularJS
Intégration continue
- Les tests peuvent être exécutés sur plusieurs navigateurs à chaque sauvegarde en local ou à chaque commit
- Karma peut être lancé par Jenkins, Sonar, ou Travis
- Les rapports produits sont au format Junit
Pour monter un projet rapidement
- Angular-seed
- Framework CSS : Twitter Bootstrap, Foundation
- Utiliser Yeoman avec generator-angular ou generator-jhipster
Hébergement
- Le serveur peut héberger les ressources front et fournir l'API
- Possibilité d'avoir un serveur statique pour le front et une API pour le back
- Plus de flexibilité quant à la charge reposant sur chacun
- Les serveurs frontaux peuvent mettre les ressources en cache efficacement
- Les serveurs d'API peuvent être dimensionnés
- Ce découpage se prête plus facilement à un cloud