[ Application 59 ]Une micro app Crud de gestion de chenil avec MEAN (node.js) en Français

7-Features-of-MEAN-Stack_785Introduction


Voici ma micro application permettant de faire du CRUD sur une liste de chien, avec la technologie MEAN.
Testée 100 % fonctionnelle

On peut donc créer, éditer, supprimer et lire les chiens.

Les chiens sont stockés sur notre base de données MONGODB en tant qu’objets JSON (Javascript object notation).

En back end, on a du MEAN, et en Front End, on a du AngularJs 1.5 et du CSS Bootstrap.

Le guide en anglais originel est situé ici :

https://scotch.io/tutorials/creating-a-single-page-todo-app-with-node-and-angular

La mise à jour d’un objet JSON est plus particulièrement traitée dans ce post, je m’en suis inspiré pour construire mon application :
https://scotch.io/tutorials/build-a-restful-api-using-node-and-express-4

J’essaye de le mettre sur Heroku ces jours ci, ou alors je monterais carrément un server mais ce n’est pas sur.

Photo de l’application


photofiltre

Pourquoi la technologie MEAN noSQL ?


C’est plus flexible que les bases de données relationnelles, lorsque l’on crée un nouveau champs HTML dans l’application, il n’y a pas besoin de remanier la base de données, celle ci prends en compte les nouveaux enregistrement JSON automatiquement..

Par rapport à Firebase et AngularFire, ce qui est bien c’est que l’on est plus dépendant d’eux pour le back end, mais ce qui est mal c’est qu’il y a 2 fois plus de code à taper .

Prérequis :


  • Télécharger puis Installer le serveur Mongodb. (La base de données)
  • Télécharger puis Installer la stack Mean (nodeJs, Npm) (NodeJs sera le serveur WEB, Npm est un gestionnaire d’applications qui télécharge des choses sur internet automatiquement et mets tout à jour)

Gérer le lancement et l’arrêt du SGBD Mongodb :

Sous Windows, une fois le serveur mongodb installé, on peut créer un batch nommé executerMongodb.batch comme ça pour le lancer à loisir sur le bureau windows:


c:\
cd /d c:\Program Files (x86)\MongoDB\Server\3.2\bin
mongod --storageEngine=mmapv1
pause

Voilà ce que ça donne sous windows :

mongoo

Puis un autre pour killer le process, lorsque l’on éteint l’ordinateur sinon, lors du reboot on a une erreur, et il faut alors renommer renommer mongod.lock pour que notre serveur puisse être relancé (dans C:\data\db) :


c:\
cd /d c:\Program Files (x86)\MongoDB\Server\3.2\bin
mongo --eval "db.getSiblingDB('admin').shutdownServer()"
pause

Pour tester notre serveur SGBD Mongodb :

Télécharger le logiciel MongoVue, créer une connexion sur localhost sur le port 27017 et ne pas spécifier d ‘identifiant.Si cela ne fonctionne pas c’est qu’on a pas encore créé de collection de data, mais notre code à venir va en créer une d’office automatiquement, c’est ça qui est génial avec le noSQL, les « tables » s’autogénérent.

Pour créer une collection en ligne de commande, consulter la doc MongoDb.

 gr

Ci dessus, j’ai créé une connexion nommée ZAD(on s’en fout du nom), qui pointe sur ma base de données appelée nod. Dans cette base de données nod, j’ai une collection d’objets JSON nommées chiens.
On peut voir que j’ai aussi une autre connexion appelée localhost(on s’en fout du nom, on peut mettre n’importe quoi tant que ça pointe sur 127.0.0.1), et qui contient une base de données nommée myapp qui contient une collection d’objets JSON nommée todos(qui veut dire  » à faire »)

Ci dessus, les  _ids sont générés automatiquement par mongoDb lors de l’ajout d’un objet JSON chien,
c’est pratique pour retrouver un objet ensuite ou en l’occurence un chien

Le code de mon application appChiens:


Créer un répertoire pour l’application WEB qui s’appelle appChiens 

Créer dans ce répertoire un fichier qui s’appelle package.json et y insérer ce code puis enregistrer :


{
"name" : "appChiens",
"version" : "0.0.0",
"description" : "Simple Application pour un chenil.",
"main" : "server.js",
"author" : "Nico",
"dependencies" : {
"body-parser" : "^1.4.3",
"express" : "^4.13.4",
"method-override": "^2.1.3",
"mongoose" : "^4.4.12",
"morgan" : "^1.1.1"
}
}

Avec la ligne de commande se rendre à la racine du repertoire  appChiens, puis taper npm install, Npm va installer auomatiquement dans le repertoire  node_module(quil crée) toutes les dépendances spécifiées dans package.json. Par exemple Moongoose qui permet de dialoguer avec notre database mongodb.

Ensuite, toujours à la racine du projet, créer le fichier server.js , c’est lui qui va opérer en tant que serveur WEB . A l’avenir, Pour lancer le serveur web, il faudra, toujours en ligne de commande, à la racine du rep  appChiens taper node server.js !

Dans le fichier server.js , on écrit tout ce code :


// server.js

    // TOUT LE SET UP========================
    var express  = require('express');
    var app      = express();                               // create our app w/ express
    var mongoose = require('mongoose');                     // mongoose for mongodb
    var morgan = require('morgan');                         // log requests to the console (express4)
    var bodyParser = require('body-parser');                // pull information from HTML POST (express4)
    var methodOverride = require('method-override');        // simulate DELETE and PUT (express4)

    // configuration =================

    mongoose.connect('mongodb://localhost/nod');     // Se connecter à notre serveur mongodb en local sur la base de donnees nod sans identifiant en anonyme

    app.use(express.static(__dirname + '/public'));                 // set the static files location /public/img will be /img for users
    app.use(morgan('dev'));                                         // log every request to the console
    app.use(bodyParser.urlencoded({'extended':'true'}));            // parse application/x-www-form-urlencoded
    app.use(bodyParser.json());                                     // parse application/json
    app.use(bodyParser.json({ type: 'application/vnd.api+json' })); // parse application/vnd.api+json as json
    app.use(methodOverride());

    // Le serveur va se mettre à écouter avec cette commande (Taper node server.js dans la ligne de commande windows, sous le bon répertoire) ======================================
    app.listen(8080);
    console.log("L app écoute sur le port 8080 dans les navigateurs");

     // Définir le modèle de données des chiens   on specifie ici chaque type et noms de variables presentes dans notre modele de donnees=================
    var Modele = mongoose.model('Chiens', {
        text : String,
		age : Number,
		photo : String
    });

    // routes : pas de routes pour linstant cest angularjs qui gere cela en front end ======================================================================

    // application -------------------------------------------------------------
    app.get('', function(req, res) {
        res.sendfile('./public/index.html'); //Charge la seule vue, c est angular qui s occupe du routing en front end
    });

    // api ---------------------------------------------------------------------

	// Obtenir la liste de tous les chiens
    app.get('/api/chiens', function(req, res) {

        // utiliser moongoose pour obtenir tous les chiens dans la base de données MONGODB
        Modele.find(function(err, chiens) {
			if(err){
				res.send(err);
			}
			res.json(chiens); // Retourne tous les chiens au format json
        });
    });

	// Créer un chien et retourner tous les chiens après création
    app.post('/api/chiens', function(req, res) {

        // create a dog ,information comes from AJAX request from Angular
        Modele.create({
            text : 	req.body.text,
			age : 	req.body.age,
			photo : req.body.photo,
            done : false
        }, function(err, todo) {
            if (err)
                res.send(err);

            // get and return all the chiens after you create another
            Modele.find(function(err, chiens) {
                if (err)
                    res.send(err)
                res.json(chiens);
            });
        });

    });

    // Supprimer un chien
    app.delete('/api/chiens/:todo_id', function(req, res) {
        Modele.remove({
            _id : req.params.todo_id
        }, function(err, todo) {
            if (err)
                res.send(err);

            // get and return all the chiens after you create another
            Modele.find(function(err, chiens) {
                if (err)
                    res.send(err)
                res.json(chiens);
            });
        });
    });

		// Obtenir 1 seul chien
    app.get('/api/chiens/:chien_id', function(req, res) {

        // utiliser moongoose
        Modele.find({
            _id : req.params.chien_id
        },function(err, chien) {
			if(err){
				res.send(err);
			}
			res.json(chien); // Retourne tous les chiens au format json
        });
    });

	 // Modif un chien et retourner tous les chiens après création
    app.put('/api/chiens/:chien_id', function(req, res) {

		 // Utiliser notre modele de donnees pour retrouver le chien  a laide de son _id genere par mongodb
		Modele.findById(req.params.chien_id
			, function(err, chien) {
				chien.text = req.body.text; // on recupere les donnees que le controleur angularjs a envoye et qui sont contenues dans req cest un objet json
				chien.photo = req.body.photo; // chien.photo est la variable actuelle dans mongodb, on la subtitue par la variable provenant de lobjet qui a ete emis par le controleur angularjs 

			// sauvegarder les modifications operees sur le chien
				chien.save(function(err) {
					if (err)
						res.send(err);

					// get and return all the chiens after you create another
					Modele.find(function(err, chiens) {
						if (err)
							res.send(err)
						res.json(chiens);
					});
				});
			});

    });

Au début du fichier server.js,  il y a la config générale, qui ne change généralement pas.

Mais après,

On a codé tout le CRUD qui permet d’ajouter des chiens, de les consulter et de les modifier. On peut bien voir qu’il y a un GET (Obtenir), un DELETE(supprimer), un PUT (modifier)

Généralement, req contient un objet json provenant de angularJs, c’est utile lors de l’update d’un chien..

chien_id contient un identifiant qui est généré automatiquement par mongodb lors de la création d’un chien, de ce fait on peut retrouver chaque chien unique pour éditer ou supprimer ensuite.

Voilà, c’est tout pour notre BACK END .

Maintenant, on va s’occuper du FRONT END :

Créer un dossier public à la racine du rep appChiens.

Voici ce que je trouve à la racine de public :

gngn

img-app contient les images de l’application

Index.html est notre seule fichier qui fait donc office de vue , il charge aussi les librairies front end angularJs et bootstrap ainsi qu’un module additionnel de angularJS angu-fixe -bla bla qui permet de laisser notre header d’une table html fixe.

core.js est notre controleur angularjs qui va nous permettre de faire du CRUD et de dialoguer avec notre fichier server.js dans le back end.

index.html :

<html ng-app="monApp">
<head>
    <!-- META -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1"><!-- Optimizer pour les mobiles  -->

    <title>Node/Angular Application de chiens</title>

    <!-- SCROLLS -->
    <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css"><!-- load bootstrap -->
    <style>
        html                    { overflow-y:scroll; }
        body                    { padding-top:50px; }
        #todo-list              { margin-bottom:30px; }
    </style>

    <!--Chargement des librairies -->
    <script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script><!-- load jquery -->
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.min.js"></script><!-- load angular -->
	<!-- ANGULAR angu-fixed-header-table -->
	<script src="angu-fixed-header-table.js"></script>
    <script src="core.js"></script>

</head>

<!-- On applique le controlleur angularjs à body-->
<body ng-controller="mainController">

	<div class="container">

        <!-- HEADER ET DECOMPTE DES CHIENS -->
        <div class="jumbotron text-center">
            <h1>Vos chiens <span class="label label-info">{{ chiens.length }}</span></h1>
        </div>

        <!-- LISTE DES CHIENS-->
        <div class="row" >

			<div class="col-md-8 ">

                <!-- FAIRE UNE BOUCLE SUR TOUS LES CHIENS DU MODELE DE DONNEES CHIENS ACQUERI PAR LE CONTROLEUR ANGULARJS -->

				<table fixed-header class="table table-bordered table-hover " style="width:100%;height:500px;" >
				<thead>
					<tr>
						<th>Photo</th>
						<th>Nom</th>
						<th>Age</th>
						<th>Gérer</th>
					</tr>
				</thead>
				<tbody >
						<tr ng-repeat="chien in chiens" >
							<td><img src="img-app/{{chien.photo}}" style="width:100px;height:100px;"></img></td>
							<td>{{ chien.text }} </td>
							<td>{{chien.age}} </td>
							<td>
								<button ng-click="supprimerChien(chien._id)" class="btn btn-primary btn-lg btn-block"> <span class=" glyphicon glyphicon-remove" aria-hidden="true"></span></button>
								<button  ng-click="getChien(chien._id)" class="btn btn-primary btn-lg btn-block"><span class=" glyphicon glyphicon-pencil" aria-hidden="true"></span></button>
							</td>
						</tr>
					</tbody>
				</table>
			</div>

			<!-- MODIFICATION OU AJOUT DUN CHIEN -->
			<div class="col-md-4 text-center">
                <form>
                    <div class="form-group">

                        <input type="text" class="form-control input-lg text-center" placeholder="Le nom de ton chien" ng-model="formData.text">
						<input type="text" class="form-control input-lg text-center" placeholder="Age" ng-model="formData.age">
						<input type="text" class="form-control input-lg text-center" placeholder="Photo" ng-model="formData.photo">
					</div>

                    <!-- APPELLE LES FONCTIONS DANS LE CONTROLEUR ANGULAR -->
                    <button type="submit" class="btn btn-primary btn-lg btn-block" ng-click="creerChien()" ng-show ="montreBtn1">Ajouter Un chien </button>
					<button type="submit" class="btn btn-primary btn-lg btn-block" ng-click="appliquerEdition()" ng-show ="montreBtn2">Appliquer l'édition du chien</button>
                </form>
            </div>

	   <!-- FIND DE ROW -->
	   </div>

	<!-- FIN DE CONT1AINER -->
    </div>

</body>
</html>

photofiltreEt le controleur core.js :


var monAppDeChiens = angular.module('monApp', ['anguFixedHeaderTable']);

function mainController($scope, $http) {

	$scope.formData = {}; // initialisation à  du formulaire d'ajout de chiens
	$scope.montreBtn1 = true; // Initialisation du boutton ajouter un chien sur montrer

	// Obtenir tous les chiens presents dans mongodb quand on initialise l application
    $http.get('/api/chiens/')
        .success(function(data) {
              $scope.chiens = data;
        })
        .error(function(data) {
            console.log('Error: ' + data);
        });

    // Transmettre l objet chien  appelé $scope.formData à l'api node pour créer un chien dans mongodb
    $scope.creerChien = function() {

		$http.post('/api/chiens', $scope.formData)
            .success(function(data) {
                $scope.formData = {}; // Supprimer le contenu du formulaire pour que lutilisateur puisse en utiliser un autre.
                $scope.chiens = data;
                console.log(data);
            })
            .error(function(data) {
                console.log('Error: ' + data);
            });
    };

    // Supprimer un chien dans mongodb.
    $scope.supprimerChien = function(id) {
        $http.delete('/api/chiens/' + id)
            .success(function(data) {
                $scope.chiens = data;
                console.log(data);
            })
            .error(function(data) {
                console.log('Error: ' + data);
            });
    };

	// Editer un chien :getChien charge les donnees d un seul chien dans le formulaire pour que lutilisateur puisse les modifier
    $scope.getChien = function(id) {
		$scope.montreBtn1 = false; // Cache le boutton de création d un chien
		$scope.montreBtn2 = true;// Montre le boutton de modification

        $http.get('/api/chiens/' + id)
            .success(function(data) {
                $scope.formData = data[0];
                console.log(data);
				console.log($scope.formData);
            })
            .error(function(data) {
                console.log('Error: ' + data);
            });
    };

	// Applique les modifications au chien qui a été édité en les enregistrant dans mongodb
    $scope.appliquerEdition = function() {

        $http.put('/api/chiens/' + $scope.formData._id, $scope.formData)
            .success(function(data) {
                $scope.formData = {}; // Supprimer le contenu du formulaire pour que lutilisateur puisse en utiliser un autre.
                $scope.chiens = data;

            })
            .error(function(data) {
                console.log('Error: ' + data);
            });
			$scope.montreBtn1 = true;
			$scope.montreBtn2 = false;
    };

}

Voilà, si je lance mon serveur en tapant node server.js, je vais dans le navigateur sous http://localhost:8080 et je vois mon application s’afficher.

Notre controleur AngularJS lance des requêtes $http en fonction des actions utilisateurs. Ces requêtes $http pointent sur les fonctions de notre api, présentes dans le fichier server.js. Ces fonctions présentes dans server.js vont dialoguer avec mongoDb et aussi lancer des fonctions de retour qui envoient des données JSON en callback au controleur AngularJs.

Au début il n’y a pas d’enregistrements, mais on peut peupler rapidement mongodb avec cette app de nouveaux chiens:

photofiltre

A remarquer la bonne astuce : Le bouton Appliquer l’édition du chien n’apparait que lorsque l’on a cliqué sur le stylet, puis il disparait une fois qu’on a éditer le chien ! C’est grâce à ng-show dans la vue et $scope.montreBtn1 = true ou $scope.montreBtn1 = false dans le controleur qui switche automatiquement…

Voilà, maintenant que l’on sait faire du CRUD sur un modèle de données au format JSON dans mongoDb, on peut créer tout ce qui nous passe par la tête ! A partir du moment ou l’on sait stocker nos objets JSON dans mongoDb, on est bien parti, et on n’est pas dépendant de Firebase !

Publicités

#todo-list