Angular, première partie

This commit is contained in:
William Petit 2015-04-08 23:22:53 +02:00
parent de745ba6df
commit 16a28eb88b
32 changed files with 585 additions and 35 deletions

View File

@ -2,7 +2,7 @@
.cadoles-list[ .cadoles-list[
- Framework applicatif côté client en Javascript - Framework applicatif côté client en Javascript
- Initialement présenté par Google en 2009 - Initialement présenté par Google en 2009
- Licence MIT - Licence MIT
- Dernière version stable 1.3.15 (version 2 en alpha) - Dernière version stable 1.3.15 (version 2 en alpha)

View File

@ -3,7 +3,7 @@
.cadoles-small[ .cadoles-small[
- Les contrôleurs permettent de gérer la logique métier dans votre application Angular. - Les contrôleurs permettent de gérer la logique métier dans votre application Angular.
- La définition du périmètre d'action d'un contrôleur est lié à un élément du DOM et se fait via l'utilisation de la directive `ng-controller` - Le périmètre d'action d'un contrôleur est lié à un élément du DOM et sa définition s'effectue via l'utilisation de la directive `ng-controller`
] ]

View File

@ -0,0 +1,35 @@
# .cadoles-slide-title[Les directives de base (1/)]
**Itération avec ng-repeat: sur un tableau**
```html
<html>
<body ng-app="myApp">
<div ng-controller="MainCtrl">
<ul>
<li ng-repeat="i in items">
<!--
Des variables spéciales permettent d'accéder aux informations
de contexte de l'itération courante: $index, $first, $middle, $last, $even, $odd
-->
<span>{{ $index }}</span>
<!-- On peut accéder directement au propriétés de i à l'intérieur de la boucle -->
<span>{{ i.label }}</span>
</li>
</ul>
</div>
<script src="angular.js"></script>
<script>
angular.module('myApp', [])
.controller('MainCtrl', ['$scope', function($scope) {
$scope.items = [
{ label: 'Item 1' },
{ label: 'Item 2' },
{ label: 'Item 3' },
];
}]);
</script>
</body>
</html>
```

View File

@ -0,0 +1,29 @@
# .cadoles-slide-title[Les directives de base (2/)]
**Itération avec ng-repeat: sur un objet**
```html
<html>
<body ng-app="myApp">
<div ng-controller="MainCtrl">
<ul>
<li ng-repeat="(key, val) in myObj">
<span>Clé: {{ key }}</span><span>Valeur: {{ value }}</span>
</li>
</ul>
</div>
<script src="angular.js"></script>
<script>
angular.module('myApp', [])
.controller('MainCtrl', ['$scope', function($scope) {
$scope.myObj = [
'prop1': 'Foo',
'prop2': 'Bar'
'prop3': 'Baz'
];
}]);
</script>
</body>
</html>
```

View File

@ -0,0 +1,29 @@
# .cadoles-slide-title[Les directives de base (3/)]
**Itération avec ng-repeat: sur un objet**
```html
<html>
<body ng-app="myApp">
<div ng-controller="MainCtrl">
<ul>
<li ng-repeat="(key, val) in myObj">
<span>Clé: {{ key }}</span><span>Valeur: {{ value }}</span>
</li>
</ul>
</div>
<script src="angular.js"></script>
<script>
angular.module('myApp', [])
.controller('MainCtrl', ['$scope', function($scope) {
$scope.myObj = [
'prop1': 'Foo',
'prop2': 'Bar'
'prop3': 'Baz'
];
}]);
</script>
</body>
</html>
```

View File

@ -0,0 +1,22 @@
# .cadoles-slide-title[Les directives de base (4/)]
**Conditions dans les templates: `ng-show`, `ng-hide`, `ng-switch`**
```html
<html>
<body ng-app="myApp">
<div ng-controller="MainCtrl" ng-init="myTest = true; myVal = 'foo'">
<span ng-hide="myTest === true">Caché !</span>
<span ng-show="myTest === true">Affiché !</span>
<div ng-switch="myTest === true">
<span ng-switch-when="foo">Affiché !</span>
<span ng-switch-when="bar">Caché !</span>
<span ng-switch-default="baz">Caché !</span>
</div>
</div>
<script src="angular.js"></script>
</body>
</html>
```

View File

@ -0,0 +1,23 @@
# .cadoles-slide-title[Les directives de base (5/)]
**Modification dynamique du style: `ng-class`**
```html
<html>
<body ng-app="myApp">
<style>
.red { color: red; }
.blue { color: blue; }
.xxl { font-size: 50px; font-weight: bold; }
</style>
<div ng-controller="MainCtrl" ng-init="iLoveBlue=true; iLoveRed=false; myClasses=['red', 'xxl']">
<span ng-class="myClasses">Rouge et large</span>
<span ng-class="{'red': iLoveRed, 'blue': iLoveBlue}">Bleu</span>
</div>
<script src="angular.js"></script>
</body>
</html>
```

View File

@ -0,0 +1,26 @@
# .cadoles-slide-title[Les directives de base (6/)]
**Inclusion de template avec la directive `ng-include`**
```html
<!-- Fichier index.html -->
<html>
<body ng-app>
<ng-include="'template1.html'"></ng-include>
<script src="angular.js"></script>
</body>
</html>
<!-- Fichier template1.html -->
<div>
<div ng-controller="MyCtrl">
<!-- ... -->
</div>
</div>
```
- Les templates sont chargés à la volée, en AJAX
- Il est possible de les précompiler et de les inclures sous leur forme Javascript lors de la mise en production

View File

@ -0,0 +1,16 @@
/*
* Énoncé:
* Implémenter les conditions dans la directive "ng-class" afin d'afficher un assemblage de cellules.
*
* Le rectangle résultant doit présenter une alternance de couleur rouge & bleu sur ses colonnes, et
* avoir un côté horizontale de longueur "edge"
*/
var Exo = angular.module('Exo', []);
Exo.controller('MainCtrl', ['$scope', function($scope) {
$scope.range = new Array(100);
$scope.edge = 10;
}]);

View File

@ -0,0 +1,28 @@
<html>
<head>
<meta charset="utf8">
<title>Exercice: conditions</title>
</head>
<!-- Déclaration de l'application -->
<body ng-app="Exo">
<style>
.pixel { display: inline-block; width: 50px; height: 50px; background: #ccc; float: left; text-align: center; line-height: 50px;}
.pixel.last { clear: both; }
.red { background: rgba(255, 0, 0, 0.5); }
.blue { background: rgba(0, 0, 255, 0.5); }
</style>
<div ng-controller="MainCtrl">
<div class="pixel"
ng-class="{ 'red': $odd, 'blue': $even, 'last': ($index)%edge === 0 }"
ng-repeat="i in range track by $index">
{{$index}}
</div>
</div>
<!-- Import de du framework Angular -->
<script src="../../node_modules/angular/angular.js"></script>
<script src="app.js"></script>
</body>
</html>

View File

@ -0,0 +1,16 @@
/*
* Énoncé:
* Implémenter les conditions dans la directive "ng-class" afin d'afficher un assemblage de cellules.
*
* Le rectangle résultant doit présenter une alternance de couleur rouge & bleu sur ses colonnes, et
* avoir un côté horizontale de longueur "edge"
*/
var Exo = angular.module('Exo', []);
Exo.controller('MainCtrl', ['$scope', function($scope) {
$scope.range = new Array(100);
$scope.edge = 10;
}]);

View File

@ -0,0 +1,28 @@
<html>
<head>
<meta charset="utf8">
<title>Exercice: conditions</title>
</head>
<!-- Déclaration de l'application -->
<body ng-app="Exo">
<style>
.pixel { display: inline-block; width: 50px; height: 50px; background: #ccc; float: left; text-align: center; line-height: 50px;}
.pixel.last { clear: both; }
.red { background: rgba(255, 0, 0, 0.5); }
.blue { background: rgba(0, 0, 255, 0.5); }
</style>
<div ng-controller="MainCtrl">
<div class="pixel"
ng-class=""
ng-repeat="i in range track by $index">
{{$index}}
</div>
</div>
<!-- Import de du framework Angular -->
<script src="../node_modules/angular/angular.js"></script>
<script src="app.js"></script>
</body>
</html>

View File

@ -0,0 +1,47 @@
/*
* Énoncé:
* Via la directive ng-repeat, afficher dans la page sous la forme d'un tableau, la liste des licences
* disponibles sur Github lors de la création d'un nouveau dépôt.
*
* Le tableau comprendra 2 colonnes: le nom de la licence et une colonne avec un bouton "Afficher la description".
* Lors d'un clic sur ce bouton, l'application devra afficher la description de la licence en utilisant la méthode
* showLicenseDesc(licenceURL) déjà implémentée dans le contrôleur.
*
* Aide:
* Voir l'élément <a /> pour l'affichage du lien et la directive ng-href sur la
* documentation Angular https://code.angularjs.org/1.3.15/docs/api/ng/directive/ngHref
*
* Liens:
* - API Github https://developer.github.com/v3/licenses
*/
var Exo = angular.module('Exo', []);
Exo.controller('MainCtrl', ['$scope', '$http', '$window', function($scope, $http, $window) {
$scope.licences = [];
$http({
method: 'GET',
url: 'https://api.github.com/licenses',
headers: { Accept: 'application/vnd.github.drax-preview+json' }
})
.then(function(res) {
$scope.licences = res.data;
})
;
$scope.showLicenseDesc = function(licenceUrl) {
$http({
method: 'GET',
url: licenceUrl,
headers: { Accept: 'application/vnd.github.drax-preview+json' }
})
.then(function(res) {
$window.alert(res.data.description);
})
.catch(console.error.bind(console))
;
};
}]);

View File

@ -0,0 +1,32 @@
<html>
<head>
<meta charset="utf8">
<title>Exercice: itération</title>
</head>
<!-- Déclaration de l'application -->
<body ng-app="Exo">
<div ng-controller="MainCtrl">
<h1>Github Licenses</h1>
<table>
<thead>
<tr>
<th>Name</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="l in licences">
<td>{{l.name}}</td>
<td><button ng-click="showLicenseDesc(l.url)">Show description</button></td>
</tr>
</tbody>
</table>
</div>
<!-- Import de du framework Angular -->
<script src="../../node_modules/angular/angular.js"></script>
<script src="app.js"></script>
</body>
</html>

View File

@ -0,0 +1,47 @@
/*
* Énoncé:
* Via la directive ng-repeat, afficher dans la page sous la forme d'un tableau, la liste des licences
* disponibles sur Github lors de la création d'un nouveau dépôt.
*
* Le tableau comprendra 2 colonnes: le nom de la licence et une colonne avec un bouton "Afficher la description".
* Lors d'un clic sur ce bouton, l'application devra afficher la description de la licence en utilisant la méthode
* showLicenseDesc(licenceURL) déjà implémentée dans le contrôleur.
*
* Aide:
* Voir l'élément <a /> pour l'affichage du lien et la directive ng-href sur la
* documentation Angular https://code.angularjs.org/1.3.15/docs/api/ng/directive/ngHref
*
* Liens:
* - API Github https://developer.github.com/v3/licenses
*/
var Exo = angular.module('Exo', []);
Exo.controller('MainCtrl', ['$scope', '$http', '$window', function($scope, $http, $window) {
$scope.licences = [];
$http({
method: 'GET',
url: 'https://api.github.com/licenses',
headers: { Accept: 'application/vnd.github.drax-preview+json' }
})
.then(function(res) {
$scope.licences = res.data;
})
;
$scope.showLicenseDesc = function(licenceUrl) {
$http({
method: 'GET',
url: licenceUrl,
headers: { Accept: 'application/vnd.github.drax-preview+json' }
})
.then(function(res) {
$window.alert(res.data.description);
})
.catch(console.error.bind(console))
;
};
}]);

View File

@ -0,0 +1,29 @@
<html>
<head>
<meta charset="utf8">
<title>Exercice: itération</title>
</head>
<!-- Déclaration de l'application -->
<body ng-app="Exo">
<div ng-controller="MainCtrl">
<h1>Github Licenses</h1>
<table>
<thead>
<tr>
<th>Name</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<!-- Compléter ici le template -->
</tbody>
</table>
</div>
<!-- Import de du framework Angular -->
<script src="../node_modules/angular/angular.js"></script>
<script src="app.js"></script>
</body>
</html>

View File

@ -18,8 +18,8 @@ Exo.controller('MainCtrl', ['$scope', function($scope) {
$scope.prenom = null; $scope.prenom = null;
$scope.age = null; $scope.age = null;
$scope.direBonjour = function() { $scope.sayHello = function() {
// alert('...'); alert('Bonjour '+$scope.nom+' '+$scope.prenom+'. Votre âge est '+$scope.age);
}; };
}]); }]);

View File

@ -9,22 +9,22 @@
<div ng-controller="MainCtrl"> <div ng-controller="MainCtrl">
<label>Nom</label> <label>Nom</label>
<input type="text" /> <input type="text" ng-model="nom"/>
<br /> <br />
<label>Prénom</label> <label>Prénom</label>
<input type="text" /> <input type="text" ng-model="prenom"/>
<br /> <br />
<label>Age</label> <label>Age</label>
<input type="number" /> <input type="number" ng-model="age"/>
<br /> <br />
<button>Dire bonjour</button> <button ng-click="sayHello()">Dire bonjour</button>
</div> </div>
<!-- Import de du framework Angular --> <!-- Import de du framework Angular -->
<script src="../node_modules/angular/angular.js"></script> <script src="../../node_modules/angular/angular.js"></script>
<script src="app.js"></script> <script src="app.js"></script>
</body> </body>

View File

@ -18,7 +18,7 @@ Exo.controller('MainCtrl', ['$scope', function($scope) {
$scope.prenom = null; $scope.prenom = null;
$scope.age = null; $scope.age = null;
$scope.direBonjour = function() { $scope.sayHello = function() {
// alert('...'); // alert('...');
}; };

View File

@ -0,0 +1,36 @@
/*
* Énoncé:
* Récupérer les données du formulaire et envoyer celles-ci via un clic sur le bouton "Envoyer".
* Les données devront être transmises sous la forme JSON au serveur NodeJS fourni avec l'exercice
* via la méthode HTTP POST avec le service $http.
*
* Documentation service $http: https://code.angularjs.org/1.3.15/docs/api/ng/service/$http
*
* Partie serveur:
* - Se placer dans le répertoire de l'exercice avec un terminal
* - Lancer "node server.js"
*
*/
var ENDPOINT = 'http://localhost:3000/';
var Exo = angular.module('Exo', []);
Exo.controller('MainCtrl', ['$scope', '$http', function($scope, $http) {
$scope.data = {
nom: '',
prenom: '',
age: 0
};
$scope.sendData = function() {
$http.post(ENDPOINT, $scope.data)
.then(function(res) {
console.log(res);
alert(res.data.message);
})
;
};
}]);

View File

@ -0,0 +1,30 @@
<html>
<head>
<meta charset="utf8">
<title>Exercice: utilisation de service</title>
</head>
<!-- Déclaration de l'application -->
<body ng-app="Exo">
<div ng-controller="MainCtrl">
<label>Nom</label>
<input type="text" ng-model="data.nom" />
<br />
<label>Prénom</label>
<input type="text" ng-model="data.prenom" />
<br />
<label>Age</label>
<input type="number" ng-model="data.age" />
<br />
<button ng-click="sendData()">Envoyer</button>
</div>
<!-- Import de du framework Angular -->
<script src="../../node_modules/angular/angular.js"></script>
<script src="app.js"></script>
</body>
</html>

View File

@ -0,0 +1,32 @@
/*
* Énoncé:
* Implémenter le service "myPrompt" qui pose une question et retourne la réponse entrée par l'utilisateur.
* Le service devra lui même utiliser le service $window, service "alias" de l'objet Window fourni par Angular et sa méthode
* prompt().
*
* Documentation:
* - Service $window: https://code.angularjs.org/1.3.15/docs/api/ng/service/$window
* - window.prompt(): https://developer.mozilla.org/en-US/docs/Web/API/Window/prompt
*
*/
var Exo = angular.module('Exo', []);
Exo.controller('MainCtrl', ['$scope', 'myPrompt', function($scope, myPrompt) {
$scope.question = 'Quel est votre age ?';
$scope.response = '--';
$scope.poserQuestion = function() {
$scope.response = myPrompt.ask($scope.question);
};
}]);
Exo.service('myPrompt', ['$window', function($window) {
this.ask = function(question) {
return $window.prompt(question);
};
}]);

View File

@ -0,0 +1,21 @@
<html>
<head>
<meta charset="utf8">
<title>Exercice: création de service</title>
</head>
<!-- Déclaration de l'application -->
<body ng-app="Exo">
<div ng-controller="MainCtrl">
<label>Question</label>
<input type="text" ng-model="question" />
<button ng-click="poserQuestion()">Poser la question</button>
<br /><br />
<b>Votre réponse:</b> <span>{{ response }}</span>
</div>
<!-- Import de du framework Angular -->
<script src="../../node_modules/angular/angular.js"></script>
<script src="app.js"></script>
</body>
</html>

View File

@ -8,7 +8,6 @@
* - Service $window: https://code.angularjs.org/1.3.15/docs/api/ng/service/$window * - Service $window: https://code.angularjs.org/1.3.15/docs/api/ng/service/$window
* - window.prompt(): https://developer.mozilla.org/en-US/docs/Web/API/Window/prompt * - window.prompt(): https://developer.mozilla.org/en-US/docs/Web/API/Window/prompt
* *
*
*/ */
var Exo = angular.module('Exo', []); var Exo = angular.module('Exo', []);
@ -18,6 +17,8 @@ Exo.controller('MainCtrl', ['$scope', /*'myPrompt',*/ function($scope /*,myPromp
$scope.question = 'Quel est votre age ?'; $scope.question = 'Quel est votre age ?';
$scope.response = '--'; $scope.response = '--';
// scope.response = myPrompt.ask($scope.question); $scope.poserQuestion = function() {
// $scope.response = myPrompt.ask($scope.question);
};
}]); }]);

View File

@ -9,7 +9,8 @@
<div ng-controller="MainCtrl"> <div ng-controller="MainCtrl">
<label>Question</label> <label>Question</label>
<input type="text" ng-model="question" /> <input type="text" ng-model="question" />
<br /> <button ng-click="poserQuestion()">Poser la question</button>
<br /><br />
<b>Votre réponse:</b> <span>{{ response }}</span> <b>Votre réponse:</b> <span>{{ response }}</span>
</div> </div>

View File

@ -0,0 +1,7 @@
# .cadoles-slide-title[Fin]
.cadoles-center[
# Fin de la première partie
]

View File

@ -22,6 +22,13 @@
'scope-4', 'scope-4',
'services-1', 'services-1',
'services-2', 'services-2',
'directives-1',
'directives-2',
'directives-3',
'directives-4',
'directives-5',
'directives-6',
'fin',
'licence' 'licence'
]; ];
</script> </script>

View File

@ -7,10 +7,12 @@
- Modules - Modules
- Contrôleurs et scopes - Contrôleurs et scopes
- Services et injection de dépendances - Services et injection de dépendances
- Templates et expressions - Les directives de base
- Routage avec le module `ngRoute`
- Les filtres - Les filtres
- Directives - Création de directives
- Animations - Animations
- Organisation du projet
- Tests unitaires - Tests unitaires
- Tests fonctionnels - Tests fonctionnels
@ -25,16 +27,20 @@
- Modules - Modules
- Contrôleurs et scopes - Contrôleurs et scopes
- Les contrôleurs - Les contrôleurs
- L'objet `$scope` - L'objet `$scope` (exercice scope-1)
- Services et injection de dépendances - Services et injection de dépendances
- Utilisation de services - Utilisation de services (exercice services-1)
- Création de services personalisés - Création de services personalisés (exercice services-2)
- Templates et expressions - Les directives de base
- Itération sur des éléments avec ng-repeat - Itération sur des éléments avec ng-repeat (exercice iteration)
- Réaction aux changements des modèles avec `ng-show`, `ng-hide`, `ng-switch`, `ng-class` - Réaction aux changements des modèles avec `ng-show`, `ng-hide`, `ng-switch`, `ng-class`, 'ng-if' (exercice conditions)
- Inclusion de templates - Inclusion de templates (exercice include)
- Les filtres - Routage avec le module `ngRoute`
- Directives - Le routage côté client
- Utilisation du module (exercice routage)
- Les filtres (exercice filtres)
- Création de directives
- Animations - Animations
- Organisation du projet
- Tests unitaires - Tests unitaires
- Tests fonctionnels - Tests fonctionnels

View File

@ -14,8 +14,10 @@
<body ng-app="myApp"> <body ng-app="myApp">
<div ng-controller="MyAppCtrl"> <div ng-controller="MyAppCtrl">
<!-- Liaison de donnée avec la propriété "myValue" du $scope -->
<span>{{ myValue }}</span>
<!-- La directive "ng-click" associe la méthode exposée sur le $scope à l'évènement "onclick" --> <!-- La directive "ng-click" associe la méthode exposée sur le $scope à l'évènement "onclick" -->
<button ng-click="buttonClickHandler()"></button> <button ng-click="myButtonClickHandler()"></button>
</div> </div>
<script src="angular.js"></script> <script src="angular.js"></script>
@ -24,9 +26,9 @@
myApp.controller('MyAppCtrl', ['$scope', function($scope) { myApp.controller('MyAppCtrl', ['$scope', function($scope) {
$scope.buttonClickHandler = function() { $scope.myValue = 'Foo !'
alert('Click !');
}; $scope.myButtonClickHandler = function() { alert('Click !'); };
}]); }]);
</script> </script>

View File

@ -18,11 +18,11 @@
var myApp = angular.module('myApp', []); var myApp = angular.module('myApp', []);
myApp.controller('ParentCtrl', ['$scope', function($scope) { myApp.controller('ParentCtrl', ['$scope', function($scope) {
* $scope.parentProp = "Foo"; $scope.parentProp = "Foo";
}]); }]);
myApp.controller('ChildCtrl', ['$scope', function($scope) { myApp.controller('ChildCtrl', ['$scope', function($scope) {
* $scope.childProp = "Bar"; $scope.childProp = "Bar";
}]); }]);
</script> </script>

View File

@ -16,15 +16,15 @@
myApp.controller('ParentCtrl', ['$scope', function($scope) { myApp.controller('ParentCtrl', ['$scope', function($scope) {
* $scope.$on('child-event', function(evt) { console.log('Emitted event: ', evt); }); $scope.$on('child-event', function(evt) { console.log('Emitted event: ', evt); });
* $scope.$broadcast('parent-event', {data: 'Parent event !'}); $scope.$broadcast('parent-event', {data: 'Parent event !'});
}]); }]);
myApp.controller('ChildCtrl', ['$scope', function($scope) { myApp.controller('ChildCtrl', ['$scope', function($scope) {
* $scope.$emit('child-event', {data: 'Child event !'}); $scope.$emit('child-event', {data: 'Child event !'});
* $scope.$on('parent-event', function(evt) { console.log('Broadcasted event: ', evt); }); $scope.$on('parent-event', function(evt) { console.log('Broadcasted event: ', evt); });
}]); }]);

View File

@ -82,7 +82,7 @@ ul > li {
.cadoles-xlarge { font-size: 1.5em; } .cadoles-xlarge { font-size: 1.5em; }
.cadoles-large { font-size: 1.2em; } .cadoles-large { font-size: 1.2em; }
.cadoles-small { font-size: 0.8em; } .cadoles-small { font-size: 0.8em; }
.cadoles-xs { font-size: 0.7em; } .cadoles-xsmall { font-size: 0.7em; }
.cadoles-center { text-align: center; } .cadoles-center { text-align: center; }
.cadoles-left-column { .cadoles-left-column {