Micro App Angular numéro 8 : GestEmployés

Introduction:gest


 Jour 1 : 2h30 de code

Une micro appli Angular d’entrainement, pour travailler le filtrage en AngularJs.

Il s’agit d’une application de gestion de personnel, tout en temps réel.

On voit les statistiques se modifier en temps réel.

J’avais un peu assez des 2 autres applications parcequ’il y avait des maladresses dedans, alors je fais celle là un peu.

Cliquer ici pour la tester.

Plus du tout de Sql ni d’accès Bdd, c’est comme du Big Data, là je sauvegarde le modèle dans le navigateur avec WebStorage, mais je pourrais stocker le modèle sur mongoDb. Faut avouer que c’est assez simple. à ce stade.

Jour 2 : 3h30 de code

Finalement, j’ai bien re-travaillé le fonctionnement des filtres et en fait, c’est assez simple à la base de faire un filtre :

ETAPE  1 :Dans la vue, créer un Select qui va contenir le critère du filtre, exemple :


<select class="selectionner" data-ng-model="filtreCsp" ng-options="opt.csp as opt.csp for opt in personnes| unique:'csp'" >
 <option value="">Catégorie ...</option>
 </select>

Dans ce cas, je parcours le modèle personnes, à la recherche de toutes les CSP(catégories socio-professionelles), et j’ajoute un UNIQUE pour spécifier qu’il ne faut pas de doublons (un peu comme en sql)

ETAPE 2 :Ensuite, dans le ng-repeat, j’ajoute tout simplement ceci: filter:filtreCsp comme cela :


<tr ng-repeat="personne in personnes |filter:filtreCsp " >

Du coup, le filtre fonctionne automatiquement ! Il y a d’autres types de filtres que l’on peut faire autrement , lorsque le filtre est compliqué du style choisir le personnel entre 20 et 40 ans, il faut alors créer une fonction qui retourne le résultat., j’expliquerais plus tard comment faire.

pas eu le temps de mettre la fenêtre modale Bootstrap pour le picking de photos

Description


  • Type : Application front-end Web de type Saas.
  • Langage : Js, Angular,  Html 5.0, Css3.0
  • Format d’échanges de Données : JSON
  • Back-end : non.
  • Difficulté : +/+++++
  • Test avec jasmine : Non.
  • Durée de codage : 2h30
  • UML 2.0 : non.
  • Webstorage(stockage des données dans le navigateur) : oui
  • Gestion de la concurence : non.
  • Webservice : non.
  • Authentification : non.
  • Minification Grunt : non
  • Nodes.Js : non.
  • MongoDb : non.
  • Ambition Commerciale : non
  • Etude de Marché, Barrières commerciales  : non.

Le code à J+2:



<html ng-app="app8">
	<head>
		<meta charset="utf8" >
		<!-- -----------------------------------------------DEBUT DU CHARGEMENT DES LIBRAIRIES------------------------ -->
		
		<!--	APPEL LIB ANGULAR -->
		<script	type="text/javascript" 	src="angular-1.3.13/angular.min.js"></script>
		<script src="angular-filter.min.js"></script>
		<script src="librairies/angular-locale_fr-fr.js"></script>
	
		<!--	APPEL LIB BOOTSTRAP -->
		<script src="librairies/ui-bootstrap.min.js"></script>
		<link rel="stylesheet" href="librairies/bootstrap/css/bootstrap.min.css">
			<!--	APPEL LIB JQUERY -->
		<script	type="text/javascript" 	src="librairies/jquery.js"></script>
		<!--	APPEL LIB JQUERY UI ( look sympa du programme) -->
		<script type="text/javascript" 	src="librairies/jquery-ui.min.js"				></script>
		<link 	href="librairies/jquery-ui.css" rel="stylesheet" type="text/css" 	/>
		<script type="text/javascript" 	src="librairies/jquery.dialogextend.js"		></script>
		
		<script>
		
		<!-- LE CONTROLEUR -->
		angular.module('app8',['ui.bootstrap','angular.filter'])
			.controller("Controleur", function ($scope) {
				
				<!-- CREATION DU MODELE -->
				
				<!-- CHARGEMENT DU MODELE A PARTIR DE LA MEMOIRE DU NAVIGATEUR -->
				if (JSON.parse(localStorage.getItem("personnes"))!=null){// Vérifie q'une sauvegarde webstorage n'est pas présente, avant de charger les données de démo.
					$scope.personnes = JSON.parse(localStorage.getItem("personnes"));
				}
				
				
				else{
					$scope.personnes = [
					{"id":1,	"nom":"Durand"	,	"prenom":"Paul"	,	"age":21,"email":"Jo@deluxe.fr","salaire":"24k","photo":"h1.jpg","note":2,"csp":"Fonctionnaire",	"equipe":"Groupe1",		"annotation":"A revoir",	"inactif":false	},
					{"id":2,	"nom":"Dupont"	,	"prenom":"José"	,	"age":30,"email":"Jo@deluxe.fr","salaire":"32k","photo":"h2.jpg","note":3,"csp":"Artisan",			"equipe":"Groupe2",		"annotation":"A voir",		"inactif":true	},
					{"id":3,	"nom":"Far"	,		"prenom":"Mohammed","age":28,"email":"Jo@deluxe.fr","salaire":"18k","photo":"h3.jpg","note":5,"csp":"Commerçant",		"equipe":"Groupe1",		"annotation":"Performant",	"inactif":false	},
					{"id":4,	"nom":"Choubala",	"prenom":"René"	,	"age":21,"email":"Jo@deluxe.fr","salaire":"24k","photo":"h4.jpg","note":2,"csp":"Fonctionnaire",	"equipe":"Groupe2",		"annotation":"Commercial",	"inactif":false	},
					{"id":5,	"nom":"Boummed",	"prenom":"Hammed",	"age":30,"email":"Jo@deluxe.fr","salaire":"55k","photo":"h5.jpg","note":3,"csp":"Artisan",			"equipe":"Groupe1",		"annotation":"A voir"	,	"inactif":true	},
					{"id":6,	"nom":"Delapierr",	"prenom":"Chiva",	"age":25,"email":"Jo@deluxe.fr","salaire":"85k","photo":"h6.jpg","note":5,"csp":"Commerçant",		"equipe":"Groupe3",		"annotation":"A faire",		"inactif":false },
					{"id":7,	"nom":"Silvoeros",	"prenom":"Gozoul",	"age":30,"email":"Jo@deluxe.fr","salaire":"12k","photo":"f1.jpg","note":3,"csp":"Artisan",			"equipe":"Groupe1",		"annotation":"A voir"	,	"inactif":false	},
					{"id":8,	"nom":"Duris",		"prenom":"Fauvert",	"age":57,"email":"Jo@deluxe.fr","salaire":"24k","photo":"f2.jpg","note":5,"csp":"Commerçant",		"equipe":"Groupe2",		"annotation":"*Faire Cela<br>*Faire Ceci"	,	"inactif":false	},
					];
				};
				
				
				<!-- CETTE BANQUE DE PHOTOS SERA CHARGEE A PARTIR DU SERVEUR, CEST AUSSI UN MODELE -->
				$scope.banquePhotos = [{"photo":"h1.jpg"},{"photo":"h2.jpg"},{"photo":"h3.jpg"} ];
				
				
				
				<!-- GESTION DE LA NOTATION PAR ETOILES -->
				$scope.max = 10; 
				
				
				<!-- INITIALISATION DES INFORMATIONS -->
				$scope.informations  = "";
				
				
			
				<!-- ENREGISTRE LE MODELE AVEC WEBSTORAGE DANS LE NAVIGATEUR -->
				$scope.enregistrer = function() {
					var u = JSON.stringify($scope.personnes);
					localStorage.setItem("personnes",u);
					$scope.informations=" Les données ont été enregistrées";
					
				};
				
				$scope.supprimer  = function(){
					localStorage.removeItem("personnes");
					$scope.informations=" Retour aux données de démo";
				
				}
				
				
				<!-- AJOUT DUNE PERSONNE AU MODELE -->
				$scope.ajoutPersonne = function() {
				
					if ($scope.filtreCsp!=null&&$scope.filtreEquipe!=null){
						$scope.personnes.push({
								id:$scope.personnes.length+1,
								nom: '',
								prenom: '',
								age: 0,
								photo:$scope.photoChoisie,
								note:'1',
								csp:$scope.filtreCsp,
								equipe:$scope.filtreEquipe,
								annotation:''
						});
					}
				
					else{
						$scope.informations = "Choisissez la catégorie et l'équipe avant d'ajouter un employé";
					};
				};
			
				<!-- SUPPRESSION DUNE PERSONNE AU MODELE -->
				$scope.suppPersonne = function(index) {
						$scope.personnes.splice(index, 1);
					}
				
				
				<!-- STATISTIQUES : NOMBRE DE PERSONNES -->
				$scope.nbPersonnes = $scope.personnes.length;
				
				
				
				<!-- STATISTIQUES : MOYENNE DES AGES -->
				$scope.getMoyenneAge = function(){
					var sommeAges =0
					var quantitePersonne = $scope.personnes.length;
					var moyenneAge =0;
					
					for (x=0;x<$scope.personnes.length;x++){
						sommeAges += eval($scope.personnes[x].age);
					};
					moyenneAge = sommeAges/quantitePersonne;
					return moyenneAge.toFixed(2);
				}
				
				
				<!-- STATISTIQUES : NOTE MOYENNE -->
				$scope.getNoteMoyenne = function(){
					var sommeNotes = 0;
					var quantitePersonne = $scope.personnes.length;
					var noteMoyenne = 0;
					
					for (x=0;x<$scope.personnes.length;x++){
						sommeNotes += eval($scope.personnes[x].note);
					};
					
					noteMoyenne = sommeNotes/quantitePersonne;
					return noteMoyenne.toFixed(2);
				}
				
				
				<!-- GESTION DES PHOTOS -->
				
				<!-- 	ETAPE 1 DEMANDE DE CHANGEMENT DE PHOTO -->
				$scope.requetePhoto = function(id){
					alert('Cliquez sur une photo dans la banque de photo pour modifier la photo');
					$scopeId = id;
				}
				
				<!-- ETAPE 2 RECUPERE LE NOM DUNE PHOTO QUANT ON A CLIQUE SUR UNE PHOTO DANS  LA LISTE DES PHOTOS -->
				$scope.getPhoto = function(index){
					photoChoisie = $scope.banquePhotos[index].photo ;
					$scope.changePhoto($scopeId);
				}
				
				<!-- ETAPE 3 AFFECTE UNE NOUVELLE PHOTO A UNE PERSONNE -->
				$scope.changePhoto = function(id){
					for(x=0;x<$scope.personnes.length;x++){
						if ($scope.personnes[x].id==id){
							$scope.personnes[x].photo =  photoChoisie;
						}
					}
				}
				
				
				
				
				
				
				<!-- FIN DU CONTROLEUR -->
				});	
		
<!-- 		FENETRE DIALOG POUR LES PHOTOS -->
		$(document).ready(function() {
			$(function() {
					$( "#listePhotos" ).dialog({width:300,height:400,autoOpen: true,draggable:true,appendTo: 'body'}).dialogExtend({
							"closable" : false,
							"maximizable" : true,
							"minimizable" : true,
							"collapsable" : true,
							"dblclick" : "collapse",
							"minimizeLocation" : "right",
							});
				});
		
		});
		
		
		</script>
	</head>
	
<!-- LA VUE -->	
<body ng-controller='Controleur'>
	<div id="menu">
		<img src="gest.jpg" class="logo"></img>Informations :<b>{{informations}}</b>
	<!-- 	<input  ng-model="categorie"></input><button>Ajouter</button>
		<input  ng-model="equipe">		</input><button>Ajouter</button> -->
	</div>
	
	
	
	<div id="filtres">
		<b>Rechercher</b>	
		<img src="adequation.png" class="icone"></img>
		<input type="search" ng-model="q" placeholder="Rechercher " /> 
		</input>
		<b>Filtrer</b>	
		
		
		<img src="categ.jpg" class="icone"></img>
		<select class="selectionner" data-ng-model="filtreCsp" ng-options="opt.csp as opt.csp for opt in personnes| unique:'csp'"  >
			<option value="">Catégorie ...</option>
		</select>
		
		<img src="candidat.jpg" class="icone"></img>
		<select class="selectionner" data-ng-model="filtreEquipe" ng-options="opt2.equipe as opt2.equipe for opt2 in personnes| unique:'equipe'" >
			<option value="">Equipe ...</option>
		</select>
		
			<img src="arrow_down.png" class="icone"></img>
			<select class="selectionner" data-ng-model="filtreInactif" ng-options="opt3.inactif as opt3.inactif for opt3 in personnes| unique:'inactif'" >
			<option value="">Inactif ...</option>
		</select>
		
		
		
		
	</div> 
	
	<div id="personnel">	
		<table class = "CSSTableGenerator" >	
					
					<tr >
						<th> Photo</th>
						<th ng-click="predicate='nom'">Nom</th>
						<th ng-click="predicate='prenom'">Prénom</th>
						<th ng-click="predicate='age'">Age</th>
						<th >Général</th>
						<th ng-click="predicate='salaire'">Salaire</th>
						<th ng-click="predicate='note'">Note</th>
						<th>Annotation</th>
						<th ng-click="predicate='equipe'">Equipe</th>
						<th ng-click="predicate='inactif'">Inactif</th>
						<!-- <th>Supprimer</th> -->
					</tr>
					
					<tr ng-repeat="personne in personnes |filter:filtreCsp|filter:filtreEquipe|filter:filtreInactif|orderBy:predicate | filter:q as results " >
						<td><img src="{{personne.photo}}" class="image" ng-click="requetePhoto(personne.id)"></img></td>
						<td><input  ng-model="personne.nom"></input></td>
						<td><input  ng-model="personne.prenom"></input></td>
						<td><input  ng-model="personne.age"></input></td>
						<td>Mail :<br> <input  ng-model="personne.email"> <br>
							Ville :<br><input  ng-model="personne.ville"></input></td>
						<td><input  ng-model="personne.salaire"></input></td>
						<td><rating ng-model="personne.note" 	 max="max" readonly="isReadonly" on-hover="hoveringOver(value)" on-leave="overStar = null"></rating></td>
						<td><textarea ng-model="personne.annotation" class="zoneTxt"></textarea></td>
						<td>{{personne.equipe}}</td>
						<td><input type="checkbox"  ng-model="personne.inactif"  ></input></td>
						<!-- <td> [<a href ng-click="suppPersonne($index)">X</a>] </td> -->
					</tr>
					
					<tr>
						<td></td>
						<td></td>
						<td></td>
						<td></td>
						<td></td>
						<td></td>
						<td></td>
						<td></td>
						<td></td>
						<!-- <td></td> -->
						<td><a href ng-click="ajoutPersonne()" class="btn">Ajouter</a></td>
					
					</tr>
		</table>	
		
		<button ng-click="supprimer()" class="left btn">Ré-Initialiser</button>
		<button ng-click="enregistrer()" class="left btn">Enregistrer</button>
	</div>
		
	<div id="stats">
		<b>Statistiques:</b><br>
		<table class="CSSTableGenerator largeFonts">
			<tr>
				<th>Nombre de Personnes : </th>
				<th>Moyenne Age : 	</th>		
				<th>Note Moyenne : 	</th>		
				
			</tr>
			<tr>
				<td>{{nbPersonnes}}</td>
				<td>{{getMoyenneAge()}} ans</td>
				<td>{{getNoteMoyenne()}} sur 10</td>
			</tr>
		</table>
	</div>
	
	
	<div id="listePhotos" title="Ma Banque de Photos">
	Banque de Photos
		<table ng-repeat="photo in banquePhotos">
		<th><img src="{{photo.photo}}" class="image" ng-click="getPhoto($index)"></th>
		</table>
		
		
	</div>
</body>

<!-- TOUS LES CSS -->
<style>

body{
background-color:slategrey;
}



.logo{
width:200px;
height:100px;

}

.icone{
width:20px;
height:20px;

}

.largeFonts{
font-size:20px;
}

.image{
width:150px;
height:150px;
}

.image hover{
background-color:blue;
}

.selectionner{


}


#menu{
margin-bottom:1%;
background-color:white;

}
#filtres{
margin-bottom:1%;
background-color:lightgrey;
	background-color:lightgrey;
	-moz-border-radius-bottomleft:14px;
	-webkit-border-bottom-left-radius:14px;
	border-bottom-left-radius:14px;
	
	-moz-border-radius-bottomright:14px;
	-webkit-border-bottom-right-radius:14px;
	border-bottom-right-radius:14px;
	
	-moz-border-radius-topright:14px;
	-webkit-border-top-right-radius:14px;
	border-top-right-radius:14px;
	
	-moz-border-radius-topleft:14px;
	-webkit-border-top-left-radius:14px;
	border-top-left-radius:14px;
	-webkit-border-radius: 4px 4px 4px 4px;
	border-radius: 4px 4px 4px 4px;
	-webkit-box-shadow:inset 2px 2px 2px 2px #635453;
	box-shadow:inset 2px 2px 2px 2px #635453;
}


#personnel{
width:95%;
Height:70%;
overflow:auto;
margin-left:auto;
margin-right:auto;
}


#stats{
margin-top : 2%;
background-color:lightgrey;
	background-color:lightgrey;
	-moz-border-radius-bottomleft:14px;
	-webkit-border-bottom-left-radius:14px;
	border-bottom-left-radius:14px;
	
	-moz-border-radius-bottomright:14px;
	-webkit-border-bottom-right-radius:14px;
	border-bottom-right-radius:14px;
	
	-moz-border-radius-topright:14px;
	-webkit-border-top-right-radius:14px;
	border-top-right-radius:14px;
	
	-moz-border-radius-topleft:14px;
	-webkit-border-top-left-radius:14px;
	border-top-left-radius:14px;
	-webkit-border-radius: 4px 4px 4px 4px;
	border-radius: 4px 4px 4px 4px;
	-webkit-box-shadow:inset 2px 2px 2px 2px #635453;
	box-shadow:inset 2px 2px 2px 2px #635453;
}


#listePhotos{
max-height:200px;
overflow:scroll;
background-color:white;

}


.zoneTxt{
width:100%;
height:100%;
}



.left{
float:right;
}

.CSSTableGenerator {
	margin:0px;padding:0px;
	width:100%;
	box-shadow: 10px 10px 5px #888888;
	border:1px solid #000000;
	
	-moz-border-radius-bottomleft:2px;
	-webkit-border-bottom-left-radius:2px;
	border-bottom-left-radius:2px;
	
	-moz-border-radius-bottomright:2px;
	-webkit-border-bottom-right-radius:2px;
	border-bottom-right-radius:2px;
	
	-moz-border-radius-topright:2px;
	-webkit-border-top-right-radius:2px;
	border-top-right-radius:2px;
	
	-moz-border-radius-topleft:2px;
	-webkit-border-top-left-radius:2px;
	border-top-left-radius:2px;
	background:white;
	overflow:auto;
}

.CSSTableGenerator table{
    border-collapse: collapse;
        border-spacing: 0;
	width:100%;
	height:100%;
	margin:0px;padding:0px;
}

.CSSTableGenerator tr:last-child td:last-child th:last-child {
	-moz-border-radius-bottomright:14px;
	-webkit-border-bottom-right-radius:14px;
	border-bottom-right-radius:14px;
}

.CSSTableGenerator table tr:first-child td:first-child th:first-child{
	-moz-border-radius-topleft:14px;
	-webkit-border-top-left-radius:14px;
	border-top-left-radius:14px;
}

.CSSTableGenerator table tr:first-child td:last-child {
	-moz-border-radius-topright:14px;
	-webkit-border-top-right-radius:14px;
	border-top-right-radius:14px;
}

.CSSTableGenerator tr:last-child td:first-child{
	-moz-border-radius-bottomleft:14px;
	-webkit-border-bottom-left-radius:14px;
	border-bottom-left-radius:14px;
}

.CSSTableGenerator tr:hover td{
	background-color:lightgrey;
}

.CSSTableGenerator highlight {
    background-color: #fff444;
}




.CSSTableGenerator td,th{
	vertical-align:middle;
	


	border:1px solid #000000;
	border-width:0px 1px 1px 0px;
	text-align:left;
	padding:7px;
	font-size:0.9em;
	font-family:Arial;
	font-weight:normal;
	color:#000000;
}


.CSSTableGenerator td highlight,th highlight{
	vertical-align:middle;
	


	border:1px solid #000000;
	border-width:0px 1px 1px 0px;
	text-align:left;
	padding:7px;
		font-size:0.9em;
	font-family:Arial;
	font-weight:normal;
	
}







.CSSTableGenerator tr:last-child td{
	border-width:0px 1px 0px 0px;
}

.CSSTableGenerator tr td:last-child{
	border-width:0px 0px 1px 0px;
}

.CSSTableGenerator tr:last-child td:last-child{
	border-width:0px 0px 0px 0px;
}

.CSSTableGenerator tr:first-child td th{
		background:-o-linear-gradient(bottom, #ff5656 5%, #7f0000 100%);	background:-webkit-gradient( linear, left top, left bottom, color-stop(0.05, #ff5656), color-stop(1, #7f0000) );
	background:-moz-linear-gradient( center top, #ff5656 5%, #7f0000 100% );
	filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#ff5656", endColorstr="#7f0000");	background: -o-linear-gradient(top,#ff5656,7f0000);

	background-color:#ff5656;
	border:0px solid #000000;
	text-align:center;
	border-width:0px 0px 1px 1px;
	font-size:0.9em;
	font-family:Arial;
	font-weight:bold;
	color:#ffffff;
	<!-- max-height:30px; -->
}
.CSSTableGenerator tr:first-child:hover td{
	background:-o-linear-gradient(bottom, #ff5656 5%, #7f0000 100%);	background:-webkit-gradient( linear, left top, left bottom, color-stop(0.05, #ff5656), color-stop(1, #7f0000) );
	background:-moz-linear-gradient( center top, #ff5656 5%, #7f0000 100% );
	filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#ff5656", endColorstr="#7f0000");	background: -o-linear-gradient(top,#ff5656,7f0000);

	background-color:#ff5656;
}
.CSSTableGenerator tr:first-child td:first-child{
	border-width:0px 0px 1px 0px;
}
.CSSTableGenerator tr:first-child td:last-child{
	border-width:0px 0px 1px 1px;
}


th:hover{
background-color:red;
}

.btn {
margin-top:10px;
	background: #d93484;
	background-image: -webkit-linear-gradient(top, #d93484, #b82b2b);
	background-image: -moz-linear-gradient(top, #d93484, #b82b2b);
	background-image: -ms-linear-gradient(top, #d93484, #b82b2b);
	background-image: -o-linear-gradient(top, #d93484, #b82b2b);
	background-image: linear-gradient(to bottom, #d93484, #b82b2b);
	-webkit-border-radius: 13;
	-moz-border-radius: 13;
	border-radius: 13px;
	text-shadow: 5px 3px 3px #666666;
	-webkit-box-shadow: 4px 8px 11px #666666;
	-moz-box-shadow: 4px 8px 11px #666666;
	box-shadow: 4px 8px 11px #666666;
	font-family: Arial;
	color: #ffffff;
	font-size:1.0em;
	padding: 21px;
	border: solid #d1047f 3px;
	text-decoration: none;
}
.btn:hover {
	background: #fcd63c;
	background-image: -webkit-linear-gradient(top, #fcd63c, #cc5414);
	background-image: -moz-linear-gradient(top, #fcd63c, #cc5414);
	background-image: -ms-linear-gradient(top, #fcd63c, #cc5414);
	background-image: -o-linear-gradient(top, #fcd63c, #cc5414);
	background-image: linear-gradient(to bottom, #fcd63c, #cc5414);
	text-decoration: none;
}
		

</style>
Publicités