Académique Documents
Professionnel Documents
Culture Documents
Angular
Prsentation des 3 Frameworks JavaScript pour le binding
Jrme Romagny
20/07/2014
I.
KNOCKOUT .................................................................................................................................................... 7
Installation...................................................................................................................................................... 7
1. Observables ........................................................................................................................................... 7
a.
b.
c.
d.
2.
Observable ......................................................................................................................................................... 7
ObservableArray ................................................................................................................................................ 8
Computed........................................................................................................................................................... 9
Binding html ....................................................................................................................................................... 9
3.
4.
5.
6.
7.
8.
9.
10.
a.
b.
II.
11.
Plus .............................................................................................................................................. 20
DURANDAL .................................................................................................................................................. 21
Convention :............................................................................................................................................................... 21
Page de dpart index ................................................................................................................................................. 22
1.
2.
3.
4.
Main..................................................................................................................................................... 24
Shell ..................................................................................................................................................... 25
Pages ................................................................................................................................................... 26
Navigation ........................................................................................................................................... 27
Passage de paramtres .............................................................................................................................................. 27
5.
Logger .................................................................................................................................................. 28
III. ANGULAR .................................................................................................................................................... 29
Installation.................................................................................................................................................... 29
Organisation du code ................................................................................................................................... 30
1. Module ................................................................................................................................................. 31
a.
b.
2.
Contrleurs .......................................................................................................................................... 38
a.
b.
Contrleur avec $scope .................................................................................................................................... 39
Contrleur As ....................................................................................................................................................... 40
3.
4.
5.
b.
c.
d.
e.
f.
g.
h.
i.
6.
Formulaire ........................................................................................................................................... 45
Validation de formulaire ............................................................................................................................................ 45
Marquer un champ invalide ....................................................................................................................................... 46
7.
Services ................................................................................................................................................ 48
$http .......................................................................................................................................................................... 48
8. Animation ............................................................................................................................................ 50
IV- BREEZE ........................................................................................................................................................... 51
1.
2.
Rappels JavaScript
1..
var viewModel = {
prop: "my property",
funcA: function () { }
}
return viewModel;
2..
var ViewModel = function () {
var self = this;
// private
var privateVariable = "private !";
var privateFunction = function () {
return "private !";
};
// public
this.publicVariable = "public !";
this.publicFunction = function () {
//var result1 = privateVariable;
//var result2 = privateFunction();
//
var result = self.publicVariable;
alert(result);
};
};
var viewModel = new ViewModel();
3..
var ViewModel = function () {
// private
var propA = "my property";
function funcA() {
};
var funcA2 = function () {
};
var funcB = function (x,y) {
return x * y;
};
// public
return {
propA: propA,
funcA: funcA,
funcA2: funcA2,
funcB:funcB
}
};
// instance
var viewModel = new ViewModel();
Astuces
Avoir lIntelliSense avec Visual Studio
Fichier distant
/// <reference path="//cdnjs.cloudflare.com/ajax/libs/knockout/3.1.0/knockout-min.js" />
Vider le cache
IE
Ici
Chrome
Ici
http://sidewaffle.com/
Knockout
Durandal
Angular
I.
Knockout
Installation
Tlchargement ou Package NuGet depuis Visual Studio
CDN
http://www.asp.net/ajaxlibrary/cdn.ashx
http://cdnjs.com/libraries/knockout
1. Observables
Les observables sont des fonctions JavaScript.
Two-way binding
Les observables ne sont pas utiles dans les cas :
-
de proprits readonly
binding one time
de charger seulement une liste dobjets
a. Observable
Utile pour les proprits
// viewModel
var vm = {
name: ko.observable('Marie')
}
vm.name('Deborah'); // write
var name = vm.name(); //read
// apply bindinds
ko.applyBindings(vm);
b. ObservableArray
Utile pour les collections (exemple : people)
Notification ajout/suppression dlments
pas de suivi des changements de valeurs
var Person = function (name) {
this.name = ko.observable(name);
};
// viewModel
var vm = {
people: ko.observableArray([])
}
vm.people.push(new Person('Marie')); // add
vm.people.push(new Person('patrick'));
var name = vm.people()[0].name(); //read
vm.people()[0].name('Deborah'); // write
vm.people.remove(vm.people()[0]); // remove one
vm.people.removeAll(); // remove all
// apply bindinds
ko.applyBindings(vm);
<ul data-bind="foreach:people">
<li data-bind="text:name"></li>
</ul>
observableArray methods
indexOff(value)
slice(2,4)
push(value)
unshift(value)
pop()
remove(item)
removeAll()
shift()
reverse()
sort()
Index
Retourne items entre lindex de dbut/fin
Ajoute un lment la fin
Ajout de llment au dbut
Supprime le dernier lment
Supprime llment
Supprime tous les lments
Supprime le premier lment
Ordre invers
Tri
c.
Computed
avant se nommait dependentObservable
Expression qui value une autre expression
this pointer
vm = (function () {
// private
var firstName = ko.observable('Marie'),
lastName = ko.observable('Bellin')
// public
return {
firstName: firstName,
lastName: lastName
}
})(); // immediate instanciation
vm.fullName = ko.computed(function () {
return this.firstName() + ' ' + this.lastName();
}, vm)
ko.applyBindings(vm);
d. Binding html
On est oblig dindiquer les parenthses pour les observables que dans le cas ou cest un
observableArray avec une proprit derrire.
<ul data-bind="foreach:people" >
<!-- -->
</ul>
<span data-bind="text: people().length"></span>
<span data-bind="text: selectedPerson.FirstName"></span>
Note : bien sr on peut ajouter les parenthses si on le dsire, ce nest quune facilit pour le
html
2. Built-in bindings
Texte et apparence
visible
text
html
css
style
attr
Rend visible/invisible
Valeur de texte (en lecture seule) .Note ne
peut pas tre appliqu des contrles
permettant la saisie (tels que input de type
text)
Met en forme du contenu html
Css class
Style css
Attribut (exemple src pour indiquer la source
dune image)
http://knockoutjs.com/documentation/visible-binding.html
Forms
click
event
submit
enable
disable
value
checked
options
selectedOptions
uniqueName
Control flow
if
ifnot
foreach
with
condition
boucle
Pour llment spcifi
http://knockoutjs.com/documentation/foreach-binding.html
10
a. Templates
http://knockoutjs.com/documentation/template-binding.html
Note : il est conseill dutiliser un template par ligne plutt quun template pour lensemble
dune liste.
Avec jQuery Templates
<ul data-bind="template: { name: 'itemTmpl',foreach: people}"></ul>
<script id="itemTmpl" type="text/html">
<li>${name}</li>
</script>
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="Scripts/jquery.tmpl.js"></script>
<script src="//ajax.aspnetcdn.com/ajax/knockout/knockout-3.1.0.js"></script>
Knockout Template
<ul data-bind="template: { name: 'itemTmpl',foreach: people}"></ul>
<script id="itemTmpl" type="text/html">
<li data-bind="text: name"></li>
</script>
Sans script
<div data-bind="template: { name: 'itemTmpl',foreach: people}"></div>
<div id="itemTmpl">
<span data-bind="text: name"></span><br/>
</div>
Avec commentaires
<ul>
<!-- ko foreach:people -->
<li data-bind="text: name"></li>
<!-- /ko -->
</ul>
Enfin
<ul data-bind="foreach: people">
<li data-bind="text: name"></li>
</ul>
11
Choix Template
Exemple
<body>
<table>
<thead>
<tr>
<td>Name</td>
<td></td>
</tr>
</thead>
<tbody data-bind="template: { name: templateChoice,foreach: people}" />
</table>
<script id="itemTmpl" type="text/html">
<tr><td><span data-bind="text: name"></span><td><button
class="edit">Edit</button></td></tr>
</script>
<script id="editTmpl" type="text/html">
<tr>
<td><input type="text" data-bind="value: name" /></td>
<td><button data-bind="click:$root.save">Save</button></td>
</tr>
</script>
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="//ajax.aspnetcdn.com/ajax/knockout/knockout-3.1.0.js"></script>
<script>
var Person = function (name) {
this.name = ko.observable(name);
};
// viewModel
var vm = {
people: ko.observableArray([]),
selectedPerson: ko.observable(),
showDetails:ko.observable(false),
templateChoice: function () {
return vm.showDetails() ? "editTmpl" : "itemTmpl";
},
save: function () {
// save ..
vm.showDetails(false);
}
}
$('table').on('click', '.edit', function () {
vm.showDetails(true);
});
vm.people.push(new Person('Marie')); // add
vm.people.push(new Person('patrick'));
// apply bindinds
ko.applyBindings(vm);
</script>
</body>
12
b. Binding Context
$data
$parent
$parents
$root
with
Item courant
item parent
Tous les parents
Element au top(ViewModel)
Dfinit un contexte
13
b. Module Pattern
$(function () {
// namespace
var my = my || {};
// The ViewModel
my.vm = (function () {
// private
var myProp = ko.observable();
var myArray = ko.observableArray([]);
var myFunc = function () {
};
// public
return {
myProp: myProp,
myArray: myArray,
myFunc: myFunc
}
})(); // immediate instanciation
// .
my.vm.myFunc();
ko.applyBindings(my.vm);
});
14
4. Custom bindings
documentation custom bindings
bindingHandler
ko.bindingHandlers.fadeVisible = {
init: function (element, valueAccessor) {
$(element).toggle(valueAccessor());
},
update: function (element, valueAccessor, allBindingsAccessor) {
var shouldDisplay = valueAccessor();
shouldDisplay ? $(element).fadeIn(2000) : $(element).fadeOut(2000);
}
};
15
ViewModel
var Person = function (name) {
this.name = ko.observable(name);
};
// viewModel
var vm = {
people: ko.observableArray([]),
selectedPerson: ko.observable(),
canShowDetails: ko.observable(false),
closeDetails: function () {
vm.canShowDetails(false);
}
}
$('table').on('click', '.person', function () {
var person = ko.dataFor(this);
vm.selectedPerson(person);
vm.canShowDetails(true);
});
vm.people.push(new Person('Marie')); // add
vm.people.push(new Person('patrick'));
// apply bindinds
ko.applyBindings(vm);
Autre exemple : Pour valider une saisie lorsque lutilisateur presse enter
5. Ko utilities
Array utilities
16
6. Data Features
Ko.toJS() renvoie un objet javascript sans binding
Ko.toJSON() renvoie une chaine au format Json
Dans le dataService utiliser ko.toJSON()
var addPerson = function (person) {
return $.ajax({
url: urlBase,
type: 'POST',
dataType: 'json',
contentType: 'application/json; charset=utf-8',
data: ko.toJSON(person),
});
};
7. Subscribe
search.subscribe(function (search) {
if (search)
searchPeople(search);
else
getPeople();
//
});
8. Extenders
documentation extenders
9. Change tracker
Jutilise ici la librairie de John Papa pour traquer les changements .Lintrt est de dtecter lors
de ldition dun formulaire par exemple si les informations ont t modifies.
function changeTracker(objectToTrack, hashFunction) {
hashFunction = hashFunction || ko.toJSON;
var lastCleanState = ko.observable(hashFunction(objectToTrack));
var result = {
somethingHasChanged: ko.computed(function () {
return hashFunction(objectToTrack) != lastCleanState()
}),
markCurrentStateAsClean: function () {
lastCleanState(hashFunction(objectToTrack));
}
};
return function () { return result }
};
17
10. Ko Validation
a. Avec ko.extenders
ko.extenders.required = function (target, overrideMessage) {
target.hasError = ko.observable();
target.validationMessage = ko.observable();
// check if value is empty
function validate(newValue) {
target.hasError(newValue ? false : true);
target.validationMessage(newValue ? "" : overrideMessage || "This field is
required");
}
validate(target());
target.subscribe(validate);
return target;
};
18
Configuration
ko.validation.configure({
registerExtenders: true,
messagesOnModified: true,
insertMessages: true,
parseInputAttributes: true,
messageTemplate: null,
decorateElement: true
});
11. Plus
Boilerplate une solution complte SPA
Sammy pour la navigation/historique SPA
Qunit pour les tests
http://www.responsinator.com/ pour tester son site dans toutes tailles/orientations dcrans
Breeze ou amplify offrent des facilits pour le dveloppement de SPA
20
II.
Durandal
Durandal utilise :
jQuery (DOM)
Require (SoC, enregistrement et chargement de modules)
Knockout (Binding)
21
22
23
1. Main
useConvention > correspondance noms views et viewmodels
setRoot dfinit le shell (+ la transition possible)
Require.js :
Les chemins (paths) reprsentent des raccourcis que lon pourra utiliser pour localiser
les fichiers + urlBase
define pour dfinir un module (nom, modules requis)
require pour indiquer les modules requis/utiliss par le module/fonction
requirejs pour configurer les options
// dfinit des chemins rutilisables par "raccourcis"
requirejs.config({
paths: {
'text': '../Scripts/text',
'durandal': '../Scripts/durandal',
'plugins': '../Scripts/durandal/plugins',
'transitions': '../Scripts/durandal/transitions',
'services': '../app/services',
}
});
define('jquery', function () { return jQuery; });
define('knockout', ko);
define(['durandal/system', 'durandal/app', 'durandal/viewLocator'], function (system,
app, viewLocator) {
//>>excludeStart("build", true)
system.debug(true);
//>>excludeEnd("build");
app.title = 'Durandal demo';
app.configurePlugins({
router: true,
dialog: true,
widget: true,
observable: true
});
app.start().then(function () {
viewLocator.useConvention();
app.setRoot('viewmodels/shell', 'entrance');
});
});
24
2. Shell
On dfinit les routes, ainsi que les fonctions accessibles pour toutes les pages.
define(['plugins/router', 'durandal/app'], function (router, app) {
return {
router: router,
search: function () {
app.showMessage('Search not yet implemented...');
},
activate: function () {
router.map([
{ route: ['home', ''], title: 'Home page', moduleId:
'viewmodels/home', nav: true },
{ route: 'people', title: "People page", moduleId:
'viewmodels/people', nav: true },
{ route: 'person/:id', title: 'person', moduleId:
'viewmodels/person', nav: false }
]).buildNavigationModel();
return router.activate();
}
};
});
<div>
<!-- barre de navigation -->
<nav class="navbar navbar-default navbar-fixed-top" role="navigation">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse">
<span class="sr-only">Toggle Navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">
<i class="fa fa-home"></i>
<span>Durandal</span>
</a>
</div>
<div class="collapse navbar-collapse">
<ul class="nav navbar-nav" data-bind="foreach: router.navigationModel">
<li data-bind="css: { active: isActive }">
<a data-bind="attr: { href: hash }, text: title"></a>
</li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li class="loader" data-bind="css: { active: router.isNavigating }">
<i class="fa fa-spinner fa-spin fa-2x"></i>
</li>
</ul>
<form class="navbar-form navbar-right" role="search" databind="submit:search">
<div class="form-group">
<input type="text" class="form-control" placeholder="Search">
</div>
</form>
</div>
</nav>
<!-- navigation -->
<div class="page-host" data-bind="router: { transition:'entrance' }"></div>
</div>
25
3. Pages
Couple view /viewmodel
define(function () {
return {
activate: function () {
}
};
});
26
4. Navigation
Routes (dfinies dans shell.js ou un fichier de config part) :
-
Exemples
router.map([
{ route: ['home', ''], title: 'Home page', moduleId:
'viewmodels/home', nav: true },
{ route: 'people', title: "People page", moduleId:
'viewmodels/people', nav: true },
{ route: 'person/:id', title: 'person', moduleId:
'viewmodels/person', nav: false }
]).buildNavigationModel();
mapUnknownRoutes
Passage de paramtres
La route dfinie
{ route: 'person/:id', title: 'person', moduleId: 'viewmodels/person', nav: false }
27
5. Logger
Utilisant Toastr
define(['durandal/system'],
function (system) {
var logger = {
log: log,
logError: logError
};
return logger;
function log(message, data, source, showToast) {
logIt(message, data, source, showToast, 'info');
}
function logError(message, data, source, showToast) {
logIt(message, data, source, showToast, 'error');
}
function logIt(message, data, source, showToast, toastType) {
source = source ? '[' + source + '] ' : '';
if (data) {
system.log(source, message, data);
} else {
system.log(source, message);
}
if (showToast) {
if (toastType === 'error') {
toastr.error(message);
} else {
toastr.info(message);
}
}
}
});
28
III.
Angular
Modle
Services personnels
Services
Enregistrement du
module, dpendances et
configuration des routes
du module
Contrleur
Vue
Contrleur et
enregistrement de celui-ci
pour un module
Page dindex du site avec ngview (ou ui-view pour uirouter) conteneur pour les vues
Index.html
Une application a
- 1 ou plusieurs modules
o Chaque module a x contrleurs
Chaque vue (template HTML) est relie un contrleur et en affiche les
donnes (data binding).
La page index affiche les vues dans un conteneur.
29
Organisation du code
Par type
Convient aux applications avec un seul module
Code organis par
contrleurs, vues, directives,
etc.
On peut mme mlanger les 2 organisations (exemple une feature people qui est divise en
dossiers controllers , views , services ).
Conventions de nommage
PascalCase pour les noms de contrleurs avec un suffixe Ctrl ou Controller
camelCase pour les directives, services, etc.
30
1. Module
Enregistrement de module avec la mthode module de lobjet angular . On donne un nom
au module et on ajoute les dpendances.
(function () {
Bonne pratique .. IIFE (Immediately-invoked
'use strict';
function expression) + use strict
angular.module('app', []);
})();
Ex de module app
(function () {
'use strict';
// 1 enregistrement du module
var app = angular.module('app', ['ngRoute']);
Enregistrement du module
(nomm app ) + dpendances
avec la mthode module de lobjet
angular
Configuration des routes du
module. On peut ou non indiquer le
contrleur, templateUrl pour le
chemin vers le template, la vue
// 2 Routes
app.config(function ($routeProvider) {
$routeProvider
.otherwise({ redirectTo: "/" })
.when("/", { templateUrl: 'app/welcomeView.html' })
.when("/people/", { templateUrl: 'app/people/peopleListView.html',
controller: 'PeopleController' })
.when("/person/:id", { templateUrl: 'app/people/personDetailView.html',
controller: 'PersonDetailController' })
.when("/person/edit/:id", { templateUrl: 'app/people/personEditView.html',
controller: 'PersonEditController' })
});
})();
a. Dpendances de module :
b. Routing du module
2 Possibilits : avec ngRoute ou ui-router
1. ngRoute
On a besoin de angular-route.js que lon rfrence dans la page dindex.
<script src="js/angular-route.js"></script>
Redirection vers la
page par dfaut
On ajoute as vm pour
un contrleur AS, sinon
Exemple de route :
on ne met que le nom du
templateUrl : le chemin vers le template de la page
contrleur
controller : le contrleur associ. Facultatif, on peut aussi le dfinir avec la directive
ng-controller dans la page.
$routeProvider.when("/", {
templateUrl: 'app/people/people.html',
controller: 'PeopleController as vm'
})
"/" est la route utilise par dfaut. Cela donnera quelque chose comme
http://localhost:7090/default.html#/ dans la barre dadresse.
Pour une autre page on pourrait indiquer "/prices/" par exemple. Ce qui donnerait
http://localhost:7090/default.html#/prices/ dans la barre dadresse.
Resolve pour excuter une action avant la navigation (documentation)
32
Avec paramtres
<a href="#/person/1">Dtails</a>
<a href="#/person/{{person.Id}}">Dtails</a>
# reprsentant
lurl du site
-
La valeur passe
$location.path("/people/");
Avec paramtre
$location.path("/person/" + $scope.person.Id);
Injection de
$routeParams pour
rcuprer les paramtres
passs
( /person/:id )
33
2. ui-router
Tlcharger ui-router https://github.com/angular-ui/ui-router
Problmes connus avec ui-view et ng-class/ng-show/ng-hide.
Ajouter angular-ui-router.js (ou version minimise) son projet et le rfrencer
<script src="js/angular-ui-router.js"></script>
$stateProvider
.state("home", {
url: "/",
templateUrl: "app/welcomeView.html"
})
.state("peopleList", {
url: "/people",
templateUrl: "app/people/peopleListView.html",
controller: "PeopleController as vm"
})
.state("personDetail", {
url: "/person/:id",
templateUrl: "app/people/personDetailView.html",
controller: "PersonDetailController as vm",
resolve: {
person: ['peopleService', '$stateParams', function
(peopleService, $stateParams) {
var id = $stateParams.id;
return peopleService.getPerson(id).then(function
(response) {
var result = response.data;
return result;
});
}]
}
})
}]
);
}());
Important avec ui-router on utilise ui-view la placve de ng-view pour indiquer le conteneur
recevant les vues dans la page index.html
<div ui-view></div>
34
Avec Paramtre
Dans la Vue
<td><a ui-sref="personDetail({id:person.Id})">{{person.Name}}</a></td>
Contrleur rcepteur
(function () {
'use strict';
angular.module('app').controller('PersonDetailController', ["person",
personDetailController]);
function personDetailController(person) {
var vm = this;
vm.title = "Dtails de la personne";
vm.person = person;
}
})();
35
Nom de ltat
La valeur passe
36
Injecter $state
(function () {
'use strict';
angular.module('app').controller('PersonDetailController', ["$state",
personDetailController]);
function personDetailController($state) {
var vm = this;
vm.title = "Dtails de la personne";
vm.goPeopleList = function () {
$state.go("home");
}
}
})();
Avec paramtre
$state.go("personDetail", { id: 1 });
Nom de ltat
Paramtre pass
37
2. Contrleurs
Ordre cration
(Crer un dossier dans le dossier app avec la catgorie exemple people )
Crer le contrleur (ajout dun template contrleur Sidewaffle possible)
Dpendances ($scope, services), membres et activate (les donnes
charges/configurations lactivation)
Crer le Template html (+style, animation, etc.) et ajouter le binding
Ajouter la route (dans app ou config.route )
Rfrencer le contrleur dans la page dindex
a. Injection de dpendances
(function () {
'use strict';
angular.module('app').controller('PeopleController', ['$state', 'peopleService',
PeopleController]);
function PeopleController($state, peopleService) {
var vm = this;
// etc.
}
})();
Avec $inject
(function () {
'use strict';
angular.module('app').controller('PeopleController',PeopleController);
PeopleController.$inject = ['$state', 'peopleService'];
function PeopleController($state, peopleService) {
var vm = this;
// etc.
}
})();
38
Nom du contrleur et
ajout au module
Dpendances
(function () {
'use strict';
angular.module('app').controller('PeopleController', ['$scope', '$location',
'peopleService', PeopleController]);
// 3 controleur
function PeopleController($scope, $location, peopleService) {
$scope membres
binds par la vue
$scope.people = [];
$scope.getPeople = function () {
peopleService.getPeople().then(function (response) {
$scope.people = response.data;
});
}
$scope.deletePerson = function (id) {
peopleService.deletePerson(id).then(function (response) {
$location.url("/people");
});
}
activate();
function activate() {
$scope.getPeople();
}
}
})();
39
Contrleur As
(function () {
'use strict';
Utilisation
Dans la vue
Contrleur as vm
40
3. La page dindex
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>AngularJS Demo</title>
<!-- Styles -->
<link href="css/default.css" rel="stylesheet" />
<!-- AngularJS -->
<script src="js/angular.js"></script>
<script src="js/angular-route.js"></script>
<!--module-->
<script src="app/app.js"></script>
<!-- services -->
<script src="app/services/peopleService.js"></script>
<!-- contrleurs -->
<script src="app/people/peopleController.js"></script>
<script src="app/people/personDetailController.js"></script>
<script src="app/people/personEditController.js"></script>
Porte dAngularjs : nom du module (vide
</head>
<body ng-app="app">
<header>
<h1>Dmonstration d'AngularJS</h1>
<ul>
<li><a href="#/">Accueil</a></li>
<li><a href="#/people/">Liste des personnes</a></li>
<li><a href="#">A propos</a></li>
<li><a href="#">Contact</a></li>
La directive ng-view (ou ui-view avec ui</ul>
router)permet dindiquer lemplacement
</header>
des vues (templates) dans la page dindex ..
<section>
<div ng-view></div>
</section>
</body>
</html>
On nindique pas de contrleurs ceux-ci tant dfinis dans app.js avec les routing.
A savoir quil est possible dutiliser plusieurs contrleurs par page. Ex
<div ng-controller="PeopleController">
<!-- -->
</div>
<div ng-controller="SessionController">
<!-- -->
</div>
Contrleur as vm
<div ng-controller="shell as vm">
<h1>{{vm.title}}</h1>
</div>
41
4. Vues
Un template :
- Sauvegard au format HTML (*.html)
- Affiche les donnes du contrleur li avec binding.
<div>
<h2>{{title}}</h2>
<table class="table">
<tr>
<td>Nom</td>
<td>{{person.Name}}</td>
</tr>
<tr>
<td>Twitter</td>
<td>{{person.Twitter}}</td>
</tr>
</table>
<div><a href="#/person/edit/{{person.Id}}">Editer</a></div>
</div>
ng-include
(sidebar.html)
ng-include
(topnav.html)
ng-view
42
Filtres
Pour filtrer, trier et formater une expression
Expression|filtername :parameter
Principaux filtres :
currency
date
filter
json
Lowercase,uppercase
number
orderby
limitTo
Il est possible de crer ses propres filtres
{{expression|currency : "USD$"}}
{{expression|date : "short"}}
Person in people|filter :searchTerm
{{expression|json }}
{{expression|uppercase}}
{{expression| number :1}}
Person in people|orderByLastName
Person in people|limitTo :10
ng-bind
Equivalent avec ng-bind
<span ng-bind="person.Name"></span>
ng-repeat
Pour les listes. Exemple ci-dessus, le contrleur a un tableau $scope.people, on fait une boucle
<table>
<tbody ng-repeat="person in people">
<tr>
<td>{{person.Name}}</td>
<td>{{person.Twitter}}</td>
</tr>
</tbody>
</table>
43
d. ng-submit
Pour les formulaires. Dans la balise form permettant de dclencher une mthode par exemple
la validation.
e. ng-include
Permet dinsrer un template dun fichier html ou dfini dans la page.
Template dun fichier html insr
<div ng-include=" '/Templates/people.html' "></div>
id="itemTmpl.html">
-->
id="editTmpl.html">
-->
f. ng-src
Pour image.On peut dfinir une expression pour modifier limage par exemple
<img ng-src="{{person.img}}" />
g. ng-show et ng-hide
Pour afficher/cacher un lment
Exemple affiche seulement si llment nest pas indfni
<div ng-show="selectedPerson"></div>
(Les nombres gal 0, les variables undefined ou null, chaines de caractres vides renvoient
false)
h. Styles avec ng-class
Pour dfinir un style CSS
https://docs.angularjs.org/api/ng/directive/ngClass
i.
44
6. Formulaire
Un formulaire doit avoir un nom, de mme chaque champ (input) doit avoir un nom. Les
champs utilisent ngModel pour binder les proprits (de $scope ou vm selon le contrleur).
Formulaire avec ngSubmit
<form name="personForm" ng-submit="vm.save()">
<input type="submit">Save</input>
</form>
ng-click="vm.save()">Save</input>
Validation de formulaire
Angular offre une validation des saisies pour les formulaires.
novalidate : permet de valider malgr les erreurs
directives disponibles : required, pattern, minlength, maxlength, min,max
Breeze Angular validation : Si on utilise Breeze avec Angular il existe une validation.
ngMessages (rfrencer angular-messages.js et ajouter la dpendance dans le
module) permet de simplifier laffichage des erreurs de validation.
45
On peut utiliser les styles Bootstrap (bootsrap validation states) avec les classes haserror , has-success , etc.
46
on peut galement utiliser debounce (le changement de valeur aprs un certain temps dfini)et
les cumuler (documentation)
Le formulaire nest soumis que sil na pas derreurs de validation
Exemple de formulaire
<form name="personForm" ng-submit="personForm.$dirty && personForm.$valid &&
vm.save()">
La classe CSS (bordure rouge) est
<fieldset>
<legend>Informations de l'utilisateur</legend>
ajoute si le formulaire a t
<div ng-class="{'has-error': personForm.$submitted &&
soumis et comporte des erreurs
personForm.inputName.$invalid }">
<label for="inputName">Name</label>
<input name="inputName" type="text" ng-model="vm.person.Name"
placeholder="Nom de l'utilisateur (requis)" ng-minlength="2" required />
<span ng-show="personForm.$submitted &&
personForm.inputName.$error.required">Nom d'utilisateur requis.</span>
<span ng-show="personForm.$submitted &&
personForm.inputName.$error.minlength">Le nom d'utilisateur doit avoir 2 caractres
minimum.</span>
</div>
<div ng-class="{'has-error': personForm.$submitted &&
personForm.inputTwitter.$invalid }">
<label for="inputTwitter">Twitter</label>
<input name="inputTwitter" type="text" ng-model="vm.person.Twitter"
placeholder="Twitter de l''utilisateur (requis)" ng-pattern="/^@[a-zA-Z0-9]*/"
required />
<span ng-show="personForm.$submitted &&
personForm.inputTwitter.$error.required">Twitter requis.</span>
<span ng-show="personForm.$submitted &&
personForm.inputTwitter.$error.pattern">Twitter invalide.</span>
</div>
<input type="submit" value="Valider" />
<input type="button" ng-click="vm.cancel()" value="Annuler" />
</fieldset>
</form>
CSS
.has-error input{ border-color: red; }
47
7. Services
Api rfrence
$http
$log
$timeout
$interval
UI related services
$window
$browser
$location
$animate
$anchorScroll
angular.module('app').service('peopleService', peopleService);
function peopleService($http) {
var baseUrl = "/api/People/";
var getPeople = function () {
return $http.get(baseUrl);
}
return {
getPeople: getPeople
}
}
})();
$http
Voyons plus en dtail ce service permettant de faire des requtes http vers un serveur.
La documentation
On utilise :
$http.get, $http.head, $http.post, $http.put, $http.delete, $http.jsonp (retournent des promises )
$http.get pour les requtes http get
$http.post pour les requtes http post
Il est possible de finir les headers avec $http
$http({ method: 'GET', url: '/url' }).
success(function (data, status, headers, config) {
}).
error(function (data, status, headers, config) {
});
48
(function () {
'use strict';
angular.module('app').service('peopleService', peopleService);
function peopleService($http) {
var baseUrl = "/api/People/";
var getPeople = function () {
return $http({
method: 'GET',
url: baseUrl,
params: { 'update-time': new Date().getTime() }
});
}
var getPerson = function (id) {
return $http.get(baseUrl + "/" + id);
}
var addPerson = function (person) {
return $http.post(baseUrl, person);
}
var updatePerson = function (person) {
return $http.put(baseUrl, person);
}
var deletePerson = function (id) {
return $http({
method: 'DELETE',
url: baseUrl + '/' + id,
});
}
return {
getPeople: getPeople,
getPerson: getPerson,
addPerson: addPerson,
updatePerson: updatePerson,
deletePerson: deletePerson
}
}
})();
Rcupration
des donnes
$scope.save = function () {
if ($scope.person.Id == 0) { // ajout
peopleService.addPerson($scope.person).then(function () {
$location.path("/people/");
})
}
else { // modification
peopleService.updatePerson($scope.person).then(function () {
$location.path("/person/" + $scope.person.Id);
})
}
}
49
RESTfull : $resource
1er
8. Animation
Convention et CSS
Exemple cration dune animation shuffle-animation .On doit dfinir pour lanimation :
.ng-enter,
.ng-enter-active(fin entre)
.ng-leave
.ng-leave-active(fin quitter)
.animate-container {
position: relative;
}
.animate-container > div {
padding: 10px;
width: 100%;
}
.shuffle-animation.ng-enter,
.shuffle-animation.ng-leave {
position: absolute;
}
.shuffle-animation.ng-enter {
-o-transition: ease-out all 0.3s 0.4s;
-webkit-transition: ease-out all 0.3s 0.4s;
transition: ease-out all 0.3s 0.4s;
}
.shuffle-animation.ng-leave {
-o-transition: 0.3s ease-out all;
-webkit-transition: 0.3s ease-out all;
transition: 0.3s ease-out all;
}
.shuffle-animation.ng-enter,
.shuffle-animation.ng-leave.ng-leave-active {
left: 2em;
opacity: 0;
}
.shuffle-animation.ng-leave,
.shuffle-animation.ng-enter.ng-enter-active {
left: 0;
opacity: 1;
}
2nd utilisation
<section class="col-md-10">
<div class="animate-container">
<div ng-view class="shuffle-animation"></div>
</div>
</section>
50
IV- Breeze
http://www.breezejs.com/
Documentation et Api
1. Partie Server
Cration dun Web Service
Requiert Breeze Server et Breeze context provider pour EF6 (Package NuGet) pour la partie
server
Pour lexemple jutilise la base de donnes Northwind et un entity data model
using
using
using
using
using
using
using
System;
System.Linq;
Breeze.WebApi2;
System.Web.Http;
Newtonsoft.Json.Linq;
Breeze.ContextProvider.EF6;
Breeze.ContextProvider;
namespace BreezeBase.Controllers
{
[BreezeController]
public class BreezeController : ApiController
{
private readonly IRepository _repository;
public BreezeController()
:this(new NorthwindRepository())
{ }
public BreezeController(IRepository repository)
{
_repository = repository;
}
[HttpGet]
public string Metadata()
{
return _repository.MetaData;
}
[HttpPost]
public SaveResult SaveChanges(JObject saveBundle)
{
return _repository.SaveChanges(saveBundle);
}
[HttpGet]
public IQueryable<Product> Products()
{
return _repository.Products();
}
[HttpGet]
public IQueryable<Category> Categories()
{
return _repository.Categories();
}
}
}
51
Le repository
public interface IRepository
{
IQueryable<Product> Products();
IQueryable<Category> Categories();
SaveResult SaveChanges(JObject saveBundle);
string MetaData { get; }
}
public class NorthwindRepository : IRepository
{
private readonly EFContextProvider<NorthwindEntities> _contextProvider
= new EFContextProvider<NorthwindEntities>();
public string MetaData
{
get { return _contextProvider.Metadata(); }
}
public IQueryable<Product> Products()
{
return _contextProvider.Context.Products;
}
public IQueryable<Category> Categories()
{
return _contextProvider.Context.Categories;
}
public SaveResult SaveChanges(JObject saveBundle)
{
return _contextProvider.SaveChanges(saveBundle);
}
}
http://localhost:15253/breeze/breeze/Products
Mon contrleur se nommant Breeze il y a 2 fois
breeze puis laction breeze/{controller}/{action}
52
BreezeWebApiConfig
2. Partie Client
Breeze.js et q.js requis ct client(JavaScript)
Exemple avec Knockout
<body>
<table>
<thead>
<tr>
<td>Id</td>
<td>Name</td>
</tr>
</thead>
<tbody data-bind="foreach:categories">
<tr>
<td data-bind="text:CategoryID"></td>
<td data-bind="text:CategoryName"></td>
</tr>
</tbody>
</table>
<script
<script
<script
<script
Binding avec
Knockout
src="Scripts/jquery-2.1.1.min.js"></script>
src="Scripts/knockout-3.1.0.js"></script>
src="Scripts/q.js"></script>
src="Scripts/breeze.min.js"></script>
<script>
var Category = function (categoryID, categoryName) {
this.CategoryID = ko.observable(categoryID);
this.CategoryName = ko.observable(categoryName);
}
var vm = {
categories: ko.observableArray([])
}
Manager
var manager = new breeze.EntityManager("/breeze/breeze/");
manager.metadataStore.fetchMetadata(manager.dataService)
var query = new breeze.EntityQuery()
.from("Categories")
.orderBy("CategoryName");
manager.executeQuery(query)
.then(function (response) {
53
response.results.forEach(function (category) {
vm.categories.push(new Category(category.CategoryID(),
category.CategoryName()));
})
}).fail(function (e) {
alert(e);
Excution de la
});
requte
ko.applyBindings(vm);
</script>
Autre exemple + rcupre que des donnes partielles (cest--dire ne rcuprer que certaines
colonnes pour les afficher dans une vue liste ). Et on rcuprera toutes les colonnes pour la
vue dtails dun lment.
function getCategoriesPartials() {
var query = new breeze.EntityQuery()
.from("Categories")
.select("CategoryID, CategoryName")
.orderBy("CategoryName")
.toType("Category")
.using(manager)
.execute(querySucceeded, queryFailed);
function querySucceeded(data) {
vm.categories(data.results);
}
function queryFailed() {
}
}
Sauvegarde des
changements
function saveFailed() {
alert("fail to save changes");
}
function saveSuccess(saveResult) {
alert("Changes saved successfully");
};
})
54
Cancel
if (manager.hasChanges())
manager.rejectChanges();
55
EntityAspect
Contient les informations pour chaque entit.
On peut lutiliser pour consulter/modifier ltat dune entit (entityState), obtenir les valeurs
originales dune entit modifie, pour la validation et suivre les changements (subscribe).
Mthodes utiles
var changes = manager.getChanges();
var entities = manager.getEntities();
56