On Github Pierrci / intro-angular
W. Churchill, 13 mai 1940
David East - Firebase & Angular team
Au sujet de MVC / MVVM :
Aujourd'hui, version 1.X - https://angularjs.org/
Demain, version 2.X - https://angular.io/
La classe non ?
<html> <head> Index </head> <body> Name: Hello ! </body> </html>
<html> <head> Index </head> <body ng-app> Name: Hello {{ nameModel }} ! </body> </html>
<html> <head> Index </head> <body ng-app> Name: Hello {{ nameModel }} ! </body> </html>
<body ng-app="monApplicationAngular">
La valeur passée à ngApp est le nom du module principal de l'application.
Un module contient les composants de notre application : controllers, directives, services, filtres...
Pour pouvoir ajouter ces composants, il faut déclarer le module côté javascript :
var app = angular.module("monApplicationAngular", [ "ngRoute", "ngResource", //... ]); // Dans sa forme la plus simple : // var app = angular.module("monApplicationAngular", []);
Une fois déclaré, on peut l'appeler et lier des composants :
angular .module("monApplicationAngular") .directive("uneDirective", maDirective); function maDirective() { //... }
<body ng-app="monApplicationAngular"> 1 + 2 = {{ 1 + 2 }} Nom de l'utilisateur : {{ user.name }} Loisir n° 3 de l'utilisateur : {{ user.loisirs[2] }} </body>
Comment et où déclarer user ?
=> Dans un controller
C'est là que l'on interagit avec les données de la vue
angular .module("monApplicationAngular") .controller("HomeController", HomeController); function HomeController() { var vm = this; // vm pour ViewModel vm.user = { name: "Pierric", loisirs: ['ski', 'lecture', 'musique'] } }
On "bind" les méthodes et variables qui nous intéressent au this de HomeController
Il faut penser à déclarer le controller dans le HTML grâce à la directive ngController
<body ng-app="monApplicationAngular">
On utilise la syntaxe controllerAs, indissociable du binding à l'instance du controller (le this côté JS), en spécifiant un alias pour notre controller : home (arbitraire)
Dans le javascript, on aurait pu aussi lier le modèle à $scope au lieu de this, sans utiliser la syntaxe controllerAs :
function HomeController($scope) { $scope.user = { name: "Pierric", loisirs: ['ski', 'lecture', 'musique'] } }
Côté HTML :
On préfèrera limiter $scope à l'utilisation de méthodes qui en dépendent telles que $watch, $on ou $broadcast
function HomeController($scope) { var vm = this; vm.username = "Pierric"; $scope.$on('someEventFiredFromElsewhere', function (event, data) { // do something! }); }
ngApp, ngController, ngModel, ... sont des directives
Ce sont des marqueurs positionnés sur des éléments du DOM qui indiquent à angular quel comportement attacher à un élément et/ou quelle transformation y apporter
De nombreuses directives sont intégrées nativement : https://code.angularjs.org/1.4.11/docs/api/ng/directive
Map Syntax Example
Disabled
Les filtres permettent de formatter et de... filtrer (!) les expressions auxquelles ils sont appliqués :
{{ expression | filter }} {{ expression | filter1 | filter2 }} {{ expression | filter:arg1:arg2 }}
Exemples :
{{ 'Mon texte' | uppercase }} {{ '25.465' | number:2 | currency:'$'}}
Liste des filtres natifs : https://docs.angularjs.org/api/ng/filter
Soit le tableau suivant dans un controller:
var jb = {name: 'JB', gender: 'male'}, cyril = {name: 'Cyril', gender: 'male', birth: '1990-11-25'}, agnes = {name: 'Agnes', gender: 'female', birth: '1991-07-22'}, cedric = {name: 'Cedric', gender: 'male', birth: '1992-02-22'}; vm.ninjas = [jb, cyril, agnes, cedric];
Avec le HTML suivant :
{{ ninjas | orderBy:'name' | limitTo:2 }}
On obtiendra :
[ {"name":"Agnes","gender":"female","birth":"1990-07-22"}, {"name":"Cedric","gender":"male","birth":"1990-02-22"} ] 1990 1991 1992
filter permet d'appliquer un filtre personnalisé aux éléments d'un tableau
Name Birth date {{ friend.name }} {{ friend.birth | date:'dd/MM/yyyy' }}
Any: Name only Gender only Equality Name Gender {{ ninja.name }} {{ ninja.gender }}
Learn AngularJS | Codecademy - Unit 1
Shaping up with AngularJS | CodeSchool - Levels 1 / 2 / 3
L'avenir du web est aux Web Components : découpage des fonctionnalités en modules réutilisables indépendamment.
Les directives sont un avant-goût et permettent d'implémenter une partie de cette logique.
peut devenir :
Fichier bookDetails.directive.js :
angular.module('myApp') .directive('bookDetails', bookDetails); // camelCase côté JS ! function bookDetails() { return { // Une directive retourne un objet de "configuration" restrict: 'E', // La directive doit être appelée sous forme d'élément scope: { // On crée un nouveau scope isolé propre à la directive book: '=' // On récupère l'objet passé à l'attribut correspondant }, templateUrl: 'bookDetails.tpl.html', // Indique où aller chercher le HTML }; }
Fichier bookDetails.tpl.html :
... controller: function () { var vm = this; vm.selectBook = function () { ... } }, controllerAs: 'bookDetails', bindToController: true ...
Learn AngularJS | Codecademy - Unit 2
Shaping up with AngularJS | CodeSchool - Level 4
Les services sont des objets dans lesquels on met le code correspondant à la logique métier de l'application. Ils sont aussi utilisés pour organiser le code partagé de l'application.
Les services sont :
$http({method: 'GET', url: '/serverUrl'}) .success(function(data, status, headers, config){ ... }) .error(function(data, status, headers, config){ ... });
{ 'get': {method:'GET'}, 'save': {method:'POST'}, 'query': {method:'GET', isArray:true}, 'remove': {method:'DELETE'}, 'delete': {method:'DELETE'} };
var Poneys = $resource('/races/:raceId/poneys/:poneyId', { raceId: 24, poneyId: '@id'}, { run: { method: 'PUT' }}); var fury = Poneys.save({ name: 'Fury Red'});
// avec l'url http://example.com/#/some/path?foo=bar&baz=xoxo var path = $location.path(); // => "/some/path" var searchObject = $location.search(); // => {foo: 'bar', baz: 'xoxo'}
var delayedFn = $timeout(function(){ ... }, 1000) // Après 1 seconde. var recurringFn = $interval(function(){ ... }, 1000, 0) // Chaque seconde.
Autres wrappers ($window, $document...) et services natifs : https://docs.angularjs.org/api/ng/service
Nouveauté de l'EcmaScript 6, implémentée via le service $q. Utilisée lors de traitements asynchrones tels que les requêtes AJAX avec $http.
Une promise peut avoir deux résultats : succès ou échec.
$http.get(...) .then(function(data){ // succès, promise résolue }, function(error){ // erreur, promise rejetée });
function asyncGreet(name) { var deferred = $q.defer(); // On crée un objet deferred $timeout(function() { // Ici on crée artificiellement un délai deferred.notify('About to greet ' + name + '.'); if (okToGreet(name)) { deferred.resolve('Hello, ' + name + '!'); // succès } else { deferred.reject('Greeting ' + name + ' is not allowed.'); // échec } }, 1000); return deferred.promise; // On retourne la promise de deferred } var promise = asyncGreet('Robin Hood'); // La fonction retourne une promise promise.then(function(greeting) { alert('Success: ' + greeting); // En cas de succès }, function(reason) { alert('Failed: ' + reason); // En cas d'échec }, function(update) { alert('Got notification: ' + update); // Indication de progression });
Pour pouvoir utiliser un composant dans un autre, angular utilise un système d'injection de dépendance.
function HomeController($scope, $http) { ... } // function HomeController($http, $scope) { ... } // équivalent !
HomeController.toString(); // "function HomeController($scope, $http) { ... }"
Pour éviter les problèmes en cas de minification du javascript, on "annote" les composants :
HomeController.$inject = ['$scope', '$http']; function HomeController($scope, $http) { ... } // Il vaut mieux garder le même ordre...
Learn AngularJS | Codecademy - Unit 3
Shaping up with AngularJS | CodeSchool - Level 5
ngRoute est le module angular de base chargé du routage. Il est composé d'une directive ngView, d'un $routeProvider et de 2 services : $route et $routeParams.
ngView indique quelle partie de la SPA sera mise à jour :
$routeProvider permet de déterminer les routes de l'application et de faire le lien entre URL, template et controller.
angular .module("monApplicationAngular") .config(configure); function configure($routeProvider) { $routeProvider .when('/races/:raceId?', { // raceId est un paramètre facultatif templateUrl: 'races.html', controller: 'RacesController' // Remplace ng-controller="..." }) .when('/', { templateUrl: 'poneys.html', controller: 'PoneysController' controllerAs: 'poneys' // Remplace ng-controller="... as ..." }) .otherwise('/'); // Si l'url ne correspond pas, redirection }
Service permettant de déterminer les paramètres de la route. Combinaison de $location.search() et $location.path().
// Avec une url = http://www.example.com/#/races/13?poney=10 $routeParams ==> { raceId: "13", poney: "10" }
Learn AngularJS | Codecademy - Units 4 / 5