[AngularJs + Material + Php-Sql] –Défi– : Réaliser une Micro-app « Rdv-Juristes »de Prise de rendez vous pour des juristes, en 2 jours maximum -> « Rdv-Juristes ».

angularjslogo-phplogo-mysql-170x170_400x400

Introduction


Je vais essayer de créer une micro application responsive , avec angularjs material, en moins de 2 jours, avec un design sympa. Pour suivre l’avancée de l’application, cliquer ici Pour suivre l’avancée de l’applciation après les 2 jours de défi, cliquer ici (version 2)

rdvjuristes.

Cette application doit permettre de prendre un rendez vous en spécifiant

  • Les noms des juristes
  • Les fichiers
  • Les annotations
  • Le taux de criticité avec des étoiles.

Voici le cahier des charges :

  • Utiliser une base de données relationelle.
  • Le design doit être clair et responsive, et si possible carrément passer sur téléphone 5 pouces.
  • Pouvoir choisir plusieurs juristes, ajouter un commentaire et uploader des fichiers au rendez vous à créer.
  • Pouvoir éditer un rendez vous, cela ouvre alors les caractéristiques du rendez vous grâce à son identifiant.
  • Pouvoir supprimer un rendez vous.
  • Ajouter un seuil de criticité.
  • Facultatif, ajouter une fenêtre qui montre les rendez vous les plus urgents à venir , automatiquement(simple rqt sql). Et aussi un google map pour l’adresse du rendez vous.

On en déduit donc 

  • La présence de 2 modèles de données : juristes et rendezVous et de 2 tables SQL + 1 pour faire les jointures. Pour les fichiers, plutôt que de créer une table SQL, je vais faire une astuce qui est d’enregistrer le tableau JSON des noms de fichiers dans un champs de la table rendezVous… hi hi, peu orthodoxe, mais efficace pour aller plus vite
  • Pas le temps de faire de UML, on le fait de tête.
  • Présence de factories AngularJS pour simplifier.

Gantt Approximatif :

  • Dessin de la maquette : 10 minutes
  • Coding du Front End : 7 heures
  • Coding du Back End : 7 heures.

Attention… j’espère y arriver (Mais pas sur du tout hem… je ne connais passez material)…C’est parti le décompte commence … Il est 17h00ir-logiciels

Libs utilisées


  • angular-ui-calendar OU de préférence Angular Material Calendar v0.2.12
  • angularJs material
  • une lib pour la notation par étoiles
  • ng-map

La Maquette Papier (5 minutes)


maquette.jpg

Création des tables SQL (10 Minutes):


On crée la table juristes :

CREATE TABLE `test`.`juristes` (
`id` INT NOT NULL AUTO_INCREMENT,
`nom` VARCHAR(45) NULL,
`prenom` VARCHAR(45) NULL,
`email` VARCHAR(45) NULL,
`image` VARCHAR(45) NULL,
PRIMARY KEY (`id`));

On crée la table rendezvous :

CREATE TABLE `test`.`rendezvous` (
`id` INT NOT NULL AUTO_INCREMENT,
`title` VARCHAR(45) NULL,
`infos` VARCHAR(45) NULL,
`adresse` VARCHAR(45) NULL,
`criticite` INT NULL,
`fichiers` VARCHAR(2000) NULL,
`start` VARCHAR(45) NULL,
`end` VARCHAR(45) NULL,

PRIMARY KEY (`id`));

On crée la table juristesrendezvous :

CREATE TABLE `test`.`juristesrendezvous` (
`idrendezvous` INT NOT NULL,
`idjuriste` INT NULL);

Le front End 


Le point à 21h00 :

J’ai perdu 2 heures au total à cause de MD CHIPS, l’exemple sur le site de angularjs Material est une horreur imbuvable qui part dans tous les sens avec un tableau simple au lieu d’un classique tableau d’objets JSON, ce qu’il ne faut jamais faire (compliquer un exemple inutilement, pour faire bien), et ne respecte pas la simplicité intrinsèque de AngularJs. Je me rabat donc en urgence sur https://github.com/mbenford/ngTagsInput qui a fonctionné évidemment du premier coup et est d’une simplicité extrême, et respecte bien la logique angularJs. Lorsque l’on dit que la notation $scope est bien plus simple et surtout que c’est uen galère de transvaser de l’un à l’autre, c’est bien vrai. Bref, impossible de faire fonctionner MD CHIPS, à moins de créer un autre controleur et à coder au format « controller as » dedans, ce que je ne veux pas.

Le point à 23h00 :
J’ai mis en place l’upload de fichiers avec restriction de taille et de type. Demain, Le calendrier à mettre en place, et commencer à coder les 2 factories pour les 2 modèles de données… MD CHIPS m’a fait perdre un temps fou, mais ngTagsInput est super bien , je vais encore l’améliorer. Pour les modèles de données, ça va aller très vite. Par exemple, un rendez vous est un objet JSON qui comprends une liste de juristes, une liste de fichiers, une date etc …., il est facile à enregistrer et à éditer. Je vais essayer de bourrer à fond pour mettre ng-map et ng-autocomplete sur le champs adresse ! je vais aussi essayer que l’on puisse faire du crud sur les juristes … Tout ça en 2 jours grr

Après une journée et demi de pause, je reprends toujours avec le même timing …

calendrierLa fin de la mise en place du front end … Explication du système des identifiants par rendez-vous.


Avec les librairies de calendriers, généralement, une date de rendez vous est un objet JSON qui ressemble à ça :

{
  title: Event Title,
  start: new Date(),
  end: new Date(),
  allDay: false
}
Evidemment, quand il y en a plusieurs, on les stocke dans un tableau d’objets JSON.
Le problème est qu’il n’ont pas d’origine un identifiant unique. En effet, si l’on recherche un rendez-vous dans la base de données avec les critères suivants : Date départ et titre, il peut quand même y avoir des doublons.
La solution, c’est d’ajouter les identifiants des rendez vous directement dans l’objet JSON, lors de la lecture AJAX de la liste des rendez-vous. Et oui , le format JSON est tellement flexible et agréable à manipuler qu’on peut le faire. De cette façon, notre objet JSON ressemblera désormais à ça, et cela ne gène pas du tout le fonctionnement du calendrier :
{
  title: Event Title,
  start: new Date(),
  end: new Date(),
  allDay: false, 
  id :1
}
De cette façon, chaque rendez vous est retrouvé à l’aide de son ID unique de base de donnée, ce qui élimine tout doublon lors de l’édition d’un rendez-vous . En d’autre terme, lorsqu’on clique sur un rendez-vous dans le calendrier, un appel ajax charge les caractéristiques du rendez-vous dans la base de données avec son identifiant unique.

rendez-vousLa fin de la mise en place du front end … Explication de l’unification de l’objet JSON « rendezVous »


Lorsque l’on va cliquer sur « enregistrer le rendez-vous », on veut envoyer au back end un seul objet JSON comprenant tout ce que l’on veut envoyer.

Cet objet JSON s’appelle rendezVous.

Comme il y a plusieurs juristes assistant à un rendez-vous, on en déduit qu’on aura un tableau dans l’objet JSON :

rendezVous.juristes = [];

Comme il y a plusieurs fichiers liés à un rendez-vous, on en déduit qu’on aura un tableau dans l’objet JSON :

rendezVous.fichiers = [];

Les autres informations sont des sous objets de l’objet JSON rendezVous :

rendezVous.dateTemps = {}; ( Comprends la date et l’heure)

rendezVous.information = {};

rendezVous.criticite ={};

rendezVous.adresse={};

Et voilà, il ne nous reste plus qu’à envoyer l’objet JSON rendezVous au Back END, attention parce qu’on a besoin de chaque ID de chaque juristes pour les retrouver ensuite !.

Petite astuce : Le temps du développement, je peux ajouter un watcher sur rendezVous.juriste afin de vérifier que tout « descend bien  » dans le tableau, comme ceci :


$scope.$watchCollection('rendezVous.juristes', function () {$scope.$watchCollection('rendezVous.juristes', function () { console.log($scope.rendezVous.juristes);});

Au final, lorsque l’on, clique sur « Enregistrer le Rendez vous », on a un objet JSON de ce type à transmettre au Back End :

Object { juristes: Array[2], fichiers: Array[1], titre: "test", adresse: "test", dateTemps: Date 2017-06-13T12:31:00.000Z, informations: "test" }

imagesLe jour 2 : Course et Finalisation de l’application de Base avec son CRUD


2 Problèmes me ralentissent encore :

  • Le format de date, impossible de l’entrer dans un Timestamp Mysql, du coup, je les ait passsé en varchar et j’ai créé une fonction qui converti en new Date() lors de la lecture. (Turnaround fait dans l’urgence)
  • Les ids des juristes sont à récupérer dans le BACK END, hors, ils arrivent au format array d’objets,  je n’ai pas encore assez l’habitude de traiter ce genre en PHP, avec une boucle FOR, ça me ralentit un peu.

Quelques bonnes nouvelles :

  • Il est possible de sérialiser un array d’objets dans un champs Mysql, puis de le déserialiser, c’était un bon truc à essayer pour des projets rapides ça peut servir.
  • Angular Material Event Calendar est bien normalisé, il fonctionne bien.

A vue de nez, je suis à la 5 ème heure de programmation du CRUD (Back End + Front End), j’ai des chances d’y arriver, mais, les formats de date m’ont vraiment retardés. Il me faut encore faire le UPDATE et le DELETE d’un rendez-vous.

Ensuite, j’ajouterais comme prévu un CRUD sur les juristes, Un ng-map pour google Map et un autocomplete sur le champs adresse, l’exercice sera ainsi terminé.

Je renouvellerais la notion de défi afin d’aller encore plus vite sur d’autres micro apps.

Aux premiers abords on a l’impression que c’est une micro app très simple, hors, il y a pas mal de choix techniques à prendre lors de la conception, qui peuvent être complexes. Par exemple, lors du chargement d’un rendez-vous, les Juristes ne peuvent être réduits à leurs identifiants, parce qu’ils sont au format objet dans ng-tags-input. Bref, c’est pas mal de difficultés à gérer en deux jours.

télécharger (1).jpg

Fin des 14 Heures de codage et conclusion


J’ai réussi avec à peu près 2 heures de retard. J’ai donc mis 16 Heures en tout pour réaliser une micro application avec un CRUD sur des rendez vous, dans un calendrier.
Il manque encore le Delete d’un rendez vous à faire vite fait, ainsi qu’un bouton « nouveau rendez vous » !

Je considère cela encourageant, vu que je ne connaissais pas Matérial.

Je vais maintenant améliorer le design et ajouter le CRUD des juristes et pleins d’améliorations de Design, mais je considère que j’ai plus ou moins réussi mon projet sur 2 jours, parce que le CRUD est fonctionnel. Il y a aussi la gestion de l’intégrité de la base de données à voir . Pour respecter la notion de défi, je publierais les mises à jour d’après les 2 jours de dev dans un nouveau répertoire, afin que l’on ne soit pas « grugé »  .

Voici le code que j’ai fait au bout de 16 heures , il y a INDEX.HTML qui est la vue globale, APP.JS qui contient le controleur et les factories de data, et CRUD.PHP qui gère le back end et les accès à mysql en technologie PDO.

INDEX.HTML :


<!doctype html>


<head>
<!-- 
	<meta http-equiv="Content-Type" content="text/html;charset=utf-8">  -->
	<!-- AngularJS  Dependencies -->
	<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular-animate.min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular-aria.min.js"></script>
	<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-sanitize/1.6.4/angular-sanitize.min.js"></script>
	<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular-messages.min.js"></script>

	<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.9.0/highlight.min.js"></script>
	
	<!-- ANGULAR MATERIAL -->
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/angular-material/1.1.4/angular-material.css">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/angular-material/1.1.4/angular-material.js"></script>
     <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
	<!-- MOMENT.JS -->
	<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.10.6/moment-with-locales.min.js"></script>
    
	<!-- DATE TIME PICKER -->
	<script src="libs/angular-material-datetimepicker.min.js"></script>
    <link rel="stylesheet" href="libs/material-datetimepicker.min.css">

	<!-- MATERIAL EVENT CALENDAR -->
	<script src="libs/angular-material-event-calendar.js"></script>
	<link rel="stylesheet" href="libs/angular-material-event-calendar.min.css">
	
	<!-- NG TAGS INPUT -->
<!-- 	<link rel="stylesheet" type="text/css" href="libs/ng-tags-input.css">
	<script src="libs/ng-tags-input.js"></script> -->
	<link rel="stylesheet" href="http://mbenford.github.io/ngTagsInput/css/ng-tags-input.min.css" />
	<script src="http://mbenford.github.io/ngTagsInput/js/ng-tags-input.min.js"></script>
	
	<!-- RATIN STARS -->
	<script src="libs/jk-rating-stars.min.js"></script>
	<link rel="stylesheet" href="libs/jk-rating-stars.min.css" />
    
	<!-- PERSONNEL -->
	<script src="app.js"></script>
    <link rel="stylesheet" href="app.css">
</head>

<body ng-app="monApp">
    <div ng-controller="AppCtrl">


        <div layout="row" layout-wrap>
            <div class="md-padding " flex="50" layout="column" >
               <!--  <md-toolbar>
                    <div class="md-toolbar-tools">
                        <h2><img src ="img/rendez-vous.jpg" class="grosicone"></img> Rendez-Vous</h2>
                    </div>
                </md-toolbar> -->
                <fieldset class="demo-fieldset madiv">
                    
					<legend class="demo-legend">
                        <h3>
                            <h3> <img src ="img/juriste.png" class="grosicone"></img> Choisis les juristes (APP EN COURS DE DEV !!!!)</h1>
                        </h1>
                    </legend> 
					
					<tags-input ng-model="rendezVous.juristes" display-property="text" add-on-paste="true" style="height:50px;" placeholder="Ajouter un juriste"  replace-spaces-with-dashes="false">
						<auto-complete 
							source="loadTags($query)"  
							min-length="0" 
							load-on-focus="false"
							load-on-empty="false"
							max-results-to-show="32"
							template="my-custom-template"
						></auto-complete>
					</tags-input>
						
				</fieldset>

				<!-- UN PREMIER FORMULAIRE AVEC CONROLE DE CHAMPS ET MESSAGES TEMPS REEL-->

                <div ng-cloak>
                    <fieldset class="demo-fieldset madiv">
                        
						<legend class="demo-legend">
                            <h3> <img src ="img/fichier.png" class="grosicone"></img> Choisis tes fichiers </h1>
                        </legend>
						
						<div style="height:50px;overflow:auto">
							<div ng-repeat="f in rendezVous.fichiers" ><img src ="img/fichier.png" class="icone" style="width:35px;height:35px;"></img><a href="fichiers/{{f.nom}}">{{f.nom}}</a> </div></div>
						<div layout="row"       layout-align="end end">
						    
							
								<input class="ng-hide" id="input-file-id" type="file" onchange="angular.element(this).scope().uploadFile(this.files,'uploadFichier.php')" />
								<label for="input-file-id" class="md-button md-raised md-primary"><img src="img/disque-dur.png" class="icone"></img> Cherche sur ton disque dur</label>
								<!-- <input  class="form-control " id="input-file-id" type="file" name="file" onchange="angular.element(this).scope().uploadFile(this.files,'uploadFichier.php')" />	 -->
												
									
									<!-- <label for="input-file-id" class="md-button md-raised md-primary">Choisir le fichier</label> -->
							
							
							  <md-progress-linear md-mode="indeterminate" ng-show="montrerLoader"></md-progress-linear>
						</div>
                </div>

                <div ng-cloak>
                    <fieldset class="demo-fieldset madiv">
                        <legend class="demo-legend">
                            <h3> <img src ="img/infos.png" class="grosicone"></img> Donne les infos</h1>
                        </legend> <form name="userForm">
						<div class="madivinverse">
                       
                            <md-input-container style="width:48%">
                                <label>Titre de votre Rendez-vous</label>
                                <input name="titre" ng-model="rendezVous.title" required md-maxlength="20" minlength="4">
                                <div ng-messages="userForm.titre.$error" ng-show="userForm.titre.$dirty">
                                    <div ng-message="required">C'est obligatoire!</div>
                                    <div ng-message="md-maxlength">C'est trop long!</div>
                                    <div ng-message="minlength">C'est trop court!</div>
                                </div>
                            </md-input-container>
                            <md-input-container style="width:48%">
                                <label >Adresse</label>
                                <textarea name="adresse" ng-model="rendezVous.adresse" required md-maxlength="150"></textarea>
                                <div ng-messages="userForm.adresse.$error" ng-show="userForm.adresse.$dirty">
                                    <div ng-message="required">C'est obligatoire!</div>
                                    <div ng-message="md-maxlength">C'est trop long!</div>
                                </div>
                            </md-input-container><br>
                            
                            <!-- <md-input-container>
                                <md-datepicker ng-model="myDate" md-placeholder="Date"></md-datepicker>
								
                            </md-input-container> -->
							
							 <md-input-container style="width:48%"> 
							<!--  {{rendezVous.dateTemps | date:'dd-MM-yyyy HH:mm:ss '}}Choisir la date et l'heure du Rendez-vous -->
								<label>Début </label>
								<input mdc-datetime-picker date="true" time="true" type="text" id="dateTemps" short-time="true"
									   show-todays-date
									   placeholder="Entrez la date et heure de début"
									   min-date="minDate"
									   format="DD-MM-YYYY HH:mm"
									   ng-change="vm.saveChange()"
									   ng-model="rendezVous.start" required>
							</md-input-container>
								
							 <md-input-container style="width:48%"> 
							<!--  {{rendezVous.dateTemps | date:'dd-MM-yyyy HH:mm:ss '}}Choisir la date et l'heure du Rendez-vous -->
								<label>Fin </label>
								<input mdc-datetime-picker date="true" time="true" type="text" id="dateTemps" short-time="true"
									   show-todays-date
									   placeholder="Entrez la date et heure de fin"
									   min-date="minDate"
									   format="DD-MM-YYYY HH:mm"
									   ng-change="vm.saveChange()"
									   ng-model="rendezVous.end" required>
							</md-input-container>	
							
							<br>
							<md-input-container style="width:50%">
                                <label>Informations</label>
									<textarea ng-model="rendezVous.infos" md-maxlength="150" rows="5" md-select-on-focus></textarea>
                            </md-input-container>
							
							<md-input-container style="width:48%">
							 <label>Criticité</label><br><br><br><br>
							 <jk-rating-stars  max-rating="10" rating="rendezVous.criticite" ></jk-rating-stars>
							 </md-input-container>
                        
						
						
						</div>
						
						<div layout="row"       layout-align="end end">
						
						<!-- <md-button ng-disabled="userForm.titre.$error" class="md-button md-raised md-primary" ng-click="sauverRendezVous();"> Enregistrer le Rendez-Vous</md-button> -->
						<md-button  ng-show="!update" type="submit" class="md-button md-raised md-primary" ng-click="sauverRendezVous();"><img src="img/disque-dur.png" class="icone"></img> Enregistrer le Rendez-Vous</md-button></form>
						<md-button  ng-show="update" type="submit" class="md-button md-raised md-primary" ng-click="supprimerRendezVous();"><img src="img/disque-dur.png" class="icone"></img> Supprimer le Rendez-Vous</md-button></form>
						<md-button  ng-show="update" type="submit" class="md-button md-raised md-primary" ng-click="modifierRendezVous();" ><img src="img/disque-dur.png" class="icone"></img> Modifier le Rendez-Vous</md-button></form>
						
						</div>
                </div>
			<!-- FIN DE LA PREMIERE COLONNE -->
			</div>
			
			
			
			<!-- COLONNE 2 -->
            <div class="md-padding" flex="50" layout="column">
                <!-- <md-toolbar>
                    <div class="md-toolbar-tools">
                        <h2><img src ="img/calendrier.png" class="grosicone"></img> Calendrier</h2>
                    </div>
				</md-toolbar> -->
                
				
				<fieldset class="demo-fieldset madiv">
                    <legend class="demo-legend">
                        <h3>
                            <h3><img src ="img/calendrier.png" class="icone"></img> Calendrier.</h1>
                        </h1>
                    </legend>
					
					<md-event-calendar
					  ng-model="selected"
					  md-events="events"
					  md-event-click="eventClicked($selectedEvent)"
					  md-label="title",
					  md-show-create-link="true"
					  md-create-event-click="eventCreatea($date)"
					  md-create-disabled="false"
					  auto-height=""
					  class="md-primary"
					>
					  <md-event-calendar-header class="md-center">
						<md-event-calendar-prev></md-event-calendar-prev>
						<md-event-calendar-title></md-event-calendar-title>
						<md-event-calendar-next></md-event-calendar-next>
					  </md-event-calendar-header>
					</md-event-calendar>
				</fieldset>
			</div>	
		<!-- FIN DE ROW -->
        </div>

</body>
    
	<script type="text/ng-template" id="my-custom-template">
      <div class="left-panel">
        <img ng-src="img/juriste.png" style="width:50px;height:50px;"/>
      </div>
      <div class="right-panel">
        <span ng-bind-html="$highlight($getDisplayText())"></span>
        <span>({{data.ville}})</span>
        <span>{{data.confederation}}</span>
      </div>
    </script>
    
    <script type="text/ng-template" id="autocomplete-template">
      <div class="autocomplete-template">
        <div class="left-panel">
          <img ng-src="http://mbenford.github.io/ngTagsInput/images/flags/{{data.flag}}" />
        </div>
        <div class="right-panel">
          <span ng-bind-html="$highlight($getDisplayText())"></span>
          <span>({{data.rank}})</span>
          <span>{{data.confederation}}</span>
        </div>
      </div>
    </script>

Le fichier APP.JS:

angular.module('monApp', ['ngMaterial','ngAnimate','ngMessages','ngAria','ngMaterialDatePicker','material.components.eventCalendar','ngTagsInput','jkAngularRatingStars','material.components.eventCalendar'])

.factory('rdvFactory',function($http){
 
    var factory = {};
 
    factory.get_rdvs = function(){
        return $http.get('crud.php?action=get_rdvs')
    }
 
    factory.get_rdv_unique = function(idBdd){
        return $http.post('crud.php?action=get_rdv_unique',{'id':idBdd})
    }
	
	factory.insert_rdv = function(rdv){
        return $http.post('crud.php?action=insert_rdv',rdv)
    }
 
    factory.delete_rdv = function(idBdd){
        return $http.post('crud.php?action=delete_rdv',{'id':idBdd})
    }
 
    factory.update_rdv = function(rdv){
        return $http.post('crud.php?action=update_rdv',rdv)
    }
	
	factory.get_juristes_du_rdv = function(idBdd){
        return $http.post('crud.php?action=get_juristes_du_rdv',{'id':idBdd})
    }
 
    return factory
})

.factory('juristesFactory',function($http){
 
    var factory = {};
 
    factory.get_juristes = function(){
        return $http.get('crud.php?action=get_juristes')
    }
	
    return factory
})

   


.controller('AppCtrl', function($scope,$timeout,$q,$log,$mdDialog,$mdBottomSheet,$mdToast,$mdDialog,$http,rdvFactory,juristesFactory) {

/* ------------------------------------------------------INITIALISATIONS--------------------------------------------- */

	/* INITIALISATION DU CALENDRIER */
	$scope.events =[]; // Chaque event est un rendez-vous
	rdvFactory.get_rdvs().then(function(data){  // On récupère en Ajax tous les rendez-vous.
		$scope.events = data.data;
		}).then(function(data){
			angular.forEach($scope.events,function(value,index){// On convertit les dates du format String à date.
				value.start = new Date(value.start);
				value.end = new Date(value.end);
			})
	});
	 
	/* INITIALISATION DU FORMULAIRE DE GESTION DE RENDEZ VOUS*/
	$scope.rendezVous = {};
	$scope.rendezVous.juristes = [];
	$scope.rendezVous.fichiers = [];
	$scope.rendezVous.dateTemps = new Date();
	$scope.update=false;

	/*  INITIALISATION DU TELECHARGEMENT DE FICHIERS */
	$scope.fichiers=[];
	$scope.montrerLoader = false;
	$scope.selected = {};

/*--------------------------------------------------------------- CRUD------------------------------------------------ */

	/* LIRE UN RENDEZ VOUS APRES CLIC */
	$scope.eventClicked = function (item) {
		
		$scope.update = true;
		rdvFactory.get_rdv_unique(item.id).then(function(data){ 
			$scope.rendezVous 			= data.data;
			rdvFactory.get_juristes_du_rdv(item.id).then(function(data){ 
				console.log(data.data);
				$scope.rendezVous.juristes = data.data;
			})
			$scope.showSimpleToast('J\'ouvre le rdv avec l identifiant :'+item.id);
			
		})
		
		
	};
	
	/* SAUVER UN NOUVEAU RENDEZ VOUS */
	$scope.sauverRendezVous = function(){
	
		if ($scope.userForm.$valid) {
			$scope.showSimpleToast('Le formulaire est valide!');
			$scope.userForm.$setSubmitted();
			rdvFactory.insert_rdv($scope.rendezVous).then(function(data){ 
				$scope.rendezVous.id = data.data;
				$scope.events.push($scope.rendezVous);
			});
		} else {
	
		  $scope.showSimpleToast('Le formulaire est invalide!');
		}
		
	}
	
	/* MODIFIER UN RENDEZ VOUS */
	$scope.modifierRendezVous = function(){
		if ($scope.userForm.$valid) {
			$scope.showSimpleToast('Le formulaire est valide!');
			$scope.userForm.$setSubmitted();
			rdvFactory.update_rdv($scope.rendezVous).then(function(data){ 
				$scope.showSimpleToast(data.data);
			});
		} else {
		  $scope.showSimpleToast('Le formulaire est invalide!');
		}
		
	}
	
	
	


/*--------------------------------------------------------------- FIN DU CRUD------------------------------------------------ */

  $scope.createClicked = function (date) {
    console.log(date);
  };

  function getDate(offsetDays, hour) {
    offsetDays = offsetDays || 0;
    var offset = offsetDays * 24 * 60 * 60 * 1000;
    var date = new Date(new Date().getTime() + offset);
    if (hour) { date.setHours(hour); }
	console.log(date);
    return date;
  }


/* AFFICHER LES JURISTES */

  $scope.tags = [];
  $scope.loadTags = function($query) {
    return $http.get('crud.php?action=get_juristes').then(function(response) {
		console.log(response);
      var tags = response.data;
      return tags.filter(function(tag) {
        return tag.text.toLowerCase().indexOf($query.toLowerCase()) != -1;
      });
    });
  };


/* CHARGEMENT DE FICHIERS SUR LE SERVEUR */
$scope.uploadFile = function(files,destinationPhp) {
	
	 $scope.montrerLoader = true;
	var fd = new FormData();
	//Take the first selected file
	fd.append("file", files[0]);

	var uploadUrl = destinationPhp;
	
	$http.post(uploadUrl, fd, {
		withCredentials: true,
		headers: {'Content-Type': undefined },
		transformRequest: angular.identity
	}).then(function(data){ 
		$scope.montrerLoader = false;
		if(data.data.reponse=='ok'){
		
		
			if(destinationPhp=='uploadPhotoFournisseurs.php'){
				notifier.notify('image téléchargée sur le serveur!');
				$scope.fournisseur.image = 'img-fournisseurs/'+files[0].name;
			}
			if(destinationPhp=='uploadFichier.php'){
				$scope.showSimpleToast('Fichier transféré!');
				/* notifier.notify('Fichier téléchargé sur le serveur!'); */
				$scope.rendezVous.fichiers.push({'nom':files[0].name});
			}
		}
		else{
			alert(data.data.reponse);
			
		}
		
	})
	
};

	/* Date picker */
	this.myDate = new Date();
	this.isOpen = false;
	
	/* TimePicker */
	  $scope.currentDate = new Date();
	  
  	this.showDatePicker = function(ev) {
    	$mdpDatePicker($scope.currentDate, {
        targetEvent: ev
      }).then(function(selectedDate) {
        $scope.currentDate = selectedDate;
      });;
    };
    
    this.filterDate = function(date) {
      return moment(date).date() % 2 == 0;
    };
    
    this.showTimePicker = function(ev) {
    	$mdpTimePicker($scope.currentTime, {
        targetEvent: ev
      }).then(function(selectedDate) {
        $scope.currentTime = selectedDate;
      });;
    }  
	
/* AUTRES CODES UTILES  */

/* $scope.$watchCollection('rendezVous.fichiers', function () {
	console.log($scope.rendezVous.fichiers);
}); */
	/* EXEMPLE D EVENT DE CALENDRIER */
/* $scope.events = [{"id":"1","title":"Loi Travail","infos":null,"adresse":"12 avenue des lis 78013  paris","criticite":"4","fichiers":null,"start":new Date("2017-06-11T22:37:59.012Z")}]  */

	/* $scope.selected = $scope.events[0]; */
	
	
	/* TOUT LE CODE DE MDTOAST (MESSAGES ); */
	  var last = {
      bottom: false,
      top: true,
      left: false,
      right: true
    };

  $scope.toastPosition = angular.extend({},last);

  $scope.getToastPosition = function() {
    sanitizePosition();

    return Object.keys($scope.toastPosition)
      .filter(function(pos) { return $scope.toastPosition[pos]; })
      .join(' ');
  };

  function sanitizePosition() {
    var current = $scope.toastPosition;

    if ( current.bottom && last.top ) current.top = false;
    if ( current.top && last.bottom ) current.bottom = false;
    if ( current.right && last.left ) current.left = false;
    if ( current.left && last.right ) current.right = false;

    last = angular.extend({},current);
  }

  $scope.showSimpleToast = function(message) {
    var pinTo = $scope.getToastPosition();

    $mdToast.show(
      $mdToast.simple()
        .textContent(message)
        .position(pinTo )
        .hideDelay(3000)
    );
  };

  $scope.showActionToast = function() {
    var pinTo = $scope.getToastPosition();
    var toast = $mdToast.simple()
      .textContent('Marked as read')
      .action('UNDO')
      .highlightAction(true)
      .highlightClass('md-accent')// Accent is used by default, this just demonstrates the usage.
      .position(pinTo);

    $mdToast.show(toast).then(function(response) {
      if ( response == 'ok' ) {
        alert('You clicked the \'UNDO\' action.');
      }
    });
  };
	
})




Le fichier CRUD.PHP :

<?php
 
/* -------------------------------------------------BACK END EN PDO------------------------------------------  */
 
include('connexionConfig.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  Angular **/
 
switch($_GET['action'])  {
    
	/* CRUD DU MODELE DE DONNEES RENDEZ VOUS */
	case 'get_rdvs' 		: get_rdvs();
    break;
	case 'get_rdv_unique' 	: get_rdv_unique();
    break;
	case 'get_juristes_du_rdv' 	: get_juristes_du_rdv();
    break;
	case 'insert_rdv' 		: insert_rdv();
    break;
    case 'delete_rdv' 		: delete_rdv();
    break;
    case 'update_rdv' 		: update_rdv();
    break;
	/* CRUD DU MODELE DE DONNEES JURISTES */
	case 'get_juristes' 	: get_juristes();
    break;
}

/* --------------------------------------------------CRUD DU MODELE DE DONNEES RENDEZ VOUS  ------------------------------------------*/
 
function get_rdvs() { 
 
    try
    {
        $DB = connection();
        $data = $DB->query('SELECT * from rendezvous');
        $arrAll = $data->fetchAll(PDO::FETCH_ASSOC);
 
        /* Convertit en JSON  */
        print_r(json_encode($arrAll));
        /* ferme la connexion ? */
        $DB=null;
    }
    catch(PDOException $e)
    {
        file_put_contents('PDOErreurs.txt', $e->getMessage(), FILE_APPEND);
    }
}


function get_rdv_unique() { 
    
	/* Récupération des données POST Provenant du Front end*/
    $data = json_decode(file_get_contents("php://input")); 
	
    try
    {	
		$DB = connection();
		
		$requete 		= 'SELECT * from rendezvous WHERE  id= '.$data->id;
		$data 			= $DB->query($requete);
		$rdv 			= $data->fetch(PDO::FETCH_ASSOC);
		$rdv[fichiers]	= unserialize($rdv[fichiers]);
		
		/* Convertit en JSON pour le front end */
		echo(json_encode($rdv)) ;
		
        /* ferme la connexion ? */
        $DB=null;
    }
    catch(PDOException $e)
    {
        file_put_contents('PDOErreurs.txt', $e->getMessage(), FILE_APPEND);
    }
}


function get_juristes_du_rdv() { 
    
	/* Récupération des données POST Provenant du Front end*/
    $data = json_decode(file_get_contents("php://input")); 
	
    try
    {	
		$DB = connection();
		
		$requete 		= 'SELECT juristes.id AS id,juristes.nom AS text,juristes.image AS flag,juristes.ville AS ville FROM juristesrendezvous LEFT JOIN juristes on juristes.id=juristesrendezvous.idjuriste WHERE  juristesrendezvous.idrendezvous= '.$data->id;
		$data 			= $DB->query($requete);
		$jrst 			= $data->fetchAll(PDO::FETCH_ASSOC);
		
		/* Convertit en JSON pour le front end */
		echo(json_encode($jrst)) ;
		
        /* ferme la connexion ? */
        $DB=null;
    }
    catch(PDOException $e)
    {
        file_put_contents('PDOErreurs.txt', $e->getMessage(), FILE_APPEND);
    }
}



function insert_rdv() {
    /* Récupération des données POST Provenant du Front end*/
     $data = json_decode(file_get_contents("php://input")); 
 
	/* Insertion du rendez vous en Bdd avec PDO */
    try {
        $DB = connection();
        $req = $DB->prepare("INSERT INTO rendezvous VALUES (?,?,?,?,?,?,?,?)");
        $req->execute(array(null,$data->title,$data->infos,$data->adresse,$data->criticite,serialize($data->fichiers),$data->start,$data->end));
        $lastid = $DB->lastInsertId();
		
		
		/* Récupération des juristes dans un tableau. */
		$juristes = $data->juristes;
		// On enregistre chaque juriste du rendez vous pour le rendez vous dans la bonne table sql
		$sql = $DB->prepare("INSERT INTO juristesrendezvous VALUES (?,?)");
		foreach($juristes as $row){
		     $sql->execute(array($lastid,$row->id)); 
		}

		
		print_r(json_encode($lastid)); 
		$DB=null;
		
        
    } catch (PDOException $e) {
        file_put_contents('PDOErreurs.txt', $e->getMessage(), FILE_APPEND);
        die();
    }
}
 

 
 function update_rdv() {
    $data = json_decode(file_get_contents("php://input"));
 
    /* Update en Bdd avec PDO */
    try {
        $DB = connection();
        $sql = "UPDATE rendezvous SET title='".$data->title."',infos='".$data->infos."',adresse='".$data->adresse."',criticite='".$data->criticite."',fichiers='".serialize($data->fichiers)."',start='".$data->start."',end='".$data->end."' WHERE  id=".$data->id." ";
        $stmt = $DB->prepare($sql); 
        $stmt->execute();
		
		/* On doit aussi mettre à jour la table juristesrendezvous */
		/* Récupération des juristes dans un tableau. */
		$juristes = $data->juristes;
		
		/* SUPPRESSION DE LA LISTE DES ANCIENS JURISTES */
		$sql = "DELETE FROM juristesrendezvous  WHERE  idrendezvous=".$data->id." ";
		$stmt = $DB->prepare($sql); 
        $stmt->execute();
		
		// MISE A JOUR DE LA LISTE DES NOUVEAUX JURISTES
		$idrendezvous = $data->id;
		$sql = $DB->prepare("INSERT INTO juristesrendezvous VALUES (?,?)");
		foreach($juristes as $row){
		     $sql->execute(array($idrendezvous,$row->id)); 
		}
		
		
        $DB=null;
		print_r(json_encode('ok')); 
		
		
    } catch (PDOException $e) {
        file_put_contents('PDOErreurs.txt', $e->getMessage(), FILE_APPEND);
        die();
    }
}


 function delete_rdv() {
    /* Récupération des données POST */
     $data = json_decode(file_get_contents("php://input")); 
 
    /* Delete en Bdd avec PDO */
    try {
        $DB = connection();
        $sql = "DELETE FROM rendezvous WHERE  id=:id";
        $stmt = $DB->prepare($sql);
        $stmt->bindParam(':id',$data->id,PDO::PARAM_INT);
        $stmt->execute();
        $DB=null;
    } catch (PDOException $e) {
        file_put_contents('PDOErreurs.txt', $e->getMessage(), FILE_APPEND);
        die();
    }
}



/* --------------------------------------------------CRUD DU MODELE DE DONNEES JURISTES  ------------------------------------------*/



function get_juristes() { 
 
    try
    {
        $DB = connection();
        $data = $DB->query('SELECT id AS id, nom AS text,image AS flag,ville AS ville from juristes');
        $arrAll = $data->fetchAll(PDO::FETCH_ASSOC);
 
        /* Convertit en JSON  */
        print_r(json_encode($arrAll));
        /* ferme la connexion ? */
        $DB=null;
    }
    catch(PDOException $e)
    {
        file_put_contents('PDOErreurs.txt', $e->getMessage(), FILE_APPEND);
    }
}

Sans oublier le fichier de connexion bien sur, CONNEXIONCONFIG.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;
}
?>
Publicités