[Bootstrap 3 ] Un magnifique Template vraiment responsive, avec une sidebar et un barre des tâches .

createiveL’agence Creative TIM

Introduction


Je m’étais égaré ces derniers temps en ne faisant pas assez attention au responsive, ainsi qu’au look de mes apps.

J’ai trouvé un Theme vraiment responsive cette fois ci, avec un look vraiment vraiment sympa par contre c’est pas du bootstrap 4.0.

C’est l’agence CREATIVE TIM qui a des templates vraiment monstrueux en Bootstrap, Matérial et des Widgets !!

J’utiliserais cette base désormais en permanence pour mes futures apps, qui comporte une sidebar qui se contracte parfaitement (togle),et une barre haute.

Lorsque l’on rapetisse l’écran, les panels se contractent parfaitement. j’ai déjà commencé à rajouter et tester des boutons et panels, et je vais rajouter un agenda , et des graphiques qu’on peux changer à la main, et des sliders et des maps, pour bien tester le tout une bonne fois pour toute et que ça passe sur téléphone 5pouces . j’ai testé hier sur un SAMSUNG GALAXY, c’est IMPECCABLE !! Incroyable ! Le template est 100 % parfait sur écran 22 pouces ET sur un téléphone 5 pouces sans rien faire !

Je n’utiliserais plus Material que je ne trouve pas aussi facile que Bootstrap (Voir rdvjuristes ou je galère). Par contre l’agence CREATIVE TIM à un super template Material CSS !

Photo du template


template.jpg

Le lien du template :


http://nicolash.org/db/dashboard.html

[AngularJs + AngularJs Material ] Un framework qui a un bon aspect.

angularjs-materialDesign.png

Introduction


A la recherche d’un bon framework de fonctionnalités pré-designées pour angularJs, autre que angular-ui bootstrap, j’utilise désormais aussi angular matérial, dont les exemples sont plus complexes, mais qui propose vraiment un bon rendu .

Voici la page du framework :

https://material.angularjs.org/latest/

En cliquant sur « demo », on peut voir tout ce que l’on peut faire avec, il s’agit d’un design normalisé et responsive, permettant d’aller plus vite. Pas mal d’exemples utilisent la notation « controller as » mais moi je repasse tout cela en notation normale avec $scope pour normaliser mon code, rien n’empêche de continuer à utiliser controller as…

Du coup, je conserve ici une page html et un controlleur angularJs relativement traduits en Français, avec les fonctionnalités que je considère les plus intéressantes, pour pouvoir les intégrer plus vite. Mon but est vraiment d’accélérer au maximum la mise en place d’idées de base, en maitrisant bien ces frameworks, et aussi de faire du responsive. Le time Picker est vraiment sympa.

Fonctionnement


Dans la plupart des cas, on injecte la fonctionnalité dans le controleur . Si la fonctionnalité s’appelle par exemple $mdBottomSheet, alors on l’injecte comme cela dans le controleur  AngularJs :


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

};

Je ne mets pas le code interne dans cet exemple bien sur.
Cette fonctionnalité affiche un super menu qui apparait tout seul en bas d'une fenêtre.

 

Voir la page HTML avec les éléments en action,  en Français .


C’est ici .

 

Lire la suite

[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 1.6] Afficher n appréciations sur double click sur une image ou une div, grâce aux coordonnées X et Y.

angularjsIntroduction



Un Petit code qui permet d’afficher autant d’inputs HTML que l’on veut sur une DIV lorsque l’on double clique n’importe ou dans la div.

Super utile pour tout type d’applications, (Santé, Localisation, Automobile etc ….) dans la mesure ou l’image de fond peut être par exemple un corps humain ou une carte.

On voit dans un premier temps comment faire apparaitre des champs HTML Inputs à loisir dans la DIV (Partie 1) avec du Jquery dans le controleur(déconseillé) , puis ensuite, dans la partie 2 le code devient du full angularJs pour permettre la sauvegarde et le rechargement du modèle de données intégral qui comprends toutes nos appréciations que l’on a créé en temps réel … On a également envie de supprimer l’appréciations que l’on veut ( Avec un icone Croix bootstrap…). Pour faire cette partie 2, il est nécessaire de refaire le code et d’utiliser un ng-repeat.

A tester ici.

Photo


xy.jpg

Explication sommaire du code (Partie 1 + Partie 2) :


Lorsqu’on double clique, l’évènement est passé en paramêtre à la fonction ajoutSurClick($event) . On récupère le x et le y puis on affiche notre appréciation au bon endroit avec un append ().

Le code (Partie 1) :


Tout d’abord Index.html qui fait aussi office de vue dans ce cas :


<!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>
    <link rel="stylesheet" type="text/css" href="css/style.css">
    <!-- FIN DE CHARGEMENT DES LIBRAIRIES -->
</head>

<body ng-app="neutre" ng-controller="neutreCtrl">
    <div class="container-fluid">
        <nav class="navbar navbar-inverse">
            <div class="container-fluid">
                <!-- Brand and toggle get grouped for better mobile display -->
                <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>
        <div class="row ">
            <div class="col-lg-12 ">
                <div class="panel panel panel-warning">
                    <div class="panel-heading">
                        <i class="fa fa-picture-o"></i>
                        <div class="box-tools pull-right">
                            <button class="btn btn-primary btn-sm pull-right" ng-model="collapsed" ng-click="collapsed=!collapsed" data-widget="collapse"><i class="fa fa-minus"></i></button></div>
                    </div>
                    <div ng-dblclick="ajoutSurClick($event)" ng-show="!collapsed" class="panel-body table-responsive" style="min-height:350px;" id="fenetre"></div>
                    <div class="panel-footer ">
                        <div class="form-group"></div>
                    </div>
                </div>
            </div>
        </div>
    </div>
    <!-- FIN DE DIV GLOABLE FLUID -->
    </div>
</body>

</html>

Puis ensuite, le controleur ANGULARJS dans notre fichier app.js:

angular.module('neutre', [])

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

            $scope.ajoutSurClick = function(event) {

                alert(event.offsetX + '  ' + event.offsetY);

                var mover = angular.element(' <
                    div > < button > Appreciation < /button><input></input > < /div>
                    ');
                    var x = event.offsetX + 'px';
                    var y = event.offsetY + 'px'; mover.css({
                        position: 'absolute',
                        top: y,
                        bottom: '0px',
                        left: x,

                        zIndex: '2'
                    });

                    angular.element('#fenetre').append(mover);
                }

                /* FIN DU CONTROLEUR */
            });

Partie 2 : Plus de Jquery, mais du full angularJs


Maintenant, voici la deuxième version, en AngularJS complet qui permet de supprimer les appréciations. On ajoute la photo d’un corps humain pour mieux comprendre le but aussi. On utilise plus de JQuery mais un ng-repeat dans la vue à la place, Les positions des inputs étant dans ng-style lors de chaque itérations du ng-repeat.

Pour tester l’app, c’est ici .

On constate là toute la simplicité de l’excellent framework angularJs, à absolument garder, qui permet de faire tout ce qui nous passe par la tête, sans prise de tête , et rapidement ( 30 minutes dans ce cas).

Photo de la micro app :


appreciations.jpg

La vue Index.html, elle a changé, on a mis un ng-repeat dedans qui affiche chaque appréciation avec sa position.

 


<!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>
		<link rel="stylesheet" type="text/css" href="css/style.css">
		
		<!-- FIN DE CHARGEMENT DES LIBRAIRIES -->
  </head>

<body ng-app="neutre" ng-controller="neutreCtrl">
	<div class="container-fluid">
 
        <nav class="navbar navbar-inverse">
            <div class="container-fluid">
                <!-- Brand and toggle get grouped for better mobile display -->
                <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>
	
	<div class="row ">
		<div class="col-lg-12 " >
			 <div class="panel panel panel-warning">
				
				<div class="panel-heading"> 
					<i class="fa fa-picture-o"></i> 
					<div class="box-tools pull-right">
						<button class="btn btn-primary btn-sm pull-right" ng-model="collapsed" ng-click="collapsed=!collapsed" data-widget="collapse"><i class="fa fa-minus"></i></button>
					</div>
				</div>
				
				<div ng-dblclick="ajoutSurDblClick($event)" ng-show="!collapsed" class="panel-body table-responsive" style="min-height:700px;" id="bg">
					<div ng-repeat="a in appreciations" >
						<div  ng-style="{'position': 'absolute','margin-top':a.y,'margin-left':a.x}"><button ng-click="supprimer($index)"><span class="glyphicon glyphicon-remove" aria-hidden="true"></span></button><input ng-model="a.label" ></input></div>
					</div>
				
					
				</div>
				
				<div class="panel-footer text-right">
					<div class="form-group ">
					<button ng-click="sauver_appreciations()">Sauver Appreciations</button>
					</div> 
				</div>
				
			 </div>
		</div>
	</div>
		
	
	


	
	
	
	</div>
	
<!-- FIN DE DIV GLOABLE FLUID -->
</div>
	
</body>
</html>
<style>
#bg{
	background:url('img/modelFemme.png') no-repeat center center; margin-bottom:1px;
}
</style>

Le controleur, on voit que la fonction sauvegarder est déjà prête, il suffit d’envoyer le tableau d’objets JSON au Back END…

angular.module('neutre', [])

.controller('neutreCtrl', function($scope,$document) {
	
	$scope.appreciations =[]; // Les appréciations arrivent dans ce tableau en temps réel, ce sont des objets JSON

	$scope.supprimer = function($index){
		$scope.appreciations.splice($index, 1);     	
	}

	$scope.ajoutSurDblClick = function(event) {
			$scope.appreciations.push( {
				"label": "Info",
				"value": 100,
				"x": event.offsetX,
				"y": event.offsetY,
			})
		console.log($scope.appreciations);
	}

	$scope.sauver_appreciations = function(){
		alert('Pour le codeur, il suffit denregistrer le tableau json appreciations dans le back end');
	}

/* FIN DU CONTROLEUR */
});

 
  

#bg

[AngularJs 1.6] « Gère ton équipe » Micro app de gestion d’équipe de FOOTBALL avec Glissé-Déposé des joueurs

Sport-football-icon.pngIntroduction


Je dois passer sur un site wordpress perso, parce que j’ai peur que celui ci disparaisse.

Voici donc une micro app à laquelle j’attribue 2 heures * 4 jours, donc 8 heures, histoire de me remettre dans le coup avec pas mal de drag and drop . Attention, ceci est un labo, mais je compte faire d’autres apps du même style en particulier une de Chimie, qui va permettre de lier des ingrédients par glissé-déposé multiples et faire des calculs temps réel.

Le back end étant simulé, il n’est pas fait usage des IDS de façon conventionelle dans ce labo, du coup,il est normal que lorsque l’on recharge une équipe, les caractéristiques du joueur soient les caractéristiques de l’instant T de l’enregistrement , il ne s’agit par d’une erreur de conception, mais de la volonté de simuler un back end pour tester plus vite d’autres fonctionnalités. De même je n’ai pas fait de service exploitant la liste des joueurs, ce n’est pas le but du labo.

Photo de l’app à début + 3 heures


football.jpg

Le but de l’app :


Disposer d’un tableau de joueur et constituer les équipes par glissé déposé, sauvegarder les équipes et pouvoir les modifier. Lorsque l’on affecte un joueur dans la catégorie junior, alors l’image junior s’affiche automatiquement dans le tableau, et ainsi de suite (conditions dans la vue html)

A terme, on verra les photos des joueurs sur le terrain de foot ou les noms au choix( ça se fait en 2 secondes.).

Timing:

Jour 1 : 2 h de code : mise en place de la vue liste et du glissé déposé

Jour 2 : 2h30 de code : mise en place de la vue modifier et du glissé déposé bi-directionnel.

Jour 3 : 3h00 de code : sauvegarde des equipes sur localstorage, tests de réinit, pbs d’actualisation du tableau.

Jour 4 : 2h45 de code : Possibilité de maj un footballeur en web storage.

Jour 5 : 3h30 de code : Mise en place des sliders sur vue modifier, Mise en place de popups sur le stade. (reste à faire les doublons en cas de modif d’une équipe.

Jour 6 : 3h30 de code: J’ai un peu ramé : mise en place des popups différents et des futures statistiques en temps réel , avec graphiques qui s’affichent dans les popups. Grâce à ces statistiques, on va pouvoir évaluer en temps réel les caractéristiques de la globalité de l’équipe que l’on créée. Pourtester : supprimer le cache de son navigateur, puis relancer.

Jour 7 : 2h30 de code: Activation de AngularCharts. Lorsque l’on droppe un joueur, le graphique des statistiques se mets à jour en temps réel. Par contre il faut effacer tout le cache du navigateur pour tester, parce que j’utilise Webstorage pour simuler le back end, et le modèle de données reste en mémoire du navigateur. Ca marche vraiment pas mal, j’aime bien.

Jour 8 : 3h30 de code J’ai enfin trouvé un algorithme qui cache les footballers présent dans une équipe lors du chargement, grâce aux gros pros anglophones sur StackOverflow, ils sont trop balaises. Avec un back end sql ce serait plus facile à faire lol, c’est parce que je simule un back end avec webstorage que cela parait un peu tordu.

Voici la fonction, ça fait mal aux yeux, aie, et pourtant ca marche bien !


set_presence_equipe(); // Je ne mets pas la fonction... trop longue voir dans le code...

/* Sert à filtrer les joueurs qui ne sont pas dans l'équipe , pour pouvoir mettre à jour une équipe*/
		$scope.footballers = $filter('filter')($scope.footballers, function (i) {

			  return presence_equipe.indexOf(i.identifiant) === -1
		});

Maintenant je vais faire des belles vignettes que l’on peut glisser-déposer … Et ajouter d’autres graphiques, caractéristiques joueurs… j’aimerais aussi fare un BIG GRAPHIQUE comparatif de toutes les équipes , AngularJS c’est TROP BIEN ! Je vais aussi ajouter un calendrier, afin que l’on puisse glisser déposer des équipes à telle ou telle date… Un bon entrainement, ce labo !

Jour 9 : 2h30 de code (de 10 h à 12h30): remodelage des Vignettes… Affichage des barres de graphiques dans les vignettes. Le Look devient sympa peu à peu, supprimer le cache de son nav pour tester :

goal1.jpg

Si AngularJs 1.6 est si bien, c’est qu’il permet d’appliquer directement la théorie des ensembles, parce qu’il est non typé (de plus le back end type déjà les variables, totalement inutile de le faire dans le front end.). Voilà pourquoi IL NE FAUT PAS utiliser typescript ou angular 2 ou 4, en tout cas c’est mon avis, pour l’instant, j’attends qu’on me fasse changer d’avis, mais j’en doute, à vrai dire, ce n’est pas possible…

Jour 10: 3h de code : Mise en place de la lib du calendrier, Tentative de mise en place des ancres sur les vignettes de footballeurs, Fix de la barre supérieure. ALERTE ! Je viens de constater un bug lorsque l’on trie , puis que l’on glisse dépose un joueur, ça buggue ! A regarder demain d’urgence , problème d’id !!

Jour 11 j’ai résolu en 20 minutes au total le problème de glissé déposé après tri grâce à ce fantastique plunker : http://codef0rmer.github.io/angular-dragdrop/#!/filter . Autant dire que c’est trop bien maintenant . J’essaye d’acheter une tablette d’occase à 18 euros dès que possible afin de faire des apps pour tablettes avec glissé déposé, ça va péter. Aujourd’hui je m’occupe du dispatching par glissé-déposé des équipes dans l’agenda, si je ne peux pas faire de glissé-déposé, je ferais quelque chose de plus simple.. A par ça, c’est assez dur de faire un look normalisé et sympa, je dois faire des flêches pour passer d’une série de vignettes à l’autre, mais le pb est que sur un écran large, le nb de vignettes par lignes augmente, ce qui mets en défaut le ptit algo que je pourrais trouver. Autre problème : OU mettre le planning des futurs matches, sachant que je n’ai pas trop envie de faire des onglets. j’aimerais que l’on voit tout d’un seul coup, pas possible de mettre un POPUP comme pour les stats, il y en aurait trop !.

Jour 12 2h30 de code : j’ai finalement mis un onglet bootstrap pour l’endroit ou l’on va gérer les matches et entrainements. Du coup, la directive fixed heard du tableau ne marchait plus, j’ai du en faire un dans le html, c’est pas terrible mais sur mon écran cela marche . Je vais bientôt recevoir ma vieille tablette à 18 euros, une 9 pouces, ca pourra me permettre de commencer à faire des apps sur tablette et de voir si le glissé déposé marche bien dessus. Pour les vignettes, Je dois m’arranger pour les aficher 9 par 9 avec une bête pagination. dans l’idéal, il faudrait pouvoir noter les joueurs par matchs avec des étoiles, puis qu’une moyenne se créée, mais ce serait plus facile avec un vrai backend, parce que là vu que c’est un labo, je simule le back end.
ALERTE : je viens de voir que la MAJ refais bugguer le tri et l’affectation quand il y a l’onglet ui bootstrap !! Cet onglet fait bugger plein de trucs!!!!

Choses à revoir :

-Mise à jour d’une équipe ne marche pas,
-Mettre des étoiles aux joueurs,
– Montrer les stats par ‘lignées’ sur les stade, moyenne age et autres.
– Trouver un moyen d’aligner les 2 fenêtres ‘footballers’ et ‘gérer l’équipe’, c’est trop laid
– Emettre un son WAV de stade lors de l’affectation d’un joueur.
– Pour les filtres, mettre des gros icônes à la one again pour faire mieux. faire la partie ‘créer un footballer’
– Trouver un moyen d’ajouter le goal
– Résoudre les petits bugs de modèle de donnée dans certaines cases ( pbs peu important de syntaxe)
– Sur le pop up de stats, montrer le graph moyen d’une équipe de 2 ème div, 1ère div … Créer un autre pop up de stats plus complets sur click de bouton.

Sur la partie gérer les matchs :
– Faire des statistiques de succès en fonction de l’équipe affrontée,
– Pouvoir déplacer un match par glissé déposé,
– Sur les divers champs, faire du web scrapping pour chopper le nom des villes ou des clubs de football.
– Pouvoir noter chaque joueur d’une équipe par étoile après chaque matchs ( Avec le back end simulé ca v être relouds je préfèrerais du sql)

Jour 13 J’ai grenouillé pendant 4h30, le temps de passer le calendrier dans une vue (Ca faisait beaucoup de datas pour 2 onglets de toute façon), de revoir les css pour mettre des stats(moyennes) par ligne de joueurs. A finaliser demain, + ajouter l’image du corps humain joueur pour qu’on puisse noter ou il a mal actuellement ou le nombre de blessures + Traitement des entrainements, avec stats du joueur etc … Bon c’est du labo, pas du uml hein .. L’app n’est pas utilisable dans la tablette simple core qui rame à fond (Surtout au niveau du réseau) par contre les css bootstrap sont corrects. Je pense qu’il faut une tablette quad core et du 12 pouces pour envisager des apps pros avec cette techno.
Jour 14 et 15 A peu près 4h de code
– Début d’utilisation de l’agenda des matches. Vu qu’il n’y a pas de back end je vais encore plus ou moins simuler pour l’instant. Ce que je veux c’est que l’on puisse comparer les stats des équipes entre elles avant les matches.
– Sur la partie vignette, on voit les stas joueurs apparaitre dans les bulles (à généraliser)
– Ajouter le corps humain et la possib d’ajouter les blessures avec la derniere tech d’ajout à l’infini d’appreciations

Jour 16 1h30 de code
– Amélioration des css
– Normalisation du style
– Ajout de code

Jour 17 5h30 de code
– Amélioration des css
– Normalisation du style
– Début du code de la partie « Gérer les matches »

Tester l’app  :


Le lien est ici 

Le controleur à début +3 heures de code :


Explication sommaire :

Au début du controleur AngularJs, j’initialise les caractéristiques des joueurs de footballs dans le tableau d’objet JSON $scope.footballers, chaque footballer étant un objet JSON.

L’objet $scope.equipe est lui vide au début, ce qui est logique, puisque l’on a pas encore dispatché les joueurs dans l’équipe, lol.

Ensuite, et bien, losque l’on glisse-dépose un joueur dans l’équipe dans la vue html, et bien il est copié dans le tableau $scope.equipe.sousequipe et supprimé(caché) du modèle de données $scope.footballers.


 monApp.controller("liste", function($scope,$route,$location,$http,Notification) {
	$scope.limit = 5;

	$scope.footballers 			= [
	{'identifiant':1,'prenom':'Jean','nom':'Valjean','categorie':1,'ville':'Détroit','age':12,'date_embauche':'','salaire':'25'},
	{'identifiant':2,'prenom':'Aziz','nom':'Jojo','categorie':2,'ville':'Paris','age':14,'date_embauche':'','salaire':'25'},
	{'identifiant':3,'prenom':'Thierry','nom':'Goubert','categorie':1,'ville':'Paris','age':17,'date_embauche':'','salaire':'28'},
	{'identifiant':4,'prenom':'Roland','nom':'Chavert','categorie':2,'ville':'Paris','age':14,'date_embauche':'','salaire':'25'},
	{'identifiant':5,'prenom':'Gogok','nom':'Rodolphe','categorie':1,'ville':'Paris','age':17,'date_embauche':'','salaire':'28'},
	{'identifiant':6,'prenom':'Thierry','nom':'Goubert','categorie':1,'ville':'Paris','age':17,'date_embauche':'','salaire':'28'},
	{'identifiant':7,'prenom':'Gawivk','nom':'Gonzogues','categorie':2,'ville':'Paris','age':14,'date_embauche':'','salaire':'25'},
	{'identifiant':8,'prenom':'Thomas','nom':'Choubal','categorie':1,'ville':'Paris','age':12,'date_embauche':'','salaire':'28'}
	]
	$scope.equipe 						= {};
	$scope.equipe.attaquants 			= [];
	$scope.equipe.ailiers_gauche 		= [];
	$scope.equipe.attaquants_soutien 	= [];
	$scope.equipe.ailiers_droit 		= [];
	$scope.equipe.milieu_gauche 		= [];
	$scope.equipe.milieu_soutien		= [];
	$scope.equipe.milieu_droit			= [];
	$scope.equipe.defense_gauche		= [];
	$scope.equipe.defense_soutien		= [];
	$scope.equipe.defense_droit			= [];
	$scope.equipe.liberos				= [];

	$scope.modifier_footballeur = function(footballeur){
		$location.path('/modifier/'+footballeur.identifiant);
	}

	$scope.loadMore = function() {
		$scope.limit += 5;
	};

	 $scope.onOver = function(e) {
		angular.element(e.target).addClass("hover");
	  };
	  $scope.onOut = function(e) {
		angular.element(e.target).removeClass("hover");
	  };
	  $scope.onDrop = function(e) {
		angular.element(e.target).removeClass("hover").addClass("done");
	  };
/* FIN DU CONTROLEUR */
})

La vue liste.html à h+3heures :

<div class="row ">
<!-- TABLEAU -->
<div class="col-lg-9 " >
   <div class="panel panel-warning">
      <div class="panel-heading">
         <div class="hd1">
            <span class="glyphicon glyphicon-list-alt" aria-hidden="true"></span>  Footballers
         </div>
         <div class="spinner pull-right" ng-show="chargement"><img src="img/loader.gif" class="ajax-loader"/></div>
      </div>
      <div  class="panel-body " >
         <div style="overflow-y: auto;overflow-x: hidden;max-height: 550px; min-height:550px; " >
            <!--  id="test" -->
            <table  class="table table-bordered table-hover  " border="1"  >
               <thead fix-head>
                  <tr>
                     <th>Photo</th>
                     <th>Identifiant</th>
                     <th>Prénom</th>
                     <th>Nom</th>
                     <th>Catégorie</th>
                     <th>Ville</th>
                     <th>Age</th>
                     <th>Date d'embauche</th>
                     <th>Salaire</th>
                     <th>Editer</th>
                  </tr>
               </thead>
               <tbody >
                  <tr  ng-click="detail_footballeur(footballeur)"  ng-repeat="footballeur in footballers| limitTo: limit "  >
                     <td data-drag="true" data-jqyoui-options="{revert: 'invalid',appendTo: 'body',containment: 'window',scroll: false,helper: 'clone'}" ng-model="footballers" jqyoui-draggable="{index: {{$index}},animate:true}" >
                        <div ><img ng-src="img/{{footballeur.photo|| 'defaut.png'}}" class="icone"/></div>
                     </td>
                     <td>{{footballeur.identifiant}}</td>
                     <td>{{footballeur.prenom}}</td>
                     <td>{{footballeur.nom}}</td>
                     <td><img ng-src="{{footballeur.categorie == '1' && 'img/junior.png' ||footballeur.categorie == '2' && 'img/master.jpg'|| 'big-black-X.png'}}" class="icone"/></td>
                     <!-- Affiche une photo en fonction de la variable -->
                     <td>{{footballeur.ville}}</td>
                     <td>{{footballeur.age}}</td>
                     <td>{{footballeur.date_embauche  | date:"dd/MM/yyyy"}}</td>
                     <td>{{footballeur.salaire | currency:'€'}}</td>
                     <td><button ng-click="modifier_footballeur(footballeur)" class="btn btn-primary" aria-label="Left Align">Editer</button></td>
                  </tr>
               </tbody>
            </table>
         </div>
         <button ng-click="loadMore()">
            more
      </div>
      <div ng-if="footballeurs =='false' " class="alert alert-info">Pas plus de footballeurs avec ce filtre.</div>
   </div>
   <div class="panel-footer text-right">
   <button  ng-click="creer_footballeur()" class="btn btn-default "  alt="Ajouter">
   <span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Créer un footballeur</button></div>
</div>
<!-- STADE-->
<div class="col-lg-3 ">
<div class="panel panel-warning">
   <div class="panel-heading">
      <div class="hd1">
         <span class="glyphicon glyphicon-list-alt" aria-hidden="true"></span>  Equipe
      </div>
   </div>
   <div id="bg" class="panel-body"  >
      <div class="row">
         <div class="col-lg-4" ></div>
         <div class="col-lg-4 " >
            <div class="ui-widget-content" >
               <ol data-drop="true" class="caseJoueur" ng-model='equipe.attaquants' jqyoui-droppable="{multiple:true,onOver: 'onOver', onOut: 'onOut',  onDrop: 'onDrop'}" >
                  <b>Attaquant</b>
                  <li ng-repeat="fb in equipe.attaquants " ng-show="fb.prenom" data-drag="true" data-jqyoui-options="{revert: 'invalid', helper: 'clone'}" ng-model="list4" jqyoui-draggable="{index: {{$index}},animate:true}">
                     {{fb.prenom}}<!--  <button ng-click="supprimer($index)">Supprimer</button></li>
                        -->
                     <!--
                        <li class="placeholder" ng-hide="hideMe()"></li>
                        -->
               </ol>
            </div>
         </div>
         <div class="col-lg-4 " ></div>
      </div>
      <div class="row">
         <div class="col-lg-4 " >
            <div class="ui-widget-content" >
               <ol data-drop="true" class="caseJoueur" ng-model='equipe.ailiers_gauche' jqyoui-droppable="{multiple:true,onOver: 'onOver', onOut: 'onOut',  onDrop: 'onDrop'}" >
                  Ailier g
                  <li ng-repeat="fb in equipe.ailiers_gauche " ng-show="fb.prenom" data-drag="true" data-jqyoui-options="{revert: 'invalid', helper: 'clone'}" ng-model="list4" jqyoui-draggable="{index: {{$index}},animate:true}">
                     {{fb.prenom}}<!--  <button ng-click="supprimer($index)">Supprimer</button></li>
                        -->
               </ol>
            </div>
         </div>
         <div class="col-lg-4 " >
            <div class="ui-widget-content" >
               <ol data-drop="true" class="caseJoueur" ng-model='equipe.attaquants_soutien' jqyoui-droppable="{multiple:true,onOver: 'onOver', onOut: 'onOut',  onDrop: 'onDrop'}" >
                  Att Soutien
                  <li ng-repeat="fb in equipe.attaquants_soutien" ng-show="fb.prenom" data-drag="true" data-jqyoui-options="{revert: 'invalid', helper: 'clone'}" ng-model="list4" jqyoui-draggable="{index: {{$index}},animate:true}">
                     {{fb.prenom}}<!--  <button ng-click="supprimer($index)">Supprimer</button></li>
                        -->
               </ol>
            </div>
         </div>
         <div class="col-lg-4 " >
            <div class="ui-widget-content" >
               <ol data-drop="true" class="caseJoueur" ng-model='equipe.ailiers_droits' jqyoui-droppable="{multiple:true,onOver: 'onOver', onOut: 'onOut',  onDrop: 'onDrop'}" >
                  Ailier d
                  <li ng-repeat="fb in equipe.ailiers_droits" ng-show="fb.prenom" data-drag="true" data-jqyoui-options="{revert: 'invalid', helper: 'clone'}" ng-model="list4" jqyoui-draggable="{index: {{$index}},animate:true}">
                     {{fb.prenom}}<!--  <button ng-click="supprimer($index)">Supprimer</button></li>
                        -->
               </ol>
            </div>
         </div>
      </div>
      <div class="row">
         <div class="col-lg-4 " >
            <div class="ui-widget-content" >
               <ol data-drop="true" class="caseJoueur" ng-model='equipe.milieu_gauche' jqyoui-droppable="{multiple:true,onOver: 'onOver', onOut: 'onOut',  onDrop: 'onDrop'}" >
                  Milieu g
                  <li ng-repeat="fb in equipe.milieu_gauche " ng-show="fb.prenom" data-drag="true" data-jqyoui-options="{revert: 'invalid', helper: 'clone'}" ng-model="list4" jqyoui-draggable="{index: {{$index}},animate:true}">
                     {{fb.prenom}}<!--  <button ng-click="supprimer($index)">Supprimer</button></li>
                        -->
               </ol>
            </div>
         </div>
         <div class="col-lg-4 " >
            <div class="ui-widget-content" >
               <ol data-drop="true" class="caseJoueur" ng-model='equipe.milieu_soutien' jqyoui-droppable="{multiple:true,onOver: 'onOver', onOut: 'onOut',  onDrop: 'onDrop'}" >
                  Milieu
                  <li ng-repeat="fb in equipe.milieu_soutien " ng-show="fb.prenom" data-drag="true" data-jqyoui-options="{revert: 'invalid', helper: 'clone'}" ng-model="list4" jqyoui-draggable="{index: {{$index}},animate:true}">
                     {{fb.prenom}}<!--  <button ng-click="supprimer($index)">Supprimer</button></li>
                        -->
               </ol>
            </div>
         </div>
         <div class="col-lg-4 " >
            <div class="ui-widget-content" >
               <ol data-drop="true" class="caseJoueur" ng-model='equipe.milieu_droit' jqyoui-droppable="{multiple:true,onOver: 'onOver', onOut: 'onOut',  onDrop: 'onDrop'}" >
                  Milieu d
                  <li ng-repeat="fb in equipe.milieu_droit " ng-show="fb.prenom" data-drag="true" data-jqyoui-options="{revert: 'invalid', helper: 'clone'}" ng-model="list4" jqyoui-draggable="{index: {{$index}},animate:true}">
                     {{fb.prenom}}<!--  <button ng-click="supprimer($index)">Supprimer</button></li>
                        -->
               </ol>
            </div>
         </div>
      </div>
      <div class="row">
         <div class="col-lg-4 " >
            <div class="ui-widget-content" >
               <ol data-drop="true" class="caseJoueur" ng-model='equipe.defense_gauche' jqyoui-droppable="{multiple:true,onOver: 'onOver', onOut: 'onOut',  onDrop: 'onDrop'}" >
                  Défense gauche
                  <li ng-repeat="fb in equipe.defense_gauche " ng-show="fb.prenom" data-drag="true" data-jqyoui-options="{revert: 'invalid', helper: 'clone'}" ng-model="list4" jqyoui-draggable="{index: {{$index}},animate:true}">
                     {{fb.prenom}}<!--  <button ng-click="supprimer($index)">Supprimer</button></li>
                        -->
               </ol>
            </div>
         </div>
         <div class="col-lg-4 " >
            <div class="ui-widget-content" >
               <ol data-drop="true" class="caseJoueur" ng-model='equipe.defense_soutien' jqyoui-droppable="{multiple:true,onOver: 'onOver', onOut: 'onOut',  onDrop: 'onDrop'}" >
                  Défense Centrale
                  <li ng-repeat="fb in equipe.defense_soutien " ng-show="fb.prenom" data-drag="true" data-jqyoui-options="{revert: 'invalid', helper: 'clone'}" ng-model="list4" jqyoui-draggable="{index: {{$index}},animate:true}">
                     {{fb.prenom}}<!--  <button ng-click="supprimer($index)">Supprimer</button></li>
                        -->
               </ol>
            </div>
         </div>
         <div class="col-lg-4 " >
            <div class="ui-widget-content" >
               <ol data-drop="true" class="caseJoueur" ng-model='equipe.defense_droit' jqyoui-droppable="{multiple:true,onOver: 'onOver', onOut: 'onOut',  onDrop: 'onDrop'}" >
                  Défense droite
                  <li ng-repeat="fb in equipe.defense_droit " ng-show="fb.prenom" data-drag="true" data-jqyoui-options="{revert: 'invalid', helper: 'clone'}" ng-model="list4" jqyoui-draggable="{index: {{$index}},animate:true}">
                     {{fb.prenom}}<!--  <button ng-click="supprimer($index)">Supprimer</button></li>
                        -->
               </ol>
            </div>
         </div>
      </div>
      <div class="row">
         <div class="col-lg-4" ></div>
         <div class="col-lg-4 " >
            <div class="ui-widget-content" >
               <ol data-drop="true" class="caseJoueur" ng-model='equipe.liberos' jqyoui-droppable="{multiple:true,onOver: 'onOver', onOut: 'onOut',  onDrop: 'onDrop'}" >
                  Libéro
                  <li ng-repeat="fb in equipe.liberos " ng-show="fb.prenom" data-drag="true" data-jqyoui-options="{revert: 'invalid', helper: 'clone'}" ng-model="list4" jqyoui-draggable="{index: {{$index}},animate:true}">
                     {{fb.prenom}}<!--  <button ng-click="supprimer($index)">Supprimer</button></li>
                        -->
                     <!--
                        <li class="placeholder" ng-hide="hideMe()"></li>
                        -->
               </ol>
            </div>
         </div>
         <div class="col-lg-4 " ></div>
      </div>
   </div>
   <div class="panel-footer text-right">
      <button  ng-click="sauver_equipe()" class="btn btn-default "  alt="Ajouter">
      <span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Sauver l'équipe</button>
   </div>
</div>
<style>
   .img-container{
   position: relative;
   }
   #bg{
   background:url('img/stade.svg.png') no-repeat center center; height: 600px;
   }
   .caseJoueur{
   height:90px;-webkit-border-radius: 20px 20px 20px 20px;-moz-border-radius: 21px 20px 20px 20px;border-radius: 21px 20px 20px 20px;border:5px solid #FFEB66;background:rgba(227,220,211,0.9);-webkit-box-shadow: #B3B3B3 14px 14px 14px;-moz-box-shadow: #B3B3B3 14px 14px 14px; box-shadow: #B3B3B3 14px 14px 14px;
   overflow:auto;
   }
   .hover{
   background-color:orange;
   }
   .icone{
   width:65px;
   height:65px;
   }
</style>
<hr />

La vue index.html à h+3heures :

<!DOCTYPE html>
<html>
	<head>
	<meta http-equiv="X-UA-Compatible" content="IE=8" />
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Gère ton équipe</title>

		<!------------------------------------------------------------ CHARGEMENT DES LIBRAIRIES ------------------------------------------------>
        <!-- APPEL LIB JQUERY -->
		<script src="libs//jquery.min.js"></script>
        <script src="libs//jquery-ui.min.js"></script>
		<!-- APPEL LIB ANGULAR -->
        <script src="libs/angular.min.js"></script>
        <script src="libs/angular-route.min.js"></script>
        <script src="libs/angular-locale_fr-fr.js"></script>
		<script src="libs/angular-animate.min.js"></script>
		<script src="libs/angular-touch.min.js"></script>
		<!-- load ngmessages -->
		<script src="libs/angular-messages.js"></script>

		<!-- APPEL LIB ADDITIONELLE FORMATAGE DES INPUTS -->
		<script src="libs/angular-input-masks-standalone.min.js"></script>

		<!-- APPEL LIB ADDITIONELLE ANGULAR FILTER -->
		<script src="libs/angular-filter.min.js"></script>
		<!-- DRAG  -->
		<script src="libs/angular-dragdrop.min.js"></script>
		<!-- APPEL LIB ADDITIONELLE ANGULAR PAGINATION -->
		<script src="libs/dirPagination.js"></script>

		<!-- APPEL LIB ADDITIONELLE INFINTE SCROLL -->
		<script src="libs/scroll.min.js"></script>

		<!-- APPEL LIB ADDITIONELLE pour Faire scroller le header d'une table html  -->
		<script src="libs/fixed-table-header.min.js"></script> 

		<!-- APPEL LIB ADDITIONELLE  pour Trier une table dans ses headers  -->
		<script src="libs/angular-tablesort.js"></script>
		 		<link href="libs/tablesort.css" media="screen" rel="stylesheet" type="text/css" />

		 <!-- APPEL LIB ADDITIONELLE  pour Afficher des messages plus sympas que ALERT()  -->
		<script src="libs/angular-ui-notification.min.js"></script>
				<link  href="libs/angular-ui-notification.min.css" media="screen" rel="stylesheet" type="text/css" />

		<!-- APPEL LIB ADDITIONELLE RZSLIDER POUR FAIRE DES SLIDES DANS LES FILTRES OU AILLEURS-->
		<!-- <script src="libs/rzslider.min.js"></script>
				<link rel="stylesheet" type="text/css" href="libs/rzslider.css"/> -->

		<!-- BOOTSTRAP -->
		<!-- Latest compiled and minified CSS -->
				<link rel="stylesheet" href="libs/bootstrap.min.css" >

		<!-- Optional theme -->
				<link rel="stylesheet" href="libs/bootstrap-theme.min.css" >

		<!-- Latest compiled and minified JavaScript -->
		<script src="libs/bootstrap.min.js" ></script>

				<link rel="stylesheet" type="text/css" href="libs//font-awesome.css" />

		<!-- CSS DE L APPLICATION -->
        		<link href="css/style.css" media="screen" rel="stylesheet" type="text/css" />

		<!-- APPEL LIB ADDITIONELLE Angular UI -->
		<!-- <script src="libs/ui-bootstrap-tpls-2.3.1.min.js"></script>  -->
		<script src="libs/ui-bootstrap-tpls.min.js"></script> <!-- Version 0.6.0 -->

		  <!-- PERSO --------------------------------------------------------------------------------->

		  <!-- ROUTING DE VUES FRONT END ET MODULES ADDITIONELS ANGULARJS -->
		<script src="app.js"  ></script>

		<!-- CONTROLEURS (UN PAR VUE) -->
		<script src="controleurs/liste.js"  ></script>
		<script src="controleurs/modifier.js"  ></script>

		<!-- SERVICES : LES SERVICES PERMETTENT DE CREER DES REQUETES AJAX DISPONIBLES DANS TOUTE LES CONTROLEURS DE L'APPLICATION A LOISIR. ON S'EN SERT POUR LES FILTRES REDONDANTS SURTOUT, VU QUILS REVIENNENT SOUVENT, POUR ALLEGER LA SYNTAXE DU CODE -->
		<script src="services/services.js"  ></script>

		<!-- DIRECTIVES : LES DIRECTIVES SONT DES MORCEAUX DE CODE BATEAU PAR EXEMPLE POUR FORMATTER LE FORMAT DUN CHAMPS TELEPHONE -->
		<script src="directives/directives.js"  ></script>

		<!------------------------------------------------------- FIN DE CHARGEMENT DES LIBRAIRIES ------------------------------------------------->
	</head>

<!-- La page HTML générale -->
<body ng-app="monApp">

	<!-- La barre de navigation -->
	<nav class="navbar navbar-default " >
<div class="navbar-header">
			<a class="navbar-brand" href="#"><img src="img/Sport-football-icon.png" style="margin-top: -25px; height:65px;" class="img_entete"/>Football</a></div>
<form class="navbar-form navbar-left">
<div class="dropdown">
				  <button class="btn btn-primary dropdown-toggle d1" type="button" data-toggle="dropdown"> Choisir
				  <span class="caret"></span></button>
<ul class="dropdown-menu">
	<li><a href="#/liste" class=""> Liste</a></li>
	<li><a href="#/detail" 	class=""> Détail</a></li>
</ul>
</div>
</form>
	</nav>

	<!-- Cette balise NG-View va afficher les différentes vues, qui sont couplées a un controleur portant le même nom-->
<div ng-view></div>
</body>

#b3b3b3, #bg, #ffeb66

[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;
}


?>