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