[Java + AngularJS] Une application de gestion d’élèves partagée avec Eclipse, AngularJs et Java,Jersey,Maven + Mysql en Back end. Un Français Intégral pour ce système CRUD à Services WEB!

maisonSommaire


  • Introduction
  • Une photo de la micro application
  • Le but de l’application
  • Le matériel nécessaire
  • Les liens utiles en Anglais
  • On crée le projet dans Eclipse
  • On construit le Front End
  • On crée notre table SQL  » eleves »
  • On crée notre classe Pojo « eleve »
  • On construit la classe Back End des Web Services CRUD (Lire, Créer, Editer, Supprimer)
  • On construit la classe Back End DAO(Data Access Object) qui actionne MYSQL
  • On construit la classe connexion qui permet la connexion à la base  de données.
  • On teste l’application
  • Points non traités dans cette doc.
  • Conclusion .

Introduction javalogo-mysql-170x170_400x400angularjs


Vous l’attendiez depuis longtemps, voici enfin une micro-application CRUD (Lire, Créer, Editer, Supprimer) totalement exposée, en Français intégral, combinant  Angularjs en Front End, et Java en Back end, le tout pointant sur une base de données relationelle  Mysql.

L’autre nom utilisé pour cette technologie Back end serveur est « Service Web » ou « Web Services » en Anglais.

Elaborée suite à l’analyse de plusieurs forums en Anglais, cette solution entièrement Francophone est simple et robuste et s’ajoute aux solutions Full Stack AngularJs + Php Sql(Le système le plus fiable et clair) ainsi que Angularjs + noSql

Avec cette solution, on bénéficie d’une part de l’organisation très structurée de Java pour le Back End avec les classes, et d’autre part  de la facilité d’AngularJS ( Avec par exemple le Super 2 ways binding et la multitude de librairies Front end de AngularJs pour le front end).

Java étant très utilisé dans l’embarqué, cette technique permet une communication optimisée entre le navigateur et divers matériels (Domotique, robotique etc …)

Ceci nous donne un couple gagnant pour les applications à sgbd relationels. AngularJs étant d’une flexibilité et d’une simplicité extrême. Aucune limitation dans ce système, Jointures SQL, librairiesde type NVD3.js pour les graphes, Bootstrap pour les CSS, Elaboration de Statistiques  et j’en passe !

exp Comme d’habitude, j’utilise les mots les plus simples ainsi que l’état initial des choses pour expliquer le fonctionnement de cette micro application, cependant, les concepts sont ensuite expandables à l’infini pour de grosses applications complexes.

Il faut rappeler qu’un CRUD se doit d’être réduit à sa plus simple expression lorsqu’il est expliqué, ainsi qu’à ses 4 fonctions primaires :

Lire, Créer, Editer, Supprimer.

Une photo de la micro application


 microapp.jpg

Lire la suite

#7f4614, #a65b1a, #bf691e, #d9cfb8, #f0e5cc, #fff, #ffffff

[AngularJs + PHP BackEnd] Gérer des filtres redondants

Introduction :

Post non finalisé très important , concernant la concaténation de filtres redondants dans le back end.
On peut en effet concaténer une requête SQL à des filtres contenus dans une autre fonction, c’est incroyablement utile lorsque l’on a affaire à des filtres redondants dans plusieurs applications .

J’écrirais ici ma méthode pour gérer les filtres redondants. Lorsque l’on désire coller un AND dans une requête, soumise aux critères provenant du front end, cette méthode est trop bien.
Pour l’instant c’est ici :

http://stackoverflow.com/questions/41720715/glue-a-redondant-php-code-into-several-functions

avec un exemple :

function filter($data) {
$requete =  »;
if($data->secteur){
$requete .=  » AND etude.Secteur = ‘ ».$data->secteur. »‘ »;
}
if($data->region){
$requete .=  » AND etude.region = ‘ ».$data->region. »‘ »;
}
if($data->ca_min){
$requete .=  » AND etude.ca >= « .$data->ca_min. » »;
}
if($data->ca_max){
$requete .=  » AND etude.ca ca_max. » »;
}
if($data->revenus_min){
$requete .=  » AND Zone.Revenue_Zone >= ».$data->revenus_min. » »;
}
if($data->revenus_max){
$requete .=  » AND Zone.Revenue_Zone revenus_max. » »;
}
return $requete;
}

puis, pour s’en servir dans n’importe quelle function :
$requete .= filter($data);

[AngularJs + PHP] Créer des filtres dans le back-end avec des requêtes SQL additives, pour trier des coureurs cyclistes par groupes.

php_1_angularjs

Introduction


Avec AngularJs, lorsque l’on liste plus de 2000 objets, cela devient difficile en terme de performances, de calculer les filtres avec le front end, ce qui est normal.

En d’autres termes, admettons que j’ai 5000 coureurs cyclistes à trier par un critère, il faut alors le faire dans le back end avec SQL, bien que le tri par colonne d’angularJS fonctionne encore. Ceci pour soulager grandement le front-end, et pour plus de confort utilisateur.

On doit filtrer dans le Back end, afin que le navigateur ne rame pas.

Pour cela, on ajoute des « morceaux de requêtes SQL » de type WHERE la plupart du temps, en fonction de ce que l’utilisateur va choisir dans les menus déroulants des filtres.

A noter que le système est identique, dans l’esprit, avec du Jquery Ajax, mais la syntaxe sera légèrement différente. Anoter aussi que ce système est relativement similaire dans l’esprit à des scripts en VBA que j’avais vu en professionel, ce qui indique qu’il est conforme dans l’esprit.

Il faut bien comprendre que les critères doivent être additifs, qu’il y ait 1 critère de choisi ou 15 de choisis. Autrement dit, je veux pouvoir utiliser 15 filtres en même temps si j’en ai envie … Avec cette technique, c’est possible et cela fonctionne !

POUR TESTER LA MINI APPLICATION CLIQUER ICI

Sommaire



  1. Création de la table SQL coureurs
  2. Mise en place basique d’une application AngularJS avec un tableau de coureurs cyclistes.
  3. Ajout de la vue des 2 filtres : Ville et Groupe.
  4. Ajout des requêtes AJAX (liste des cyclistes et liste pour les filtres)
  5. Elaboration du fichier back end en PHP MYSQL qui convertit et envoie le tout au format JSON.
  6. Conclusion.
  7. Annexe : Code pour Postgre.

Création de la table SQL coureurs

On crée la table suivante dans MYSQl :

CREATE TABLE `test`.`coureurs` (
`id` INT NOT NULL AUTO_INCREMENT,
`nom` VARCHAR(45) NULL,
`prenom` VARCHAR(45) NULL,
`ville` VARCHAR(45) NULL,
`groupe` VARCHAR(45) NULL,
PRIMARY KEY (`id`));

On la remplit avec des données bateau :

LOCK TABLES `coureurs` WRITE;
/*!40000 ALTER TABLE `coureurs` DISABLE KEYS */;
INSERT INTO `coureurs` VALUES (1,'Durand','Henri','Marseille','junior'),(2,'Levy','Patrick','Lille','junior'),(3,'José','Conzola','Marseilles','anciens'),(4,'Shivaa','roberto','Marseilles','junior');
/*!40000 ALTER TABLE `coureurs` ENABLE KEYS */;
UNLOCK TABLES;

Voilà, rien de plus à faire, si ce n’est remarquer la présence des groupe junior et anciens, et les villes. Ce sont ces critères qui vont nous servir à filtrer notre liste.

Mise en place basique d’une application AngularJS avec un tableau de coureurs cyclistes.

Comme d’hab on créée un arborescence de ce type sur notre serveur web :

liste1.jpg

Je n’ai pas inclus de module de routing de vues pour cet exercice.

  • Le répertoire backend contient les fichiers qui gèrent les opérations PHP-MYSQL
  • Le répertoire bower_component permet de télécharger et gérer les versions des modules optionnels (non utilisé dans cet exo) ou de télécharger bootstrap par exemple. Bower est un logiciel optionnel.)
  • Le répertoire css contient le fichier css de l’application.
  • Le répertoire js contient le code js et angularjs dans un seul fichier app.js pour cet exercice.

Voici la « vue  » principale : index.html, qui charge les libriairies, et affiche la table des coureurs cyclistes. En bas, on peut constater la présence de la vue filtres, qui peut être inclue à loisir dans d’autres vues. Normalement, la vue filtre devrait être dans un répetoire vues contenant toutes les vues.


<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Neutre</title>
    <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
		<!-- CHARGEMENT DES LIBRAIRIES -->
		
		<!-- JQUERY ET BOOTSRAP -->
        <script src="bower_components/jquery/dist/jquery.min.js"></script>
        <script src="bower_components/bootstrap/dist/js/bootstrap.min.js"></script>
        <link rel="stylesheet" type="text/css" href="bower_components/bootstrap/dist/css/bootstrap.min.css">
		<link rel="stylesheet" href="bower_components/font-awesome/css/font-awesome.min.css" type="text/css">
 
        <!-- ANGULARJS -->
        <script src='bower_components/angular/angular.min.js'></script>
		
		<!-- APPLICATION PERSO -->
		<script src="js/app.js"></script> <!-- Contient pour l'exemple le controleur et les appels aux modules. -->
		<link rel="stylesheet" type="text/css" href="css/style.css">
		
		<!-- FIN DE CHARGEMENT DES LIBRAIRIES -->
  </head>

<body ng-app="neutre" ng-controller="neutreCtrl">
	
	<!-- BARRE DE NAVIGATION -->
	<nav class="navbar navbar-inverse">
		<div class="container-fluid">
			<!-- for better mobile affichage-->
			<div class="navbar-header">
				<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
					<span class="sr-only">Toggle navigation</span>
				</button>
				<a class="navbar-brand" href="#">Neutre</a>
			</div>
			<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
			</div><!-- /.navbar-collapse -->
		</div><!-- /.container-fluid -->
	</nav>
	
	
	<!-- VUE UNIQUE  -->
	<div class="row ">
		<div class="col-lg-8 " >
			 <div class="panel panel panel-warning">
				
				<div class="panel-heading"> 
					<i class="fa fa-picture-o"></i> Liste
				</div>
				
				<div class="panel-body table-responsive" style="min-height:350px;" ng-show="!collapsed" >
					
					<table  class="table table-bordered table-hover  " border="1"  >
						<thead fix-head>
						  <tr> 
							<th>Nom</th>
							<th>Prénom</th>
							<th>Ville</th>
							<th>Groupe</th>
						  </tr>
						</thead>
			 
						<tbody >
						  <tr  ng-repeat="coureur in coureurs"   >
							 <td>{{coureur.nom}}</td>
							 <td >{{coureur.prenom}}</td>
							 <td >{{coureur.ville}}</td>
							 <td >{{coureur.groupe}}</td>
							 <td ><button class="btn btn-primary">Fiche</button></td>
						  </tr>
						</tbody>
					</table>
				
				</div>
				
				<div class="panel-footer ">
				</div>
				
			 </div>
		</div>
		
		<!-- VUE DES FILTRES -->
		<div class="col-lg-4 " ng-include="'filtres.html'" ></div>
	</div>
		

</body>
</html>

Ajout de la vue des 2 filtres : Ville et Groupe.

Les filtres sont des select HTML qui seront alimentés par des requêtes SQL AJAX $http :

Voici la vue des filtres filtres.html, remarquer $parent qui permet au controleur de la vue principale de récupérer les variables ng-model correctement :

         <div class="panel panel-warning">
 
            <div class="panel-heading">
                <span class="glyphicon glyphicon-filter" aria-hidden="true"></span>  Filtres 
            </div>
 
            <div  class="panel-body " > <!-- TOUS LES FILTRES  -->
			
				<select ng-model="$parent.filtres.ville" class="form-control">
					<option value="">Villes</option>
					<option ng-repeat="ville in $parent.villes | orderBy:'villes'" value="{{ville.nom}}">{{ville.nom}}</option>
				</select><br> 
				
            
				<select ng-model="$parent.filtres.groupe" class="form-control">
					<option value="">Groupe</option>
					<option ng-repeat="groupe in $parent.groupes | orderBy:'groupe'" value="{{groupe.nom}}">{{groupe.nom}}</option>
				</select><br>
			
			</div>
 
			<div class="panel-footer text-right">
			</div>
 
         </div>

Voilà, à ce stade on a ce look dans le navigateur :

rqtsadditives1.jpg

Ajout des requêtes AJAX (liste des cyclistes et liste pour les filtres)

Voici le fichier app.js qui contient mon controleur des vues précédentes, qui va lancer des requêtes AJAX  et récupérer des données:

  • Une requête ajax qui remplit le tableau des coureurs cyclistes ( Celle ci est relancée lors de chaque nouveau choix d’un critère par un utilisateur grâce à $watch() de angular. La requête Ajax contient alors en paramêtres les critères choisis par l’utilisateur, pour que le back end PHP crée à la volée la bonne requête SQL puis retourne les données au format JSON dans la fonction de rappel de la requête Ajax $http.
  • 2 Requêtes Ajax qui remplissent tout simplement les filtres (Listes de critères), Le Back end php retourne alors une requête SQL de type de DISTINCT pour éliminer les doublons.
angular.module('neutre', [])

.controller('neutreCtrl', function($scope,$http) {

	$scope.filtres 		= {}; 	// L'objet filtre contient en temps réel les choix de l'utilisateur, dans la vue filtres.html

	/* CHARGEMENT AJAX INITIAL DE LA LISTE DES COUREURS */
   $http.post('backend/backend.php?action=get_coureurs',$scope.filtres).success(function(data){
		$scope.coureurs = data;
	}).error(function(data){console.log(data);}).finally(function() {});

	/* CHARGEMENT DES LISTES DE FILTRES */

   /* CETTE REQUETE VA REMPLIR LE SELECT AVEC LES NOMS DES VILLES */
   $http.get('backend/backend.php?action=get_villes').success(function(data){
		$scope.villes = data;
	}).error(function(data){console.log(data);}).finally(function() {});

	/* CETTE REQUETE VA REMPLIR LE SELECT AVEC LES NOMS DES GROUPES */
   $http.get('backend/backend.php?action=get_groupes').success(function(data){
		$scope.groupes = data;
	}).error(function(data){console.log(data);}).finally(function() {});

	/* WATCHER DES FILTRES */
	/* ON RELANCE LE CHARGEMENT DU MODELE DE DONNEES DANS LE BACK END LORS DE CHAQUE CHANGEMENT DE FILTRES PAR L UTILISATEUR DANS LE NAVIGATEUR*/
	$scope.$watchCollection('filtres', function () {
		$http.post('backend/backend.php?action=get_coureurs',$scope.filtres).success(function(data){
			$scope.coureurs = data;
		}).error(function(data){ $scope.infos = data}).finally(function() {});

	});

/* FIN DU CONTROLEUR */
});

Remarque importante : $scope.filtres est un objet JSON qui stocke en temps réel les choix de l’utilisateur dans les select des filtres… C’est ça l’astuce parce que , lors de chaque choix, $scope.filtres est renvoyé au back end afin de recréer la requête SQL additive !!

Elaboration du fichier back end en PHP MYSQL qui convertit et envoie le tout au format JSON.

Le fichier backend.php permet de créer la requête SQL évolutive qui permet d’ajouter les critères de tri, indépendamment.

<?php

/* ---------------------------------------------BONJOUR BIENVENUE DANS LE BACK END EN PDO--------------------------------------------------  */
/* -------CE FICHIER PERMET A PHP D'EXECUTER DES REQUETES SQL ET DE LES ENVOYER AU FRONT END ANGULARJS OU JQUERY ENCODES EN JSON------------  */
/* --------------------------------------------IL PERMET DE FAIRE DU CRUD (CREE LIRE METTRE A JOUR SUPPRIMER -------------------------------  */


/* ---------------------------------------Paramêtres de connexion à la bdd et php--------------------------------  */
include('connexion_config.php');
header( 'content-type: text/html; charset=utf-8' );
error_reporting(E_ALL ^ E_NOTICE); // important pour ne pas afficher les notice PHP sans cela le script ne marche pas.
 

/* ------------------------Switch Case pour récupérer la l'action demandée par le controleur  AngularJs (appel $http ajax) ou par un appel ajax provenant de jquery-----------  */
 
switch($_GET['action'])  {
    case 'get_coureurs' 	:   get_coureurs();
    break;
	case 'get_villes' 		:   get_villes();
    break;
	case 'get_groupes' 		:   get_groupes();
    break;

}
 
 
/* ------------------------Fonctions qui récupère le résultat d'une requête SQL et encodent en JSON pour AngularJS ou Jquery qui le reçois dans la fonction de rappel des requêtes $HTPP ou les services -----------  */ 
 
function get_coureurs() {
	 
	  /* Récupération des données POST */
	 $data = json_decode(file_get_contents("php://input")); 

	try 
	{   
		$DB = connection();	
		
		/* Requête de base  */
		$sql = "SELECT * FROM coureurs WHERE 1=1";
		
		/* Requêtes Imbriquées à la requête de base avec les critères de filtres provenant du front end, on colle des morceaux de requêtes en fonction des critères*/
		if($data->ville){
			$sql .= " AND ville='".$data->ville."'";
		}
		if($data->groupe){
			$sql .= " AND groupe='".$data->groupe."'";
		}
		
		
		$data = $DB->query($sql);
		
		/* Convertit en JSON le résultat */    
		print_r(json_encode($data->fetchAll(PDO::FETCH_ASSOC)));
		
		/* ferme la connexion ? */
		$DB=null;
	}  
	catch(PDOException $e) 
	{
		file_put_contents('PDOErreurs.txt', $e->getMessage(), FILE_APPEND);  
	} 		
	
} 
 

/*  FONCTIONS QUI REMPLISSENT LES FILTRES */
function get_villes() {
	try 
	{   
		$DB = connection();	
		$data = $DB->query('SELECT distinct(ville) AS nom FROM coureurs');
		/* Convertit en JSON  */    
		print_r(json_encode($data->fetchAll(PDO::FETCH_ASSOC)));
		/* Ferme la connexion ? */
		$DB=null;
	}  
	catch(PDOException $e) 
	{
		file_put_contents('PDOErreurs.txt', $e->getMessage(), FILE_APPEND);  
	} 	
} 

function get_groupes() {
	try 
	{   
		$DB = connection();	
		$data = $DB->query('SELECT distinct(groupe) AS nom FROM coureurs');
		/* Convertit en JSON  */    
		print_r(json_encode($data->fetchAll(PDO::FETCH_ASSOC)));
		/* Ferme la connexion ? */
		$DB=null;
	}  
	catch(PDOException $e) 
	{
		file_put_contents('PDOErreurs.txt', $e->getMessage(), FILE_APPEND);  
	} 	
} 
 


?>

Bien sur ne pas oublier le script qui permet la connexion à mysql connexion_config.php:

<?php
function connection(){
    static $DBH;
	$DBH = new PDO('mysql:host=localhost;dbname=test', 'root', 'root');
          $DBH->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
		  /* $DBH->query("SET CHARACTER SET utf8"); */
	return $DBH;
}
?>

Conclusion.

Avec cette architecture, il nous est possible d’exploiter les formidables ressources angularJs et ses modules additionnels, ainsi que le super back end PHP, d’une manière très structurée, et facile à dépanner, tout semble logique. Je n’ai pas mentionné qu’il faut de préférence créer une factory angularJs pour les requêtes ajax parce que c’est facultatif.

Finalement, on a une application basée sur le framework AngularJs, mais on peut filtrer les données dans le back end si on a des soucis de performance.

Si on ne veut pas utiliser AngularJs, il est également possible de faire ecela avec Jquery Ajax.

Annexe : exemple de code Postgre.

Avec Post gre, le code du back end est un peu différent :

Voici un exemple RANDOM de fonction qui retourne un resultat en tenant compte des requêtes additives :

function get_etudes() {
	// Récupère les critères des filtres provenant du front end.
	$data = json_decode(file_get_contents("php://input")); 
	
	/* Connexion à la base de données */
	$linkdb = connexion();
	
	/* Requête de base  */
	$select = "SELECT Etude.Identifiant AS Id_Etude,Enseignes.Nom AS EnseigneE,Id_CRM,Etude.Ville,Etude.Nom,Type_Etude.Nom AS TypeE,Etude.Date_Etude,Etude.CA,Etude.departement,Etude.region,Etude.secteur,Etude.surface,zone.population_zone,zone.foyer_zone FROM ((base.Etude LEFT JOIN base.Enseignes ON Etude.Enseigne=Enseignes.Identifiant) LEFT JOIN base.Type_Etude ON Etude.Type=Type_Etude.Identifiant)LEFT JOIN base.Zone ON Etude.Identifiant=Zone.Id_Etude WHERE Etude.Domaine='Alimentaire' " ;
	
	/* Requêtes Imbriquées à la requête de base avec les critères de filtres provenant du front end*/
	if($data->enseigne){
		$select .= " AND enseignes.nom='".$data->enseigne."'";
	}
	if($data->filtre_dpt){
		$select .= " AND etude.departement='".$data->filtre_dpt."'";
	}
	if($data->filtre_region){
		$select .= " AND etude.region='".$data->filtre_region."'";
	}
	if($data->filtre_secteur){
		$select .= " AND etude.secteur='".$data->filtre_secteur."'";
	}
	
	$select .= " ORDER BY Etude.Date_Etude DESC";

	$result = pg_query($linkdb, $select);
	
	if (!$result) {
	  echo "Une erreur est survenue.\n";
	  echo ($data->enseigne);
	  exit;
	}
	
	$arr = pg_fetch_all($result);
	print_r(json_encode($arr));
	pg_close($linkdb);
} 

et le fichier connexion_config pour se connecter :

<?php

function connexion(){
	session_start();

	$linkdb=pg_connect("host='192.168.0.234' port='5432' user='jojo' password='*!6SM*J9' dbname='coureurs'");

	if (!$linkdb) {
	  echo "Une erreur de connexion à la base de données s'est produite.\n";
	  exit;
	}
	
	return $linkdb;
}


?>


[AngularJs] Faire une factory AngularJs pour PHP-MYSQL : un intérêt limité.

angularjslogo-php

Introduction


J’ai fait une factory AngularJs pour gérer le back end PHP-MYSQL, MYSQL étant une base de données relationnelle, et donc très structurée et normée, ce qui est extrêmement appréciable, parfois, face à noSql.

Comme pré supposé, l’intérêt est assez limité, ça fait perdre du temps et le code n’est pas beaucoup simplifié.

La factory centralise certes les données, mais d’un autre côté, il faut écrire une chose de plus… Cela sert pour faire les tests unitaires aussi.

Du coup , il est fortement possible que je continue à faire mes appels AJAX avec $http dans les controleurs, lorsqu’il s’agit d’un back end PHP (Mais pas dans le cas d’une app en noSql).

Le but est toujours le même : Faire du CRUD : CREER, LIRE, METTRE A JOUR, SUPPRIMER

Lire la suite

[Application 61] Passage de l’ ancien Back End Php-Mysql à PDO Mysql.

logo-phppompestation

Introduction


Avec Php 7 , mysql_real_escape_string() est discontinué.

Je passe donc le back end au format PDO en 1h30 de temps.

Cela ne change rien à ma technique de copié-collé pour chaque CRUD ..

Note : On peut spécifier le typage de variables dans les insert et les update pour ajouter à la sécurité, mais là je ne le fais pas.

Note 2 : A la fin d’une action SQL,le back end peut renvoyer un message JSON au front end qui peut l’afficher directement dans le front end dans la fonction de rappel de AngularJs, c’est le json nommé « data » qui contiendra le message… J’ai mis un exemple :
print_r(json_encode(‘Procédure Back end Ok’));

Pourquoi utiliser PDO et les requêtes préparées ?


  • Les requêtes préparées empêchent les injections SQL (Pour tester, essayer de rentrer un quote ‘, cela ne passe pas, hi hi !)
  • PDO devient le standard avec mysqli, mais est mieux que mysqli

Schéma :


vues

Le nouveau code :


Présence de 2 fichiers :

  • 1 pour la connexion
  • 1 pour tout le back end qui récupère les datas du front end (AngularJs dans ce cas). tout le back end est centralisé dans un seul fichier.

Lire la suite

[ 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 .

Lire la suite

#todo-list

[MEAN] Créer une application MEAN

Introduction


Une bonne Méthode pour commencer avec MEAN.

(MongoDB, Express, Angular , Node).

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

C’est plus compliqué que de gérer Firebase , mais cela fonctionne.

Ce qui est génant avec  Firebase, c’est qu’on ne peut pas gérer son propre serveur pour faire du noSql, alors qu’avec MongoDb, on peut monter son propre serveur.

appppp

Comment faire ?



  • Installer MongoDb, s’assurer qu’il fonctionne avec le logiciel Mongovue :Sans titre 2.jpg
  • Installer la stack MEAN et suivre la méthode en Anglais.

Voici l’arborescence de l’application :

 

Sans titre 4.jpg

Sous le répertoire PUBLIC, on trouve le controleur angularJS core.js , et la vue principale index.html :

Sans titre 6

 

Le code :



Package.json, c’est ce qui permet d’installer les dépendances une fois qu’on la créé on lance une commande npm install dans le répertoire de l’app, et cela installe automatiquemeent toutes les dépendances, un peu comme bower :

{
"name" : "node-todo",
"version" : "0.0.0",
"description" : "Simple todo application.",
"main" : "server.js",
"author" : "Scotch",
"dependencies" : {
"body-parser" : "^1.4.3",
"express" : "^4.13.4",
"method-override": "^2.1.3",
"mongoose" : "^4.4.12",
"morgan" : "^1.1.1"
}
}

Server.js permet de configurer

. Les dépendences et libs annexes
. moongose qui se connecte à mongodb
. l’écoute du serveur http et sur quel port
. L’api qui gére les données sur mongoDb en fonction du nom du modèle de données

// server.js

    // 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/myapp');     // connect to mongoDB database on modulus.io

    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");
	
	
	
	 // definire le modèle de données qui s'apelle todo qui veut dire "chose à faire" =================
    var Todo = mongoose.model('Todo', {
        text : String
    });
	

	// routes ======================================================================
	
	// 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 tous les todo
    app.get('/api/todos', function(req, res) {

        // utiliser moongoose pour obtenir tous les todo dans la database
        Todo.find(function(err, todos) {

            // if there is an error retrieving, send the error. nothing after res.send(err) will execute
            if (err)
                res.send(err)

            res.json(todos); // Retourne tous les todo au format json
        });
    });

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

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

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

    });

    // supprimer un todo
    app.delete('/api/todos/:todo_id', function(req, res) {
        Todo.remove({
            _id : req.params.todo_id
        }, function(err, todo) {
            if (err)
                res.send(err);

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

	
	   

Core.js qui est le controleur de index.html :

// public/core.js
var scotchTodo = angular.module('scotchTodo', []);

function mainController($scope, $http) {
    $scope.formData = {};

    // Quand on exécute la page, montrer toutes les choses à faire
    $http.get('/api/todos')
        .success(function(data) {
            $scope.todos = data;
            console.log(data);
        })
        .error(function(data) {
            console.log('Error: ' + data);
        });

    // Quand on soumets le formulaire ajouter, transmettre la chose à faire à l'api node
    $scope.createTodo = function() {
        $http.post('/api/todos', $scope.formData)
            .success(function(data) {
                $scope.formData = {}; // Supprimer le contenu du formulaire pour que l'utilisateur puisse en utiliser un autre.
                $scope.todos = data;
                console.log(data);
            })
            .error(function(data) {
                console.log('Error: ' + data);
            });
    };

    // Supprimer une chose à faire après l'avoir vérifié.
    $scope.deleteTodo = function(id) {
        $http.delete('/api/todos/' + id)
            .success(function(data) {
                $scope.todos = data;
                console.log(data);
            })
            .error(function(data) {
                console.log('Error: ' + data);
            });
    };

}

Index.html qui est la vue principale:

<!-- index.html -->
<!doctype html>

<!-- ASSIGNER LE MODULE ANGULAR  -->
<html ng-app="scotchTodo">
<head>
    <!-- META -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1"><!-- OptimizeR la vue mobile -->

    <title>Node/Angular Todo App</title>

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

    <!-- LIBS -->
    <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 -->
    <script src="core.js"></script>

</head>
<!--  EXECUTER LE CONTROLLER AND OBTENIR TOUTES LES CHOSES A FAIRE -->
<body ng-controller="mainController">
    <div class="container">

        <!-- HEADER ET COMPTE DE CHOSES A FAIRE -->
        <div class="jumbotron text-center">
            <h1>J'ai plein de trucs à faire <span class="label label-info">{{ todos.length }}</span></h1>
        </div>

        <!-- LISTE DE CHOSES A FAIRE -->
        <div id="todo-list" class="row">
            <div class="col-sm-4 col-sm-offset-4">

                <!-- LOOPER SUR LES  TODOS IN $scope.todos -->
                <div class="checkbox" ng-repeat="todo in todos">
                    <label>
                        <input type="checkbox" ng-click="deleteTodo(todo._id)"> {{ todo.text }}
                    </label>
                </div>

            </div>
        </div>

        <!-- FORM POUR CREER UNE CHOSE A FAIRE -->
        <div id="todo-form" class="row">
            <div class="col-sm-8 col-sm-offset-2 text-center">
                <form>
                    <div class="form-group">

                        <!-- BIND THIS VALUE TO formData.text IN ANGULAR -->
                        <input type="text" class="form-control input-lg text-center" placeholder="Je veux un toutou" ng-model="formData.text">
                    </div>

                    <!-- createToDo() WILL CREATE NEW TODOS -->
                    <button type="submit" class="btn btn-primary btn-lg" ng-click="createTodo()">Ajouter</button>
                </form>
            </div>
        </div>

    </div>

</body>
</html>

#todo-list