Si vous pensez encore que le data-binding, l’inversion de dépendances, le pattern MVC ou bien encore la gestion de la navigation sont réservés au code Java des applications web modernes, courrez assistez à ce workshop. AngularJS, le dernier framework JavaScript de chez Google, devrait vous surprendre.
Basée sur l’université AngularJS, ou le futur du développement Web présentée lors de Devoxx France 2013, ce workshop a pour objectif de vous initier à AngularJS.
Les concepts fondamentaux seront mis en en action au travers de l’application Game Store.
Côté industrialisation, nous verrons que tests unitaires, tests fonctionnels et infrastructure de build ne sont pas non plus délaissés.
A l’heure où la couche présentation des applications web est de plus en plus déportée côté client, ce workshop a pour objectif de démystifier ce type de framework permettant de structurer une application JavaScript.
3. INTRODUCTION
1 nouveau framework MVC JavaScript
+2 ans d’existence
+3 développeurs principaux
•Miško Hevery, Vojta Jína et Igor Minar
+43 000 lignes de code JavaScript
+80 Ko minifié
+ 3 applications significatives en production
3
ANGULARJS EN QUELQUES CHIFFRES
7. CONCEPTS FONDAMENTAUX
7
LE DATA-BINDING BI-DIRECTIONNEL (1/3)
+Nombreux systèmes de templating :
String statique + données => texte ajouté au DOM par innerHTML
+Tout changement sur une donnée nécessite un nouveau merge
9. CONCEPTS FONDAMENTAUX
+LA MAGIE DU DATA-BINDING REPOSE SUR 2 MÉCANISMES :
COMPILATION DU DOM
•Analyse du DOM au démarrage de l’application
•Directives remplacées par fonctions JS et un scope
•DOM dynamisé
LES WATCHS
•Surveille tout objet JavaScript
•Détecte qu’une valeur a changé depuis
la dernière analyse
+CONTRAINTES
S’applique aux objets managés par Angular
Performance : limite des 2000 watches
9
LE DATA-BINDING BI-DIRECTIONNEL (3/3)
10. CONCEPTS FONDAMENTAUX
+ CONTEXTE D’EXÉCUTION D’UNE DIRECTIVE ANGULAR
•Créé par les directives ng-app, ng-controler et ng-repeat
+RECEPTACLE
DES DONNÉES DU MODÈLE
DES MÉTHODES DÉDIÉES À LA VUE
+STRUCTURE HIÉRARCHIQUE
SCOPE RACINE
UTILISE L’HÉRITAGE PAR PROTOTYPE DU JAVASCRIPT
SUIT LA STRUCTURE DU DOM
+UTILISÉ LORS DE L’ÉVALUATION DES {{ EXPRESSIONS }}
10
LE SCOPE (1/3)
11. CONCEPTS FONDAMENTAUX
11
LE SCOPE (2/3)
$scope.catalog = [ {
name : 'Le Trône de Fer',
price : 48.90
}, {
name : 'Twilight Struggle',
price : 49.90
} ];
<ul ng-controller="GameCtrl">
<li ng-repeat="game in catalog">
Nom : {{game.name}} - Tarif : {{game.price}}
</li>
</ul>
+EXEMPLE : LISTE D’UN CATALOGUE DE JEUX DE PLATEAU
Objet littéral JavaScript ajouté par le GameCtrl au scope courant :
Modèle de données
12. CONCEPTS FONDAMENTAUX
12
LE SCOPE (3/3)
<html ng-app>
</html>
<ul ng-controller="GameCtrl">
</ul>
<li ng-repeat="game in catalog">
</li>
Nom : {{game.name}}
Root
Scope
GameCtrl
Scope
Repeater
Scope
Repeater
Scope
• Nom : Le Trône de Fer
• Nom : Twilight Struggle
catalog
game
13. CONCEPTS FONDAMENTAUX
+LE PATTERN MVC STRUCTURE LES APPLICATIONS ANGULAR
+CARACTÉRISTIQUES D’UN CONTRÔLEUR :
FONCTION JAVASCRIPT
POSITIONNABLE SUR UN ÉLÉMENT DE LA VUE
•Utilisation de la directive ng-controller.
POSITIONNABLE SUR UNE VUE PARTIELLE
•Lors de la définition d’une route
ACCEPTE DES SERVICES EN PARAMÈTRES
•Prédéfinis ou spécifiques
•Injectés par Angular
INDÉPENDANT DE LA VUE
•Plusieurs vues possibles
•Pas de manipulation de DOM
•Tests facilités
13
LES CONTRÔLEURS MVC (1/2)
14. CONCEPTS FONDAMENTAUX
+EXEMPLE : AFFICHAGE DE LA PAGE DE DÉTAIL D’UN JEU DE PLATEAU
14
LES CONTRÔLEURS MVC (2/2)
function GameCtrl($scope, $routeParams, $http) {
$http.get("data/" + $routeParams.ref + ".json")
.success(function (data) {
$scope.game = data;
});
};
URL : http://localhost:8000/app/index.html#/game/AGOT
<img ng-src="img/{{game.ref}}.jpg"/>
<h2>{{game.name}}</h2>
<p>Auteur : {{game.designer}}</p>
Ressource data/AGOT.json :
{
"ref": "AGOT",
"name": "Le Trône de Fer",
…
}
15. CONCEPTS FONDAMENTAUX
+CODE TRANSVERSE AUX CONTRÔLEURS
+SINGLETONS
+SERVICES CLÉS EN MAIN PROPOSÉS PAR ANGULAR :
15
SERVICES (1/2)
Services Description
Scope Contexte d’exécution, observe les expressions
Routing Gère les URL et les routes vers les contrôleurs et les sous-
vues
i18n Internationalisation
Resource API de type REST avec support JSONP, cache, bulk
Filter Fonctions de transformations sur une donnée
Q (Q Library) Promise permettant de représenter le résultat différé d'une
opération asynchrone
16. CONCEPTS FONDAMENTAUX
16
SERVICES (2/2)
+SERVICES PERSONNALISÉS
•Exemple d’un panier d’achats
var moduleSrv = angular.module('gamestore.services', []);
moduleSrv.factory('Cart', function () {
return {
rows: {},
add: function (game) { … },
total: function () {
var sum = 0;
for (var i in this.rows) {
sum += this.rows[i].qty * this.rows[i].game.price;
}
return sum;
},
totalHT: function () {
return this.total() * 100 / (100 + 19.6);
},
};
});
17. CONCEPTS FONDAMENTAUX
+BASÉE SUR LE SERVICE LOCATOR INJECTOR
LOOKUP PAR LE NOM DU SERVICE
var cart = $injector.get('Cart');
+INJECTION DES SERVICES DANS LES CONTRÔLEURS
AUTOMATIQUE PAR LEUR NOM
function MainCtrl($scope, Cart) { … };
EXPLICITE
function MainCtrl(scope, newCart) { … };
MainCtrl.$inject = ['$scope', 'Cart'];
+BÉNÉFICES
DÉCOUPLAGE
SÉPARATION DES PRÉOCCUPATIONS
FACILITE L’ÉCRITURE DES TESTS UNITAIRES
17
INJECTION DE DÉPENDANCES
18. CONCEPTS FONDAMENTAUX
+FILTRE OU MODIFIE L’AFFICHAGE DES DONNÉES ÉVALUÉES
+SYNTAXE INSPIRÉE DE LINUX : CARACTÈRE PIPE « | »
+FILTRES PRÉ-INCLUS
CURRENCY, DATE, HTML, JSON, LINKY, LOWERCASE, NUMBER, LIMITTO, ORDERBY
+EXEMPLES :
18
LES FILTRES
<li ng-repeat="game in catalog | filter:search">
<span class="price">{{game.price | number:2}} €</span>
Critère de recherche
<input ng-model="search"/>
<li ng-repeat="game in catalog | orderBy:'name'">
Propriété du
modèle game
19. CONCEPTS FONDAMENTAUX
+ ETEND LE HTML
+BALISES OU ATTRIBUTS HTML
Mais aussi classes CSS et commentaires HTML
+LES DIRECTIVES FOURNIES PAR ANGULAR COMMENCENT PAR NG-*
ng-click, ng-repeat, ng-model, ng-controller, ng-app, ng-show, ng-include, ng-class
+PERMET LA CRÉATION DE COMPOSANTS RÉUTILISABLES
JavaScript + HTML
19
DIRECTIVES (1/2)
<game-img game="game"/>
<a href="#/game/AGOT"
class="AGOT">
<img ng-src="image/
AGOT.jpg"/>
</a>
20. CONCEPTS FONDAMENTAUX
20
DIRECTIVES (2/2)
angular.module('gamestore.directives', [])
.directive('gameImg', function() {
return {
restrict: 'E',
replace: true,
scope: {
game: '='
},
template: '<a href="#/game/{{game.ref}}">
<img ng-src="img/{{game.ref}}.jpg"/></a>',
link: function(scope, element) {
if (scope.game.name === 'Le Trône de Fer') {
element.addClass('AGOT');
}
}};
});
Directive de type Element (tag HTML)
Le template remplace l’élément du DOM
Paramètre de la directive
Disponible dans le scope de la directive
Fonction JS appelée avant l’affichage de la vue
Dynamise la directive
21. TESTS
+APPLICATION FACILEMENT TESTABLE
PAS DE MANIPULATION DE DOM DANS LES CONTRÔLEURS
MOCKS ENCOURAGÉS
+TESTS UNITAIRES
COUVERTURE POSSIBLE DE TOUT LE CODE JS
INTÉGRATION DE JASMINE ET TESTJS DANS KARMA
EN CONTINUE
MULTI-NAVIGATEURS
+TESTS END-TO-END
À LA SELENIUM
REPOSE SUR KARMA
CONNAISSANCE NATIVE DU FONCTIONNEMENT D’ANGULAR
21
FACILITÉS ET COMPLETS
22. TESTS
22
TESTS UNITAIRES DU CONTRÔLEUR GAMECTRL
// Prépare les données de test : mock simulant une réponse JSON,
// scope vierge et contrôleur à tester avec paramètre HTTP
$httpBackend.expectGET('data/AGOT.json')
.respond( { "ref": "AGOT",
"name": "Le Trône de Fer"
} );
var scope = $rootScope.$new();
var ctrl = $controller('GameCtrl',
{$scope: scope, $routeParams: {ref: 'AGOT'}});
// Exécution du test unitaire et assertions
it('should load game information', function () {
expect(scope.game).toBeUndefined();
$httpBackend.flush();
expect(scope.game.ref).toBe("AGOT");
expect(scope.game.name).toMatch(/Trône/);
});
@Setup
@Test
23. TESTS
23
TESTS END-TO-END AVEC KARMA
describe('Game view', function () {
beforeEach(function () {
browser().navigateTo('#/game/AGOT');
});
it('should render AGOT game details view', function () {
expect(element('h2').text()).toMatch(/Trône/);
});
});
it('should add to cart from catalog', function () {
browser().navigateTo('#/catalog');
expect(element('#catalog li').count()).toBeGreaterThan(1);
element('#catalog li:nth-child(1) .add').click();
browser().navigateTo('#/catalog');
element('#catalog li:nth-child(2) .add').click();
browser().navigateTo('#/cart');
expect(element('#cart tr.game').count()).toEqual(2);
});
24. CONCLUSION
+GESTION DE LA NAVIGATION
+BOUTONS PRÉCÉDENT / SUIVANT
+ VALIDATION DES CHAMPS D’UN FORMULAIRE
+ MODULARISATION
+ PAGINATION DE TABLEAUX
+ ANIMATION
24
APERÇU D’AUTRES FONCTIONNALITÉS
25. CONCLUSION
+ LES SLIDES DE L’UNIVERSITÉ SUR ANGULARJS À DEVOXX FRANCE 2013
http://tchatel.github.com/slides-angularjs/
+ BLOG FRANCOPHONE SUR LE FRAMEWORK ANGULARJS
http://www.frangular.com/
+ TUTORIAL DU SITE OFFICIEL D’ANGULARJS
http://docs.angularjs.org/tutorial
+ CONCEPTS DU FRAMEWORK SUR LE SITE OFFICIEL :
http://docs.angularjs.org/guide/concepts
+ SÉRIES DE COURTES VIDÉOS RÉALISÉES PAR JOHN LINDQUIST :
http://egghead.io/
+ COMMUNAUTÉ GOOGLE+ ANGULARJS FRANCE :
https://plus.google.com/communities/109984348857296908402
+ WORKSHOP GDC ANGULARJS D’ANTOINE RICHARD
Repo Github : https://github.com/antoine-richard/angular-movie-workshop
Explications sur le blog de Rossi Oddet:
HTTP://BLOG.RODDET.COM/2013/04/STEREOLUX-WORKSHOP-HTML5/ 25
RESSOURCES EN LIGNE
26. CONCLUSION
26
AVANTAGES ET INCONVÉNIENTS
Avantages Inconvénients
Two-way data binding
Pattern du monde Java
Testabilité
Sponsorisé par Google
Structure les développements
Création de widgets
Connaissances JavaScript
indispensables
Philosophie à appréhender
Composants graphiques externes
Jeunesse
Verbosité HTML
Autres frameworks MVC JavaScript : Knockout.js, Ember.js, Backbone.js, CanJS
Intégration possible avec JQuery, RequireJS
Google : DART, GWT, Angular, GO
Applis en prod : manager OVH v5 beta, Google Doublick for publishers, Youtube pour PS3
SPA :
Angular cible les applications dynamiques (appli web RIA versus sites statiques)
Exemples : Gmail, applis développés en GWT
Les applis de gestion sont de parfaits candidats
A relativiser : notions de vue ⬄ pages. Même .html mais ancres # différentes pour chaque vue.
Un refresh (F5) réinitialise l’application.
Déclaratif: là où JQuery reste de l’impératif=> moins de code JavaScript de manipulation du DOM
Angular propose un sous-ensemble de JQuery (ex: addClass, removeClass) basée sur une implémentation jQlite.
JQuery est optionnel. Si présente Angular, utilisera JQuery à la place de jQlite.
Facilite le travail avec les web designers
Data-binding : un modèle, plusieurs vues
Angular enrichit le HTML à l’aide de directives : balises et tags ng-xxx, influence sur HTML 6
Design Patterns : MVC, IoC, Factory, Singleton
Composants : création de nouveaux tags HTML pour alléger les pages. Initiative des Web Components au sein du W3C (cf. Angular-UI, Work in Progress…)
Doctype HTML 5
Possibilité d’intégrer Angular sur une d’une application existante en positionnant ng-app sur un div
La notation entre double accolades référence une variable AngularJS
L’attribut ng-model dans la balise input est une directive Angular qui permet de lier la variable name au champ de texte
Au chargement de la page dans le navigateur, le champs de saisie est vide. Lors d’une saisie, la balise <p>Hello est immédiatement mise à jour.
Solutions de templating JS : Mustache, Handlesbar
Aucune action nécessaire par le développeur pour rafraichir la vue lorsque le modèle a changé, même depuis la vue.
Observation manuelle des changements du modèle par appel de la fonction $watch
Le plugin Batarang pour Chrome permet d’avertir le développeur des data-binding trop coûteux
Initiative Object.observe() pour améliorer nativement les performances. Support dans Chrome depuis Canary 25, pour les autres ??
Espace de stockage entre une balise ouvrante et fermante
Lien entre le modèle, la vue et le contrôleur
Durée de vie bornée par sa directive
Scope racine : rootScope => 1 par application
catalog : nom du tableau sur lequel itérer
game : variable locale au <li> de chaque itération
Permet également de travailler avec les patterns Model View Presenter (MVP) et Model View ViewModel (MVVM).
Un contrôleur définit l’état initial d’un scope, et permet gérer ce scope => il implémente les règles métiers gérant le modèle de données
Le contrôleur ne doit pas :
Manipuler le DOM -> responsabilité des directives, et le data-binding assure la maj de la vue suite à la modif du modèle par le contrôleur
Formater ou filtre les données (angular form controls, angular filter)
Implémenter du code partagé entre contrôleur -> utiliser des services
L’attribut ng-src permet d’éviter des erreurs 404 au chargement de la page
Exemple : un panier d’achat
Service = un objet JavaScript avec des propriétés et des fonctions
Les services fournis par Angular sont reconnaissables par leur préfixe $
Promise : à rapprocher aux FutureTask de Java
Module : permet d’organiser le code (découpage technique et/ou fonctionnel)
La méthoe add(game) ajoute un jeu dans le tableau rows
Egalement : injection des services dans les fabriques de méthodes
TU : passage de bouchons aux contrôleurs testés
Angular met à disposition des mocks pour certains services pré-définis (ex: http)
Currency, Date : formattage monnaie, date
limitTo : sous-tableau (>0 : depuis le début, <0 depuis la fin)
Permet de dynamiser un DOM statique contenant du HTML et du CSS.
Transforme la page HTML en template
Directives :
ng-click : fait appel sur un clic utilisateur à une fonction du contrôleur JS associé
ng-repeat : itération sur des collections (li, tr)
ng-model : référence une donnée du scope
ng-controller : spécifie le contrôleur JS à utiliser
ng-show : affiche un nœud en fonction de la condition passée
ng-include : inclue une page HTML partielle
ng-class : ajoute ou supprime une classe CSS sur un nœud
Exemple de directives supplémentaires : BindOnce (permet de faire un bind sans watch) -> reprend certaines directives angular
Bo-text,
Bo-href
Mécanismes à connaître pour créer une directive : compilation, linking, transclusion, scope, interpolation
gameImg est le nom de la directive (camel case). Utilisation dans le code HTML : game-img, game:img, …
Restrict accepte les 4 types :
E : Element
A : Attribut
C : Class
M : Comment
Link : fonction JS appelée pendant la phase de Linking, à savoir après la phase de compilation de la directive mais avant l’affichage de la vue
Karma = ex-testacular
En continue à la Infinitest
E2E : support des requêtes Ajax et de la mise à jour cyclique lors de data-binding
Gestion de la navigation : routing
Gestion des boutons précédent/suivant, historique, bookmark, permet l’ indexation dans les moteurs de recherche
Pour gérer l’historique et le bouton Back, Angular sait exploiter l’API History HTML 5 si elle est dispo
Validation
Validateur fourni : date, email, entier, nombre, URL, regexp + validateur curstom + gestion de l’asynchrone
Validation asynchrone et validateur personnalisé
Attribut required du HTML5 et polyfill pour navigateurs non compatibles
Modularisation : espaces de nommage, découpage technique et/ou fonctionnels
Animation : animations CSS disponibles dans la version béta 1.1.x
Vidéo de l’université disponible gratuitement sur Parleys
Donne envie de se (re)mettre au HTML
Facilite le travail avec les intégrateurs web
plain old JavaScript sans surcouche
Laisse possible l’utilisation de CoffeeScript et de TypeScript