1 Applications avec Node.js Angular et MEAN
Transcript of 1 Applications avec Node.js Angular et MEAN
![Page 1: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/1.jpg)
1
Applications avec Node.js,
Angular et MEAN
Table des matières I. Prérequis ............................................................................................................................. 4
1. Les « indispensables ».................................................................................................... 4
a. NPM ............................................................................................................................. 4
b. Task runner : GruntJS ................................................................................................ 5
c. MongoDB.................................................................................................................... 6
2. Les « utiles »..................................................................................................................... 7
a. Bower .......................................................................................................................... 7
b. Git ................................................................................................................................ 8
c. Une console plus agréable ...................................................................................... 9
d. Pour tester ses services Web .................................................................................. 10
II. EDI et éditeurs de texte ................................................................................................. 10
III. Mêmento Node.js ....................................................................................................... 11
1. Création du projet et installation des modules ...................................................... 11
2. Organisation de projet ............................................................................................... 12
a. Serveur ...................................................................................................................... 13
b. Configuration ........................................................................................................... 13
c. Contrôleurs ............................................................................................................... 16
d. Mongoose ................................................................................................................ 16
e. Moteurs de vues ...................................................................................................... 17
IV. Module « core » ........................................................................................................... 22
1. Partie « client » ............................................................................................................. 22
a. « config.js » ................................................................................................................ 22
b. Configuration du module « core » ........................................................................ 22
c. Contrôleurs Angular ................................................................................................ 23
d. Message flash .......................................................................................................... 23
e. Vue « header » ......................................................................................................... 25
2. Partie « server » ............................................................................................................ 26
a. Routes côté server .................................................................................................. 26
b. Le layout ................................................................................................................... 26
V. Module « users » .............................................................................................................. 28
![Page 2: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/2.jpg)
2
1. Partie « server » ............................................................................................................ 28
a. Configuration de Passport ..................................................................................... 28
b. Création du modèle « User » .................................................................................. 32
c. Contrôleur d’’authentification .............................................................................. 33
d. « ErrorHandler » ........................................................................................................ 36
2. Partie « client » ............................................................................................................. 37
a. Module ...................................................................................................................... 37
b. Contrôleur Angular pour l’authentification ......................................................... 38
c. Service Authentication ........................................................................................... 38
d. Formulaires ............................................................................................................... 39
VI. Module quelconque .................................................................................................. 42
1. Partie client (Angular) ................................................................................................ 43
a. Module ...................................................................................................................... 43
b. Contrôleur(s) Angular ............................................................................................. 45
c. Services ..................................................................................................................... 46
d. Vues ........................................................................................................................... 47
2. Partie Serveur ............................................................................................................... 51
a. Routes côté serveur ................................................................................................ 51
b. Modèle Mongoose ................................................................................................. 51
c. Contrôleur « Express » .............................................................................................. 53
VII. Plus … ............................................................................................................................ 55
1. Express .......................................................................................................................... 55
a. Variables partagées ............................................................................................... 55
b. Charger un fichier JSON ......................................................................................... 55
c. Changer le répertoire des vues ............................................................................ 55
d. Ressources (dossier « public ») ............................................................................... 55
e. Express Generator ................................................................................................... 56
2. “Sans Express” .............................................................................................................. 57
a. Serveur ...................................................................................................................... 57
c. URL et paramètres .................................................................................................. 57
d. Créer un index listant les contrôleurs .................................................................... 58
e. Evénements.............................................................................................................. 58
3. Bases de données ....................................................................................................... 59
a. SQL Server ................................................................................................................. 59
b. MongoDB.................................................................................................................. 60
VIII. MEAN.JS ........................................................................................................................ 62
![Page 3: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/3.jpg)
3
Génération de code ......................................................................................................... 65
IX. Publication ................................................................................................................... 67
![Page 4: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/4.jpg)
4
I. Prérequis
1. Les « indispensables »
a. NPM
Documentation
NPM (Node Package Manager) permet d’installer et publier des modules.
Générer « package.json » de l’application.
Depuis une invite de commande, naviguer jusqu’au dossier du projet (cd …) du
projet puis
npm init
Installation de modules
On peut soit :
Installer des modules un par un
Installation globale
npm install nommodule –g
Installation locale au projet
npm install nommodule
Installation avec ajout de la dépendance à « package.json »
npm install nommodule --save
Autres commandes utiles :
Désinstaller un module (suppression dossier et dépendance dans « package.json »)
npm rm nomdule Mettre à jour
npm update
Soit définir les dépendances dans « package.json » et les installer toutes avec
la commande. Cette méthode est utile pour alléger le projet, on pourra
supprimer tous les modules et les installer ensuite par cette simple commande.
npm install
Exemple « package.json »
{
"name": "AngNodeDemo",
"version": "1.0.0",
"description": "Node Angular application demo.",
"main": "server.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
![Page 5: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/5.jpg)
5
"author": "ROMAGNY13",
"license": "ISC",
"dependencies": {
"body-parser": "^1.14.2",
"client-sessions": "^0.7.0",
"consolidate": "^0.14.0",
"express": "^4.13.4",
"mongoose": "^4.4.2",
"passport": "^0.3.2",
"passport-facebook": "^2.1.0",
"passport-google-oauth": "^1.0.0",
"passport-local": "^1.0.0",
"swig": "^1.4.2"
},
"devDependencies": {
"grunt": "^0.4.5",
"grunt-nodemon": "^0.4.1"
}
}
b. Task runner : GruntJS
Documentation
Permet d’éviter d’avoir à relancer le serveur à chaque modification du code.
Installer Grunt en global
npm install -g grunt-cli
Installer Grunt-Nodemon en local au projet
npm install grunt-nodemon --save-dev
Créer un fichier de configuration pour Grunt « gruntfile.js »
module.exports = function (grunt){
grunt.initConfig({
nodemon: {
all: {
script: 'app.js',
options: {
watchedExtensions: ['js']
}
}
}
});
grunt.loadNpmTasks('grunt-nodemon');
grunt.registerTask('default', ['nodemon']);
};
Pour lancer le serveur il suffit désormais de taper la commande « grunt » à la place
de « node server.js »
grunt
Dépendances qui seront installées
(« ^ » pour version minimum)
![Page 6: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/6.jpg)
6
c. MongoDB
Installation de MongoDB
Par défaut la base est installée dans « C:\Program Files\MongoDB »
La base de données est stockée par défaut dans « C:\data\db »
Les bases de données sont sur le port 27017. Exemple de chaine de connexion
« mongodb://localhost:27017/local-dev ». Les collections seront ajoutées à la
base de données « local-dev ».
Pour lancer , depuis une invite de commande, naviguer jusqu’au dossier
« bin » de MongoDB puis
mongod
Il est possible de changer la base de données de répertoire et définir ce nouveau
dossier :
mongod –dbpath ./data
Robomongo permet de gérer facilement ses bases de données MongoDB
Autres outils d’administration
![Page 7: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/7.jpg)
7
2. Les « utiles »
a. Bower
Documentation et packages disponibles
Bower est un gestionnaire de dépendances. Indispensable avec « Angular ». Il
permet d’installer des packages, les dépendances seront automatiquement
installées. Par exemple jQuery sera automatiquement ajouté avec Bootstrap. Bower
nécessite que Node.js et Git soient installés.
Installation de Bower (en global)
npm install bower -g
Installation de Bower localement au projet
npm install bower --save
Avec dépendance de développement (« devDependencies » de « package.json »)
npm install bower --save-dev
Pour définir le dossier où seront installées les librairies … Créer un fichier « .bowerrc »à
la racine du projet
{
"directory": "public/lib"
}
Le fonctionnement est un peu le même qu’avec NPM. On peut créer un fichier
« bower.json » qui contiendra la liste des dépendances
bower init
… et utiliser la commande pour installer tous les packages
bower install
On peut également installer les packages un par un
bower install bootstrap --save
Mettre à jour tous les packages
bower update
Mettre à jour un package
bower update bootstrap
Les fichiers seront installés
dans le dossier « public/lib »
![Page 8: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/8.jpg)
8
b. Git
Documentation
Installation
Télécharger et installer la version de Git (Windows, Mac, Linux, etc.)
On peut configurer si on veut (avec « Git Bash » )
git config --global user.name "Jerome Romagny"
git config --global user.email "romagny13@....."
git config --list
Définir le dossier du projet :
Avec git bash, naviguer jusqu’au dossier du projet (cd … ) puis
git init
Commit
Valider les changements dans le dossier (ajout/ suppression de fichiers, etc.)
git commit -a -m "initial commit"
On peut également définir les fichiers à ajouter puis « commit »
git add .
git commit -m "inital commit"
Commandes utiles :
- « git help »
- « git status » permet de lister les changements validés avec « git add » avant
un « commit »
- « git log » permet de lister tous les « commit »
Créer un fichier « .gitignore » à la racine du projet et indiquer les dossiers et fichiers à
ignorer. Exemple
/.idea
/vendor
composer.lock
Github
Cloner un projet github (copié dans le dossier défini auparavant) git clone http://github.com/...git
Remote
git remote add origin https ://github.com/…git
git push
(Demande les identifiants avec « https », on peut également utiliser « ssh »)
…Puis seulement « git push » les fois suivantes.
Message décrivant la build
Exemple ajout de variables globales
puis listing
![Page 9: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/9.jpg)
9
c. Une console plus agréable
Pour avoir une console plus agréable, on peut utiliser cmder.
Autre possibilité console 2 combiné avec gitbash (installée avec Git) pour avoir une
console moins austère.
Lancer console 2 puis menu « Edit » … « Settings »… onglet « Tabs »… « Add »
Title : « git bash » par exemple
Shell : C:\Windows\SysWOW64\cmd.exe /c ""C:\Program Files\Git\bin\sh.exe" --
login -i"
Startup uri : ce que l’on veut
On peut désormais ouvrir une nouvelle tab git bash
Le chemin vers git peut varier
![Page 10: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/10.jpg)
10
Commandes utiles
« cd » pour naviguer dans les dossiers
Glisser les répertoires dans l’invite de commande
« dir » lister les dossiers et fichiers du répertoire courant
« md » créer un dossier
touche « espace » et « flèches » permet de répéter la dernière commande entrée.
« cls » pour nettoyer la console
d. Pour tester ses services Web
DHC ,extension pour Chrome
Fiddler de Telerik (free)
II. EDI et éditeurs de texte WebStorm (ou PHPStorm) : chercher des plugins pour Node et Angular depuis
les settings
Visual Studio avec l’extension NodeJS tools for Visual Studio (ajout d’un onglet
de Templates « nodejs » + ouverture de la console depuis le menu contextuel
du projet et fenêtre « Node.js interactive window »)
Brackets, Visual Studio Code, Sublime Text, Atom, etc.
![Page 11: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/11.jpg)
11
III. Mêmento Node.js
1. Création du projet et installation des modules a. Créer le dossier du projet
b. Ajout de « package.json »
npm init
c. Modules
Express
npm install express --save
Moteur de vues
o Pour vash
npm install vash --save
o Pour ejs
npm install ejs --save
npm install ejs-locals --save
o Pour jade
npm install jade --save
o Pour swig
npm install consolidate --save
npm install swig --save
Mongoose
npm install mongoose --save
Body parser pour récupérer les valeurs de formulaires
npm install body-parser --save
Session
npm install client-sessions --save
Passport pour l’authentification
npm install passport --save
Stratégies (local, facebook, google,etc.)
npm install passport-local --save
npm install passport-facebook --save
npm install passport-google-oauth --save
![Page 12: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/12.jpg)
12
2. Organisation de projet Partie « server » Partie « client »
« node_modules » : librairies
installées par NPM pour node.js
« public » : dossier contenant la
partie « visible » du site (feuilles de
styles, images, modules Angular,
etc.)
« server » : On peut ranger dans
un dossier « server » si on veut
organiser son code
« config » : configuration des
différents modules Node.js
« controllers » Contrôleurs
« Express »
« models » : Modèles Mongoose
« views » : le layout et la page
index du site
A la racine « server.js », le serveur
Node.js
Dans le dossier « public » :
« css » : feuille de styles du site
« lib » : dossier où sont
installées les librairies par
Bower
« modules » dossier contenant
tous les modules Angular
![Page 13: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/13.jpg)
13
a. Serveur
Nommé « server.js » plutôt que « app.js » pour éviter la confusion avec Angular.
var express = require('express');
var env = process.env.NODE_ENV = process.env.NODE_ENV || 'development';
var app = express();
var config = require('./server/config/config')[env];
require('./server/config/express')(app, config);
require('./server/config/mongoose')(config);
require('./server/config/passport')(app,config);
require('./server/config/routes')(app);
app.listen(config.port);
console.log('Listening on port ' + config.port + '...');
b. Configuration
config.js var path = require('path');
var rootPath = path.normalize(__dirname + '/../');
module.exports = {
development: {
db: 'mongodb://localhost:27017/local-dev',
rootPath: rootPath,
port: process.env.PORT || 3000,
facebook: {
clientID: 'your client id',
clientSecret: 'your client secret',
callbackURL: '/api/auth/facebook/callback'
},
google: {
clientID: 'your client id',
clientSecret: 'your client secret',
callbackURL: 'http://localhost:3000/api/auth/google/callback'
}
},
production: {
rootPath: rootPath,
db: 'mongodb://....', // à configurer
port: process.env.PORT || 80,
facebook: {
clientID: 'your client id',
clientSecret: 'your client secret',
callbackURL: '/api/auth/facebook/callback'
},
google: {
clientID: 'your client id',
clientSecret: 'your client secret',
callbackURL: 'http://localhost:3000/api/auth/google/callback'
}
}
};
![Page 14: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/14.jpg)
14
Express var express = require('express'),
bodyParser = require('body-parser'),
session = require('client-sessions'),
consolidate = require('consolidate');
module.exports = function(app, config) {
app.set('views', config.rootPath + '/views');
app.engine('html', consolidate['swig']);
app.set('view engine', 'html');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(session({
cookieName: 'session',
secret: 'secret'
}));
app.use(express.static(config.rootPath + '/public'));
};
Mongoose var mongoose = require('mongoose'),
userModel = require('../models/user'),
articleModel = require('../models/article');
module.exports = function(config) {
mongoose.connect(config.db);
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error...'));
db.once('open', function callback() {
console.log('Db opened');
});
//articleModel.createDefaultArticles();
};
Passport
Voir le module “users”
![Page 15: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/15.jpg)
15
Routes var articleController = require('../controllers/articleController'),
auth = require('../controllers/authController');
module.exports = function (app) {
app.get('/api/articles/', articleController.list);
app.get('/api/articles/:id', articleController.read);
app.post('/api/articles/', articleController.create);
app.put('/api/articles/', articleController.update);
app.delete('/api/articles/:id', articleController.delete);
app.get('/', function (req,res) {
if (req.session && req.session.passport && req.session.passport.user) {
res.render('index', { 'user' : req.session.passport.user });
}
else {
res.render('index');
}
});
// local
app.route('/api/auth/register').post(auth.register);
app.route('/api/auth/login').post(auth.login);
app.route('/api/auth/facebook').get(auth.oauthCall('facebook',{ scope: ['email'] }));
app.route('/api/auth/facebook/callback').get(auth.oauthCallback('facebook'));
app.route('/api/auth/google').get(auth.oauthCall('google', {
scope: [
'https://www.googleapis.com/auth/userinfo.profile',
'https://www.googleapis.com/auth/userinfo.email'
]
}));
app.route('/api/auth/google/callback').get(auth.oauthCallback('google'));
// log out
app.get('/api/auth/logout', auth.logout);
};
Si on ne veut pas passer « app » on peut utiliser « router »
var articleController = require('../controllers/articleController'),
express = require('express'),
router = express.router();
module.exports = function () {
router.get('/api/articles/', articleController.list);
// etc.
};
Utilise les contrôleurs
On passe express en argument
Route et appel de fonction du
contrôleur
![Page 16: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/16.jpg)
16
c. Contrôleurs
Exemple de contrôleur
var mongoose = require('mongoose'),
Article = mongoose.model('Article'),
errorHandler = require('./errorHandler');
exports.list = function (req, res) {
Article.find().sort('-created').populate('user').exec(function (err, articles) {
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
res.json(articles);
}
});
};
d. Mongoose
Documentation
Création des modèles dans un dossier « models »
var mongoose = require('mongoose');
var schema = new mongoose.Schema({
title: {type:String, required:'{PATH} is required!'},
content: {type:String, required:'{PATH} is required!'}
});
var Article = mongoose.model('Article', schema);
Types de données :
String
Number
Date
Boolean
Buffer
ObjectId
Mixed
Array
Ne pas oublier « require » dans ce cas dans « mongoose.js »
var mongoose = require('mongoose'),
articleModel = require('../models/article');
Dans les contrôleurs on utilisera
var mongoose = require('mongoose'),
Article = mongoose.model('Article');
![Page 17: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/17.jpg)
17
Une variante
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var ArticleSchema = new Schema({
title: {type:String, required:'{PATH} is required!'},
content: {type:String, required:'{PATH} is required!'}
});
module.exports = mongoose.model('Article', ArticleSchema, 'articles');
Pas besoin de require dans « mongoose.js » mais require dans les contrôleurs
var mongoose = require('mongoose'),
Article = require('../models/article');
e. Moteurs de vues
Choix du moteur de template (Express)
app.set("view engine", "ejs");
Définir le chemin du dossier content les vues
app.set('views', __dirname + '/views');
Passage de paramètres à la vue
res.render('articles-list',{title:'Mon titre', articles:articles});
Swig
Documentation
Fichiers avec extension « *.html »
Pour pouvoir utiliser Swig, installer avec NPM
npm install consolidate --save
npm install swig --save
Puis dans la configuration d’Express
var express = require('express'),
// etc.
consolidate = require('consolidate');
module.exports = function(app, config) {
app.set('views', config.rootPath + '/views');
app.engine('html', consolidate['swig']);
app.set('view engine', 'html');
// etc.
app.use(express.static(__dirname + "/../../public"));
};
Les variables entre accolades {{ }}
![Page 18: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/18.jpg)
18
{{ title }}
Exemple de boucle
{% for article in articles %}
<h1>{{ article.title }}</h1>
<p>{{ article.content }}</p>
{% endfor %}
Note : avec Angular on utilisera plutôt les directives
![Page 19: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/19.jpg)
19
VASH
Documentation
Fichiers avec extension « *.vash »
Master Page « layout.vash »
<!doctype html>
<html>
<head>
<title>@model.title</title>
</head>
<body>
@html.block("body")
@html.block("scripts")
</body>
</html>
Vue
@html.extend('layout', function(model){
@html.block("body", function (model) {
<p>Le contenu</p>
});
});
Variable avec @model
@model.title
Exemple de boucle
@model.articles.forEach(function(article){ <h2>@article.title</h2> <p>@article.content</p> });
![Page 20: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/20.jpg)
20
EJS
Documentation
Fichiers avec extension « *.ejs »
Installer ejs-locals pour le support des master pages
npm install ejs –save
npm install ejs-locals --save
configuration
var engine = require('ejs-locals');
app.engine('ejs', engine);
app.set('view engine', 'ejs');
Master page “layout.ejs”
<!doctype html>
<html>
<head>
<title><%- title %></title>
</head>
<body>
<%- body %>
</body>
</html>
Vue
<% layout('layout.ejs') -%>
<p>Le contenu</p>
Variables entre <%= %>
<h1><%= title %></h1>
Exemple de boucle
<% articles.forEach(function(article){ %>
<h2><%= article.title %></h2>
<p><%= article.content %></p>
<% }) %>
Vues partielles (dans un dossier “partials” de “views”)
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<title></title>
<link href="/css/default.css" rel="stylesheet" />
</head>
<body>
<%= include partials/footer.ejs %>
</body>
</html>
Exemple de vue partielle
<footer>
<div>Copyright © J. ROMAGNY</div>
![Page 21: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/21.jpg)
21
</footer>
Jade
Documentation
Fichiers avec extension « *.jade »
Master page “layout.jade”
doctype
html
head
title= title
body
block content
Vue
extends layout
block content
p Le contenu
Variables
h1= title
Exemple de boucle
each article in articles
h2=article.title
p=article.content
![Page 22: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/22.jpg)
22
IV. Module « core »
1. Partie « client »
a. « config.js »
Enregistrement de tous les modules de l’application + dépendances
'use strict';
var app = angular.module('app',['core','articles','users','ngRoute']);
b. Configuration du module « core »
Contient essentiellement les routes vers la page d’accueil et vers la page « 404 »
'use strict';
var core = angular.module('core',['ngRoute']);
core.config(function ($routeProvider) {
$routeProvider
.when('/',{
controller:'HomeController',
templateUrl:'modules/core/views/home.html'
})
.otherwise({ redirectTo: "/" })
}
);
Enregistrement de tous les modules de
l’application
Contrôleurs Angular pour la vue
« header » insérée dans le layout et
pour la vue d’accueil du site.
Vues
Configuration du module
« core » et routes
Directives et services
partagés
![Page 23: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/23.jpg)
23
c. Contrôleurs Angular
« HeaderController » On injecte « Authentication » afin de pouvoir mettre en forme le
menu du header selon que l’utilisateur est connecté ou non.
angular.module('core').controller('HeaderController',function($scope,Auth
entication, flash, $rootScope){
$scope.authentication = Authentication;
function flashMessage() {
if(flash.hasMessage()){
$scope.message = flash.getMessage();
}
else{
$scope.message = undefined;
}
}
$rootScope.$on('$routeChangeStart',
function () { flashMessage(); }
);
});
« HomeController » est très classique voir quasiment vide, selon ce que l’on affiche
en page d’accueil. Il peut avoir un « title ».
d. Message flash
On peut se créer un service très simple de message. Le message n’est affiché
qu’une fois (supprimé après un changement de route)
angular.module('core').service("flash", function($rootScope) {
var message = undefined;
$rootScope.$on("$routeChangeSuccess", function() {
message = undefined;
});
this.setMessage = function(text,type){
message ={};
message.text = text;
message.type = typeof type !== 'undefined' ? 'success' : type;
message.cssclass = typeof message.type !== 'success' ? 'alert-
success' : 'alert-error';
};
this.getMessage = function() {
return message;
};
this.hasMessage = function() {
return message;
};
});
Il suffit ensuite de l’injecter dans les contrôleurs devant l’utiliser. On indique un
message avec « setMessage »
flash.setMessage('Article modifié.');
![Page 24: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/24.jpg)
24
On ajoute dans une vue partielle que l’on inclut dans le layout par exemple.
<div ng-show="message" class="alert {{ message.cssclass }}">
<span dynamic="message.text"></span>
</div>
Et dans le contrôleur de cette vue partielle, on injecte le service « flash » puis on teste
à chaque changement de route si un message est présent.
function flashMessage() {
if(flash.hasMessage()){
$scope.message = flash.getMessage();
}
else{
$scope.message = undefined;
}
}
$rootScope.$on('$routeChangeStart',
function () { flashMessage(); }
);
La directive « dynamic » permet d’insérer du contenu au format HTML dans le
message.
angular.module('core').directive('dynamic', ['$compile', function
($compile) {
return {
restrict: 'A',
replace: true,
link: function link(scope, ele, attrs) {
return scope.$watch(attrs.dynamic, function (html) {
ele.html(html);
return $compile(ele.contents())(scope);
});
}
};
}]);
Exemple de contenu au format HTML
flash.setMessage('<strong>Article ajouté!</strong> vous pouvez le
<i>modifier</i> si vous le désirez.');
C’est un exemple simple. On peut aussi utiliser angular-flash
Exemple de message flash
![Page 25: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/25.jpg)
25
e. Vue « header »
(Mise en forme avec Bootstrap)
<div class="navbar-inverse">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-
target=".navbar-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a href="#/" class="navbar-brand">Angular Node Demo</a>
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li ng-class="{ active: isActive('/')}"><a href="#/">Accueil</a></li>
<li ng-class="{ active: isActive('/articles/')}"><a
href="#/articles/">Blog</a></li>
</ul>
<ul class="nav navbar-nav navbar-right" ng-hide="authentication.user">
<li><a href="#/register">S'inscrire</a></li>
<li class="divider-vertical"></li>
<li><a href="#/login">Se connecter</a></li>
</ul>
<ul class="nav navbar-nav navbar-right" ng-show="authentication.user">
<li><a href="#">Bonjour {{ authentication.user.username }}</a></li>
<li class="divider-vertical"></li>
<li><a href="/api/auth/logout">Se déconnecter</a></li>
</ul>
</div>
</div>
</div>
<div class="separator-20"></div>
<div class="container">
<div ng-show="message" class="alert {{ message.cssclass }}">
<span dynamic="message.text"></span>
</div>
</div>
Menu hamburger
visible sur mobile
Menu à gauche avec
« Accueil » ,etc.
Menu à droite pour
utilisateur anonyme et
connecté
Pour l’exemple
message flash
Menu
« déconnecté »
Menu
« connecté »
![Page 26: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/26.jpg)
26
2. Partie « server »
a. Routes côté server
Dans « routes.js » du dossier « config » du « server ». Essentiellement la route vers la
page d’accueil
var articleController = require('../controllers/articleController'),
auth = require('../controllers/authController');
module.exports = function (app) {
// etc.
app.get('/', function (req,res) {
if (req.session && req.session.passport && req.session.passport.user) {
res.render('index', { 'user' : req.session.passport.user });
}
else {
res.render('index');
}
});
};
b. Le layout <!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1">
<title>Titre</title>
<link type="text/css" rel="stylesheet" href="/lib/bootstrap/dist/css/bootstrap.css" />
<link type="text/css" rel="stylesheet" href="/css/style.css" />
</head>
<body ng-app="app">
<header ng-include="'/modules/core/views/header.html'" ng-
controller="HeaderController"></header>
<section class="content">
<section class="container">
{% block content %}{% endblock %}
</section>
</section>
<script type="text/javascript">
window.user = {{ user | json | safe }}
</script>
<!-- vendors -->
<script type="text/javascript" src="/lib/angular/angular.min.js"></script>
<script type="text/javascript" src="/lib/angular/angular-locale_fr-fr.js"></script>
<script type="text/javascript" src="/lib/angular-route/angular-route.min.js"></script>
<script type="text/javascript" src="/lib/angular-resource/angular-
resource.min.js"></script>
<!-- modules -->
<script type="text/javascript" src="/modules/core/core.module.js"></script>
<script type="text/javascript" src="/modules/users/users.module.js"></script>
<script type="text/javascript" src="/modules/articles/articles.module.js"></script>
![Page 27: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/27.jpg)
27
<script type="text/javascript" src="/modules/core/config/config.js"></script>
<!-- controllers -->
<script type="text/javascript"
src="/modules/articles/controllers/articleController.js"></script>
<script type="text/javascript" src="/modules/users/controllers/authController.js"></script>
<script type="text/javascript"
src="/modules/core/controllers/headerController.js"></script>
<script type="text/javascript" src="/modules/core/controllers/homeController.js"></script>
<!-- Directives -->
<script type="text/javascript" src="/modules/core/directives/dynamic.js"></script>
<script type="text/javascript"
src="/modules/articles/directives/contenteditable.js"></script>
<!-- Services -->
<script type="text/javascript"
src="/modules/articles/services/articles.service.js"></script>
<script type="text/javascript" src="/modules/core/services/flash.js"></script>
<script type="text/javascript" src="/modules/users/services/authentication.js"></script>
</body>
</html>
« Index.html »
C’est la page principale du site qui va afficher les vues avec la directive ng-view (ou
ui-view avec ui-router). Elle utilise le layout.
{% extends 'layout.html' %}
{% block content %}
<div ng-view></div>
{% endblock %}
![Page 28: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/28.jpg)
28
V. Module « users »
1. Partie « server » Passport permet de simplifier l’authentification. Il faut définir les stratégies utilisées :
local, facebook, google, … Stratégies disponibles
a. Configuration de Passport var passport = require('passport'),
User = require('mongoose').model('User');
module.exports = function (app, config) {
passport.serializeUser(function (user, done) {
done(null, user);
});
passport.deserializeUser(function (id, done) {
User.findOne({
_id: id
}, '-salt -password', function (err, user) {
done(err, user);
});
});
require('./strategies/facebook')(config);
require('./strategies/google')(config);
require('./strategies/local')();
app.use(passport.initialize());
app.use(passport.session());
};
Stratégie « local »
npm install passport-local --save
var passport = require('passport'),
LocalStrategy = require('passport-local').Strategy,
User = require('mongoose').model('User');
module.exports = function () {
passport.use(new LocalStrategy({
usernameField: 'username',
passwordField: 'password'
},
function (username, password, done) {
User.findOne({
username: username
}, function (err, user) {
if (err) {
return done(err);
}
if (!user || !user.authenticate(password)) {
return done(null, false, {
message: 'Utilisateur ou mot de passe incorrect.'
});
}
return done(null, user);
});
}
));
};
![Page 29: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/29.jpg)
29
Stratégie « Facebook »
npm install passport-facebook --save
var passport = require('passport'),
FacebookStrategy = require('passport-facebook').Strategy,
auth = require('../../controllers/authController');
module.exports = function (config) {
passport.use(new FacebookStrategy({
clientID: config.facebook.clientID,
clientSecret: config.facebook.clientSecret,
callbackURL: config.facebook.callbackURL,
profileFields: ['id', 'name', 'displayName', 'emails',
'photos'],
passReqToCallback: true
},
function (req, accessToken, refreshToken, profile, done) {
var providerData = profile._json;
providerData.accessToken = accessToken;
providerData.refreshToken = refreshToken;
var providerUserProfile = {
firstName: profile.name.givenName,
lastName: profile.name.familyName,
displayName: profile.displayName,
email: profile.emails[0].value,
profileImageURL: (profile.id) ? '//graph.facebook.com/' +
profile.id + '/picture?type=large' : undefined,
provider: 'facebook',
providerIdentifierField: 'id',
providerData: providerData
};
auth.saveOAuthUserProfile(req, providerUserProfile, done);
}
));
};
Création d’une application Facebook
![Page 30: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/30.jpg)
30
Récupérer l’App ID et l’APP Secret et les indiquer dans « config.js »
Stratégie « Google »
On utilise ici « passport-google-oauth », il en existe d’autres pour Google.
npm install passport-google-oauth --save
var passport = require('passport'),
GoogleStrategy = require('passport-google-oauth').OAuth2Strategy,
auth = require('../../controllers/authController');
module.exports = function (config) {
passport.use(new GoogleStrategy({
clientID: config.google.clientID,
clientSecret: config.google.clientSecret,
callbackURL: config.google.callbackURL,
passReqToCallback: true
},
function (req, accessToken, refreshToken, profile, done) {
var providerData = profile._json;
providerData.accessToken = accessToken;
providerData.refreshToken = refreshToken;
var providerUserProfile = {
firstName: profile.name.givenName,
lastName: profile.name.familyName,
displayName: profile.displayName,
email: profile.emails[0].value,
username: profile.username,
profileImageURL: (providerData.picture) ?
providerData.picture : undefined,
provider: 'google',
providerIdentifierField: 'id',
providerData: providerData
};
auth.saveOAuthUserProfile(req, providerUserProfile, done);
}
));
};
![Page 31: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/31.jpg)
31
Création d’une application Google avec la console Google Developers
Avec creation d’une clé et URI de redirection (exemple
« http://localhost:3000/api/auth/google/callback » en local)
Récupérer le Client ID et le code secret et les indiquer dans « config.js »
![Page 32: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/32.jpg)
32
b. Création du modèle « User » var mongoose = require('mongoose'),
Schema = mongoose.Schema,
crypto = require("crypto");
var UserSchema = new Schema({
firstName: {type: String, trim: true, default: ''},
lastName: {type: String, trim: true, default: ''},
displayName: {type: String, trim: true},
email: { type: String, trim: true, unique: true, default: ''},
username: {type: String, unique: 'Un utilisateur avec cet identifiant
est déja enregistré.', required: 'Vous devez indiquer un nom
d\'utilisateur', trim: true},
password: {type: String, default: ''},
salt: {type: String},
profileImageURL: {type: String},
roles: {
type: [{
type: String,
enum: ['user', 'admin']
}],
default: ['user']
},
provider: {type: String, required: 'Un provider est requis'},
providerData: {},
created: {type: Date, default: Date.now}
});
UserSchema.pre('save', function (next) {
this.salt = createSalt();
this.password = hashPassword(this.password, this.salt);
next();
});
var createSalt = function () {
return crypto.randomBytes(128).toString('base64');
};
var hashPassword = function (password, salt) {
var hmac = crypto.createHmac("sha1", salt);
return hmac.update(password).digest("hex");
};
UserSchema.methods.authenticate = function (password) {
return this.password === hashPassword(password,this.salt);
};
var User = mongoose.model('User', UserSchema);
![Page 33: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/33.jpg)
33
c. Contrôleur d’’authentification
Partie pour la stratégie « local »
var passport = require('passport'),
mongoose = require('mongoose'),
User = mongoose.model('User'),
errorHandler = require('./errorHandler');
exports.register = function (req, res) {
var user = new User(req.body);
var message = null;
user.provider = 'local';
user.displayName = user.firstName + ' ' + user.lastName;
user.save(function (err) {
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
// sensitive data
user.password = undefined;
user.salt = undefined;
req.login(user, function (err) {
if (err) {
res.status(400).send(err);
} else {
res.json(user);
}
});
}
});
};
exports.login = function (req, res) {
passport.authenticate('local', function (err, user, info) {
if (err || !user) {
res.status(400).send(info);
} else {
user.password = undefined;
user.salt = undefined;
req.login(user, function (err) {
if (err) {
res.status(400).send(err);
} else {
res.json(user);
}
});
}
})(req, res);
};
exports.logout = function(req,res){
req.logout();
req.session.destroy();
res.redirect('/'); //
};
![Page 34: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/34.jpg)
34
Stratégies Facebook, Google, etc.
var noReturnUrls = [
'/login',
'/register'
];
exports.oauthCall = function(strategy,scope){
return passport.authenticate(strategy, scope)
};
exports.oauthCall = function (strategy, scope) {
return function (req, res, next) {
if (noReturnUrls.indexOf(req.query.redirect_to) === -1) {
req.session.redirect_to = req.query.redirect_to;
}
passport.authenticate(strategy, scope)(req, res, next);
};
};
exports.oauthCallback = function (strategy) {
return function (req, res, next) {
var sessionRedirectURL = req.session.redirect_to;
delete req.session.redirect_to;
passport.authenticate(strategy, function (err, user, redirectURL) {
if (err) {
return res.redirect('/login');
}
if (!user) {
return res.redirect('/login');
}
req.login(user, function (err) {
if (err) {
return res.redirect('/login');
}
else{
return res.redirect(redirectURL || '/#' + sessionRedirectURL || '/');
}
});
})(req, res, next);
};
};
![Page 35: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/35.jpg)
35
La fonction servant à connecter/enregistrer l’utilisateur avec stratégie Facebook,
Google, etc.
exports.saveOAuthUserProfile = function (req, providerUserProfile, done) {
var identifierField = 'providerData.' + providerUserProfile.providerIdentifierField;
var searchQuery = {};
searchQuery.provider = providerUserProfile.provider; // facebook, google, etc.
searchQuery[identifierField] =
providerUserProfile.providerData[providerUserProfile.providerIdentifierField]; // id
User.findOne(searchQuery, function (err, user) {
if (err) {
return done(err);
} else {
if (!user) {
var availableUsername = providerUserProfile.username ||
((providerUserProfile.email) ? providerUserProfile.email.split('@')[0] : '');
user = new User({
firstName: providerUserProfile.firstName,
lastName: providerUserProfile.lastName,
username: availableUsername,
displayName: providerUserProfile.displayName,
email: providerUserProfile.email,
profileImageURL: providerUserProfile.profileImageURL,
provider: providerUserProfile.provider,
providerData: providerUserProfile.providerData
});
user.save(function (err) {
return done(err, user);
});
}
else {
return done(err, user);
}
}
});
};
![Page 36: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/36.jpg)
36
d. « ErrorHandler »
Pour afficher des messages d’erreurs lisibles pour les visiteurs.
exports.getErrorMessage = function (err) {
var message = '';
if (err.code) {
switch (err.code) {
case 11000:
case 11001:
message = getUniqueErrorMessage(err);
break;
default:
message = 'Une erreur est survenue';
}
} else {
for (var errName in err.errors) {
if (err.errors[errName].message) {
message = err.errors[errName].message;
}
}
}
return message;
};
var getUniqueErrorMessage = function (err) {
var output;
try {
var fieldName = err.errmsg.substring(err.errmsg.lastIndexOf('.$') + 2,
err.errmsg.lastIndexOf('_1'));
output = fieldName.charAt(0).toUpperCase() + fieldName.slice(1) + ' existe
déja';
} catch (ex) {
output = 'Ce champ existe déja';
}
return output;
};
![Page 37: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/37.jpg)
37
2. Partie « client »
a. Module
Routes vers les vues « login » et « register » et check à changement de route pour voir
si l’utilisateur est autorisé à aller à la route suivante
'use strict';
var users = angular.module('users',['ngRoute']);
users.config(function ($routeProvider) {
$routeProvider
.when('/login',{
controller:'AuthController',
templateUrl:'modules/users/views/login.html'
})
.when('/register',{
controller:'AuthController',
templateUrl:'modules/users/views/register.html'
})
}
);
users.run(function ($rootScope, Authentication,$location) {
$rootScope.$on('$routeChangeStart', function (event,next, current) {
if (next && next.$$route && next.$$route.secure) {
if (!Authentication.user) {
$rootScope.$evalAsync(function () {
$rootScope.previousUrl = next.$$route.originalPath;
$location.path('/login');
});
}
}
});
});
Contrôleur gérant
l’authentification
Service permettant de
stocker l’utilisateur
Vues pour se connecter et
s’inscrire
Configuration et routes du
module
![Page 38: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/38.jpg)
38
b. Contrôleur Angular pour l’authentification 'use strict';
angular.module('users').controller('AuthController',
function ($rootScope, $scope, $http, $location, $window, Authentication) {
$scope.authentication = Authentication;
// erreur passée dans l’url
$scope.error = $location.search().err;
var redirect_to = $rootScope.previousUrl || '/';
if ($scope.authentication.user) {
$location.path('/');
}
$scope.register = function () {
$http.post('/api/auth/register',$scope.credentials).then(function(response){
$scope.authentication.user = response.data;
$location.path('/');
},function(response){
$scope.error = response.data.message;
});
};
$scope.login = function () {
$http.post('/api/auth/login',$scope.credentials).then(function(response){
$scope.authentication.user = response.data;
$location.path(redirect_to);
},function(response){
$scope.error = response.data.message;
});
};
$scope.callOauthProvider = function (url) {
$window.location.href = url + (redirect_to ? '?redirect_to=' +
encodeURIComponent(redirect_to) : '');
};
});
c. Service Authentication
Permettant de stocker l’utilisateur connecté
angular.module('users').service('Authentication', ['$window',
function ($window) {
var auth = {
user: $window.user
};
return auth;
}
]);
![Page 39: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/39.jpg)
39
Dans le layout
<script type="text/javascript">
window.user = {{ user | json | safe }}
</script>
d. Formulaires
Connexion
<div class="col-md-offset-4 col-md-4">
<h3>Se connecter avec</h3>
<form ng-submit="login()" class="form-horizontal" autocomplete="off">
<fieldset>
<div class="form-group">
<a class="btn btn-block btn-social btn-facebook" href ng-
click="callOauthProvider('/api/auth/facebook')">
<span class="fa fa-facebook"></span>
</a>
<a class="btn btn-block btn-social btn-google" href ng-
click="callOauthProvider('/api/auth/google')">
<span class="fa fa-google"></span>
Google+
</a>
</div>
<hr class="hrOr">
<div class="form-group">
<label class="sr-only" for="email">Email</label>
<input type="email" id="email" name="email" placeholder="Email"
class="form-control" ng-model="credentials.email"/>
</div>
<div class="form-group">
<label class="sr-only" for="password">Password</label>
<input type="password" id="password" name="password" class="form-control"
placeholder="Mot de passe" ng-model="credentials.password"/>
</div>
<div class="text-center form-group">
<button type="submit" class="btn btn-primary">Se connecter</button>
ou
<a href="#/register">S'inscrire</a>
</div>
</fieldset>
</form>
<alert type="danger" ng-show="error" class="text-center text-danger">
<span ng-bind="error"></span>
</alert>
</div>
Utilisation de Bootstrap social pour les boutons Facebook et Google+
bower install bootstrap-social --save
Référencer bootstrap social et font awesome dans le layout
<link type="text/css" rel="stylesheet" href="/lib/bootstrap/dist/css/bootstrap.css" />
<link type="text/css" rel="stylesheet" href="/lib/bootstrap-social/bootstrap-social.css"
/>
<link type="text/css" rel="stylesheet" href="/lib/font-awesome/css/font-awesome.css" />
![Page 40: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/40.jpg)
40
Inscription
<div class="col-md-offset-4 col-md-4">
<h3>Inscription</h3>
<alert type="danger" ng-show="error" class="text-center text-danger">
<span ng-bind="error"></span>
</alert>
<form name="userForm" ng-submit="register()" class="form-horizontal" novalidate
autocomplete="off">
<fieldset>
<div class="form-group">
<label for="firstName">Prénom</label>
<input type="text" required id="firstName" name="firstName" class="form-
control"
ng-model="credentials.firstName" placeholder="Prénom">
</div>
<div class="form-group">
<label for="lastName">Nom</label>
<input type="text" id="lastName" name="lastName" class="form-control"
ng-model="credentials.lastName" placeholder="Nom">
</div>
<div class="form-group">
<label for="username">Username</label>
<input type="text" id="username" name="username" class="form-control"
ng-model="credentials.username" placeholder="Username">
</div>
<div class="form-group">
<label for="email">Email</label>
<input type="email" id="email" name="email" placeholder="Email"
class="form-control" ng-model="credentials.email"/>
</div>
<div class="form-group">
<label for="password">Mot de passe</label>
<input type="password" id="password" name="password" class="form-control"
placeholder="Mot de passe" ng-model="credentials.password"/>
</div>
<div class="form-group">
<label for="confirmpassword">Confirmer le mot de passe</label>
<input type="password" id="confirmpassword" name="confirmpassword"
class="form-control" ng-model="credentials.confirmpassword" placeholder="Confirmer le mot
de passe" required>
</div>
<div class="text-center form-group">
<button type="submit" class="btn btn-primary">S'inscrire</button>
ou
<a href="#/login">Se connecter</a>
</div>
</fieldset>
</form>
</div>
![Page 41: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/41.jpg)
41
Ce qui donne …
Connexion
Inscription
![Page 42: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/42.jpg)
42
VI. Module quelconque Exemple avec « articles » que l’on pourrait retrouver avec un CMS.
Détails Liste
Edition
Boutons édition,
suppression visibles
que si l’utilisateur
est l’auteur de
l’article
Affichage du contenu
au format HTML
Content éditable
et sauvegarde au
format HTML vers
MongoDB. L’ajout
et la modification
d’articles
réclament des
utilisateurs
authentifiés
![Page 43: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/43.jpg)
43
1. Partie client (Angular)
a. Module
Avec une organisation du projet par modules.
Pour chaque module on crée un fichier dans lequel on définit le nom du
module, ses dépendances, routes pour ce module uniquement (on peut aussi
créer un fichier de routes à part dans un dossier « routes »)
'use strict';
var articles = angular.module('articles',['ngRoute','ngResource']);
articles.config(function ($routeProvider) {
$routeProvider
.when('/articles/',{
controller:'ArticleController',
templateUrl:'modules/articles/views/list.html'
})
.when('/articles/view/:id',{
controller:'ArticleController',
templateUrl:'modules/articles/views/view.html'
})
.when('/articles/create',{
controller:'ArticleController',
templateUrl:'modules/articles/views/create.html',
secure:true
})
.when('/articles/edit/:id',{
controller:'ArticleController',
templateUrl:'modules/articles/views/edit.html',
secure:true
})
}
);
Routes : On peut utiliser soit $routeProvider, soit $stateProvider
On enregistre le module dans un module principal (dans un fichier « config.js »
dans un dossier « config » du module « core »)
var app = angular.module('app',['core','articles','users','ngRoute']);
Configuration du
module
Vues
Services du module
Contrôleurs Angular
Directives
![Page 44: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/44.jpg)
44
Sécuriser une route
Dans l’exemple la création et modification d’articles demandent d’être authentifié.
De plus, chaque utilisateur ne pourra modifier que les articles dont il est l’auteur.
Indiquer « secure » dans la route
$routeProvider
.when('/articles/create',{
controller:'ArticleController',
templateUrl:'modules/articles/views/create.html',
secure:true
})
Dans le module « users » on vérifie à chaque changement de route si l’utilisateur est
autorisé à accéder à la route suivante. Si ce n’est pas le cas on le redirige vers la vue
de login.
'use strict';
var users = angular.module('users',['ngRoute']);
// routing du module
users.run(function ($rootScope, Authentication,$location) {
$rootScope.$on('$routeChangeStart', function (event,next, current) {
if (next && next.$$route && next.$$route.secure) {
if (!Authentication.user) {
$rootScope.$evalAsync(function () {
$rootScope.previousUrl = next.$$route.originalPath;
$location.path('/login');
});
}
}
});
});
Pour rendre un article éditable seulement par son auteur, on n’affiche les boutons
édition et suppression que si l’identifiant de l’utilisateur actuel correspond à celui de
l’auteur de l’article.
<div class="pull-right" ng-show="authentication.user._id == article.user._id">
<a href="#/articles/edit/{{ article._id}}" class="btn btn-default">Modifier</a>
<a class="btn btn-primary" ng-click="delete();">
Supprimer
</a>
</div>
![Page 45: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/45.jpg)
45
b. Contrôleur(s) Angular
Contiennent les crud. Un contrôleur peut servir pour plusieurs vues. Exemple de
contrôleur utilisant un service avec $resource
'use strict';
angular.module('articles').controller('ArticleController', ['$scope', '$routeParams',
'$location', 'Authentication', 'Articles', 'flash',
function ($scope, $routeParams, $location, Authentication, Articles, flash) {
$scope.authentication = Authentication;
$scope.getAll = function () {
$scope.articles = Articles.query();
};
$scope.findOne = function () {
$scope.article = Articles.get({
id: $routeParams.id
});
};
$scope.create = function () {
var article = new Articles({
title: this.title,
content: this.content
});
article.$save(function (response) {
flash.setMessage('Article ajouté.');
$location.path('/articles/view/' + response._id);
$scope.title = '';
$scope.content = '';
}, function (errorResponse) {
$scope.error = errorResponse.data.message;
});
};
$scope.update = function () {
var article = $scope.article;
article.$update(function () {
flash.setMessage('Article modifié.');
$location.path('/articles/view/' + article._id);
}, function (errorResponse) {
$scope.error = errorResponse.data.message;
});
};
$scope.delete = function () {
$scope.article.$delete({id: this.article._id},function () {
flash.setMessage('Article supprimé.');
$location.path('/articles/');
});
};
}
]);
![Page 46: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/46.jpg)
46
c. Services
Service avec $http
Documentation
'use strict';
angular.module('articles').service('Articles',function($http){
var baseUrl = "/api/articles/";
this.getAll = function(){
return $http.get(baseUrl);
};
this.findOne = function (id) {
return $http.get(baseUrl + id);
};
this.create = function (article) {
return $http.post(baseUrl,article);
};
this.update = function (article) {
return $http.put(baseUrl,article);
};
this.delete = function (id) {
return $http.delete( baseUrl + id);
}
});
Service avec $resource
Documentation
Installer avec Bower angular-resource
bower install angular-resource --save
Le référencer dans le layout
<script type="text/javascript" src="/lib/angular-resource/angular-
resource.min.js"></script>
Création du service utilisé par le contrôleur
'use strict';
angular.module('articles').factory('Articles', ['$resource',
function ($resource) {
return $resource('api/articles/:id', {
id: '@id'
}, {
update: {
method: 'PUT'
}
},
{
delete:{
method:'DELETE'
}
});
}
]);
Création d’une fonction
delete avec passage du
paramètre id dans l’url
Création d’une fonction
update avec utilisation de la
méthode PUT (non présente
de base)
![Page 47: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/47.jpg)
47
d. Vues
Vue liste
<section ng-init="getAll()">
<div>
<h1>Articles</h1>
<hr>
</div>
<div ng-show="articles.length > 0">
<a href="#/articles/create" class="btn btn-primary">Ajouter un nouvel
article</a>
<div ng-repeat="article in articles">
<article>
<header class="entry-header">
<h2><a href="#/articles/view/{{ article._id }}" >{{ article.title
}}</a></h2>
<div class="entry-meta">
<small>
<em class="text-muted">
Posté le <span class="created">{{ article.created |
date:'mediumDate' }}</span>
par <span class="author">{{ article.user.username
}}</span>
</em>
</small>
</div>
</header>
<div class="entry-content">
<div dynamic="article.content" ></div>
</div>
</article>
</div>
</div>
<div class="alert alert-warning text-center" ng-show="articles.length==0">
Voulez-vous ajouter <a href="#/articles/create">le premier article</a>?
</div>
</section>
ng-init : chargement des données à partir du contrôleur Angular, pour la vue détails
on utilse « findOne() »
<section ng-init="getAll()">
ng-repeat pour faire une boucle avec utilisation soit de directive « ng-bind » sur une
balise soit de variable avec accolades {{ }}
Liens
Pour afficher directement une vue
<a href="#/articles/create" class="btn btn-primary">Ajouter un nouvel
article</a>
Avec un paramètre
<a href="#/articles/view/{{ article._id }}" >{{ article.title }}</a>
Lien avec appel d’une fonction du contrôleur
<a class="btn btn-primary" ng-click="delete();">Supprimer</a>
Note ici Bootstrap met en forme le lien, mais on peut afficher le lien correctement
sans style en indiquant simplement « href » sans valeur. Exemple
<a href ng-click="delete();">Supprimer</a>
![Page 48: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/48.jpg)
48
Localisation des dates
Documentation avec Angular pour les dates
Copier le fichier dans la langue désirée et le référencer. Les dates avec filtres par
exemple seront automatiquement localisées.
{{ article.created | date:'mediumDate' }}
Affichage du contenu au format HTML
Créer une directive dans un dossier « directives »
angular.module('core').directive('dynamic', ['$compile', function
($compile) {
return {
restrict: 'A',
replace: true,
link: function link(scope, ele, attrs) {
return scope.$watch(attrs.dynamic, function (html) {
ele.html(html);
return $compile(ele.contents())(scope);
});
}
};
}]);
Utilisation
<div dynamic="article.content" ></div>
![Page 49: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/49.jpg)
49
Formulaire <section>
<div class="page-header">
<h1>Ajouter un nouvel article</h1>
</div>
<div class="col-md-12">
<form name="articleForm" class="form-horizontal" ng-submit="create()" novalidate>
<fieldset>
<div class="form-group">
<label class="control-label" for="title">Titre</label>
<div class="controls">
<input name="title" type="text" ng-model="title" id="title"
class="form-control" placeholder="Saisissez votre titre ici" required>
</div>
</div>
<div class="form-group">
<div class="controls">
<div contenteditable ng-model="content" class="form-control
content-editable"></div>
</div>
</div>
<div class="form-group">
<input type="submit" class="btn btn-default" value="Publier">
</div>
<div ng-show="error" class="text-danger">
<strong ng-bind="error"></strong>
</div>
</fieldset>
</form>
</div>
</section>
ng-submit sur la balise form pointe la fonction du contrôleur permettant de valider
l’ajout, la modification du formulaire.
Une variante consiste à utiliser ng-click sur le bouton submit
ng-model pour binder les valeurs en édition du formulaire
Afficher un message d’erreur
<div ng-show="error" class="text-danger">
<strong ng-bind="error"></strong>
</div>
![Page 50: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/50.jpg)
50
Permettre de sauvegarder le contenu formaté en html dans une base MongoDB
Création d’une directive
angular.module('core').directive("contenteditable", function() {
return {
restrict: "A",
require: "ngModel",
link: function(scope, element, attrs, ngModel) {
function read() {
ngModel.$setViewValue(element.html());
}
ngModel.$render = function() {
element.html(ngModel.$viewValue || "");
};
element.bind("blur keyup change", function() {
scope.$apply(read);
});
}
};
});
Utilisation
<div contenteditable ng-model="article.content"></div>
On peut mettre en forme ce bloc avec Bootstrap par exemple
<div contenteditable ng-model="article.content" class="form-control
content-editable"></div>
Et ajouter une classe CSS simple
.content-editable{ height: 250px; overflow: auto;}
On peut imaginer créer une barre permettant de mettre en forme, insérer des
images, etc. un peu comme un « tinyMCE »
Une div éditable avec
l’illusion que c’est un
textarea
![Page 51: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/51.jpg)
51
2. Partie Serveur
a. Routes côté serveur
Il faut renseigner les routes dans « routes.js » du dossier « config » du « server »
var articleController = require('../controllers/articleController'),
auth = require('../controllers/authController');
module.exports = function (app) {
app.get('/api/articles/', articleController.list);
app.get('/api/articles/:id', articleController.read);
app.post('/api/articles/', articleController.create);
app.put('/api/articles/', articleController.update);
app.delete('/api/articles/:id', articleController.delete);
// etc.
}
b. Modèle Mongoose
Dans un dossier « models » du « server »
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var articleSchema = new Schema({
title: {type:String, required:'Vous devez renseigner un titre'},
content: {type:String, required:'Votre article n\'a aucun contenu.'},
user : { type: Schema.ObjectId, ref: 'User' },
created: {type: Date, default: Date.now }
});
var Article = mongoose.model('Article', articleSchema);
Ajouter les routes
Créer un contrôleur
pour mettre à jour la
base de données
Créer un modèle
Mongoose
![Page 52: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/52.jpg)
52
Modèle avec relation
Pour “user” on indique le nom du schéma en relation
user : { type: Schema.ObjectId, ref: 'User' },
L’élément “user” sera chargé depuis le contrôleur grâce à la function “populate”
exports.list = function (req, res) {
Article.find().sort('-created').populate('user').exec(function (err, articles) {
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
res.json(articles);
}
});
};
![Page 53: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/53.jpg)
53
c. Contrôleur « Express »
C’est lui qui va recevoir des requêtes depuis le service Angular et renvoyer les
réponses au format JSON
var mongoose = require('mongoose'),
Article = mongoose.model('Article'),
errorHandler = require('./errorHandler');
exports.list = function (req, res) {
Article.find().sort('-created').populate('user').exec(function (err, articles) {
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
res.json(articles);
}
});
};
exports.read = function (req,res){
Article.findOne({ _id: req.params.id }).populate('user').exec(function (err,
article) {
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
res.json(article);
}
});
};
exports.create = function (req, res) {
var article = new Article(req.body);
article.user = req.user || req.session.passport.user;
article.save(function(err){
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
res.json(article);
}
});
};
exports.update = function (req, res) {
Article.update({ _id: req.body._id }, { $set: { title: req.body.title, content:
req.body.content } },
function (err) {
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
res.json(req.body);
}
});
![Page 54: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/54.jpg)
54
};
exports.delete = function (req, res) {
Article.remove({ _id: req.params.id }, function (err) {
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
res.send('Ok')
}
});
};
![Page 55: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/55.jpg)
55
VII. Plus …
1. Express
a. Variables partagées var express = require('express'),
app = express();
app.locals.pageTitle="Ma variable";
Pas besoin de passer la variable pour pouvoir l’afficher dans la vue. Exemple avec
ejs
<h1><%= pageTitle %></h1>
b. Charger un fichier JSON
On charge simplement un fichier json
app.locals.customers = require("./customers.json");
Le contenu du fichier “customers.json”
[
{"name":"M. PILLON","email":"[email protected]"},
{"name":"M. BELLIN","email":"[email protected]"}
]
Exemple avec ejs
<ul>
<% customers.forEach(function(customer){ %>
<li><%= customers.name %></li>
<% }) %>
</ul>
c. Changer le répertoire des vues app.set('views', __dirname + '/views');
d. Ressources (dossier « public »)
app.use(express.static(__dirname + "/public"));
Utilisation d’une ressource
<link href="/css/default.css" rel="stylesheet" />
Référencer le répertoire « public » de
l’application
Dans un dossier « public »
Inutile d’indiquer le répertoire « public »
![Page 56: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/56.jpg)
56
e. Express Generator
Créer un projet avec Express generator
Installer express generator en global
npm install express-generator -g
Naviguer jusqu’au dossier parent qui contiendra le du projet puis
express nomprojet
Installation des dépendances du projet généré : Naviguer jusqu’au dossier du projet
généré puis
npm install
Lancer le serveur
node bin/www
On peut se rendre à la page « http://localhost:3000/ »
![Page 57: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/57.jpg)
57
2. “Sans Express”
a. Serveur
b. Créer un serveur (fichier « server.js » ou « app.js » par exemple)
var http = require('http'); var html = "<!DOCTYPE html><html><head><meta charset=\"utf-8\" /><title>Demo NodeJS</title></head><body><h1>Démonstration NodeJS</h1></body></html>"; var server = http.createServer(function (req, res) { res.writeHead(200, { "Content-Type": "text/html" }); res.write(html); res.end(); }); server.listen(8080); console.log("listen on port 8080");
b. Lancer un serveur :
Depuis une invite de commande, naviguer jusqu’au dossier
du projet puis
node server.js
c. Aller à « http://localhost:8080/ » pour tester
(CTRL + C pour arrêter le serveur)
c. URL et paramètres
Paramètres d’url (querystring)
var http = require('http'); var url = require('url'); var querystring = require('querystring'); var server = http.createServer(function (req, res) { var params = querystring.parse(url.parse(req.url).query); res.writeHead(200, { "Content-Type": "text/plain" }); if ('firstname' in params && 'lastname' in params) { res.write('Hello ' + params['firstname'] + ' !'); } else { } res.end(); }); server.listen(8080);
Réponse. Types de contenu :
Texte : text/plain
HTML : text/html
CSS : text/css
Image : image/jpeg
Vidéo : video/mp4
Zip : application/zip
Etc.
Création du serveur
« req » pour request,
« res » pour response
Chargement du module « http »
Port 3000 ou 8080 en local
Besoin du module
« querystring » pour récupérer
les paramètres dans l’url
Récupération des paramètres
passés dans un tableau
Accès aux membres du tableau
de paramètres
![Page 58: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/58.jpg)
58
d. Créer un index listant les contrôleurs (function (controllers) { var homeController = require('./homeController.js'); var contactController = require('./contactController.js'); controllers.init = function (app) { homeController.init(app); contactController.init(app); } })(module.exports);
Utilisation
var express = require('express'), app = express(), controllers = require('./controllers'); app.set("view engine", "vash"); controllers.init(app); app.listen(8080);
e. Evénements
Ecouter et émettre des événements
var eventEmitter = require('events').EventEmitter; var myEvent = new eventEmitter(); myEvent.on('myEventEmittted', function (message) { console.log(message); }); myEvent.emit('myEventEmittted', 'Evénement déclenché');
On indique le dossier
contenant les contrôleurs
Initialisation des contrôleurs en
appelant la méthode
Besoin du module « events »
On écoute l’événement, avec fonction callback
![Page 59: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/59.jpg)
59
3. Bases de données
a. SQL Server
Plusieurs Drivers existent… Exemple avec Tedious (documentation)
npm install tedious
Note : il faut lancer SQL Browser
var Connection = require('tedious').Connection; var Request = require('tedious').Request; exports.getAll = function (req, res) { var config = { server: 'DonJR', userName: 'sa', password: 'password123456' , database: 'peopledb', options : { instanceName: 'SqlExpress', rowCollectonOnRequestCompletion: 'true' } } var connection = new Connection(config); connection.on('connect', function (err) { if (err) { console.log("Erreur"); } else { var request = new Request("use peopledb; select * from Person", function (err, rowCount, columns) { var result = []; columns.forEach(function (column) { var person = new Person(column[1].value, column[2].value); result.push(person); }); res.render('index.ejs', { people: result }); }); connection.execSql(request); } }); };
Autre exemple avec paramètres
var TYPES = require('tedious').TYPES; var sql = 'use peopledb; insert into Person(name,twitter) values(@name,@twitter);'; var request = new Request(sql, function (err) { console.log("Erreur"); }); request.addParameter('name', TYPES.VarChar, 'M. Bellin'); request.addParameter('twitter', TYPES.VarChar, '@mbellin'); connection.execSql(request);
Nom du serveur, indiquer le
nom de l’instance
(instanceName) dans
« options ».
« rowCompletionOnRequestCompletion »
permet de récupérer le résultat de la
requête en callback
Exécution de la
requête
Paramètres
![Page 60: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/60.jpg)
60
b. MongoDB
Autres bases NoSQL : RavenDB, Cassandra, Neo4j, Redis, CouchDB
Installation locale au projet avec Windows
a. Télécharger le zip de MongoDB (ou le msi et choisir le dossier du projet
pourl’installation)
b. Créer un dossier « mongodb » dans le projet et y copier l’ensemble de
l’archive
c. Créer un dossier « data » dans « mongodb »
d. Ouvrir une invite de commande, naviguer jusqu’au dossier « mongodb » du
projet et indiquer le dossier dans lequel la base est installée
mongod –dbpath ./data
(Un message « waiting for connections on port 27017 » apparait si tout se passe bien)
Pour avoir accès aux bases depuis « http://localhost:28017 »
mongod –dbpath ./data --rest
![Page 61: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/61.jpg)
61
Créer une base en invite de commandes
Une base de données NoSQL a des collections. Chaque collection a des documents
(JSON), « schemaless » (par exemple un document peut avoir seulement un nom et
un autre avoir un nom et un email)
Créer ou utiliser une base
use peopledb
Insertion d’un document dans une collection
db.people.insert({name:"J. Romagny", twitter:"@romagny13"})
Un identifiant unique est ajouté à chaque document (_id)
Obtenir un document
Utilisation de la méthode « find »
Retourner tous les documents de la collection
db.people.find()
Filtrer les résultats
$gt : plus grand
$lt : plus petit
$gte : plus grand ou égal
$lte: plus petit ou égal
$or : ou
$and : et
$in, $all, $exist, $type ,$regex
db.people.find({name : "J. Romagny"})
db.people.find({age : {$gt :18}})
Trier
Avec la méthode « sort »
db.people.find().sort({name :1})
Modification de document
db.people.update({name : "J. Romagny"}, {$set :{twitter : "@jerome_romagny13"}})
Supprimer un document
db.people.remove ({name : "J. Romagny"})
$unset permet de supprimer une propriété du document
Collection Document
Modification de la propriété « twitter » Filtre des documents recherchés Méthode « update »
Tri de la collection de personnes sur le nom en ordre
croissant
Pour un ordre décroissant utiliser « -1 »
![Page 62: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/62.jpg)
62
VIII. MEAN.JS MEAN = MongoDB + Express + AngularJS + Node.js
Documentation
Installation
a. Pré-requis
Node.js et NPM
MongoDB
Bower
Grunt
b. Installation avec Yo
Installation de Yeoman en global
npm install -g yo
Installation du generator meanjs
npm install -g generator-meanjs
Puis création d’un projet MEAN …Naviguer jusqu’au dossier où créer le projet avec la
commande puis
yo meanjs
Répondre aux questions… donner un nom à l’application …
c. Une fois le projet généré. Installer tous les modules avec la commande
npm install
Lancer MongoDB. Depuis une invite de commande, naviguer jusqu’au dossier
d’installation puis
mongod
Et lancer le serveur. Depuis une invite de commande naviguer jusqu’au projet mean
et
grunt
Ou simplement
node server.js
![Page 63: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/63.jpg)
63
Le projet généré
Configuration
Serveur
Package avec informations du
projet et dépendances
Chaque module est divisé avec une partie
client (Angular) et une partie serveur (Node)
Librairies installées avec NPM
![Page 64: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/64.jpg)
64
Exemple de module (« users » pour l’authentification, utilise Passport)
Moteur de vues utilisé Swig
Les vues sont dans la partie « client » des modules
Le layout, la page index, pages « complètes » sont dans la partie « server »
Le module core
Client
Contient le fichier de config permettant d’enregistrer des modules pour
l’application
Fichier init qui permet également d’intercepter au changement d’état et
vérifier l’autorisation. Des rôles sont définis pour les états et c’est par rapport à
ceux-ci que l’on vérifie si l’utilisateur a les droits pour accéder au prochain
état. S’il n’est pas autorisé, l’utilisateur est redirigé vers la page
d’authentification.
Routes avec $stateProvider avec les vues home, 404, un fichier pour les routes
admin
Contient également le header avec le menu principale inclus dans le layout
du site
Un contrôleur pour le header (avec le service « Authentication » pour switcher
entre utilisateur connecté et anonyme) et un contrôleur pour la vue home
Feuille de style core.css, images (favicon,logo)
Un service pour le menu
Server
Routes pour page index (‘/’) et pages not found,etc.
Le contrôleur ne sert qu’à afficher les pages index, not found,etc.
Le layout, la page index, pages « complètes » (404,500)
![Page 65: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/65.jpg)
65
Génération de code Documentation
Création d’un module MEAN
yo meanjs:mean-module
Server … « Express »
Création d’un contrôleur côté serveur avec crud (create, read, update,
delete, list)
yo meanjs:express-controller
Choisir le module (exemple « voyages ») puis donner un nom au contrôleur
Modèle pour Mongoose
yo meanjs:express-model
Choix du module et nom du modèle
Routes pour le module
yo meanjs:express-route
Choix du module et nom du fichier de routes
Client … « Angular »
Contrôleur Angular
yo meanjs:angular-controller
Choix du module et nom du contrôleur
Routes Angular avec $stateProvider
yo meanjs:angular-route
Choix du module, nom, …
Vue
yo meanjs:angular-view
Choix du module, nom de la vue, du contrôleur, routes
Exemple de module généré nommé « voyage »
![Page 66: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/66.jpg)
66
Angular
« Express »
![Page 67: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/67.jpg)
67
IX. Publication Heroku
1. Créer un compte
2. Créer une nouvelle application
3. Donner un nom d’application
![Page 68: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/68.jpg)
68
4. Plusieurs méthodes de déploiement disponibles
Publication du projet
1. « package.json »
{
"name": "NodejsAuthDemo",
"version": "0.0.0",
"description": "NodejsAuthDemo",
"main": "server.js",
"author": {
"name": "romagny13",
"email": ""
},
"engines": {
"node": "0.12.x",
"npm": "2.7.x"
},
"dependencies": {
"body-parser": "^1.12.3",
"ejs": "^2.3.1",
"express": "^4.12.3",
"mongoose": "^4.0.2",
"passport": "^0.2.1",
"passport-local": "^1.0.0"
}
}
2. « procfile.js »
Créer un fichier « procfile.js » à la racine du projet et y ajouter le nom du serveur
web: node app.js
Ajouter une section « engines » avec les
versions de node et npm
… que l’on peut obtenir avec « node --
version » et « npm --version »).
![Page 69: 1 Applications avec Node.js Angular et MEAN](https://reader031.fdocuments.net/reader031/viewer/2022012022/6169bc8c11a7b741a34acab5/html5/thumbnails/69.jpg)
69
3. Dans le serveur « server.js » ou « app.js » selon le nom donné, modifier le port
var port = process.env.PORT || 3000;
app.listen(port);
console.log("Listen on " + port + "...");
4. MongoDB addons (option « free » mais demande quand même de rentrer des
informations de paiement)
Permet de créer une base. On obtient également les informations de connexion
(Créer un utilisateur minimum) et modifier la chaine de connexion dans le projet.
mongoose.connect('mongodb://………);
Port de test