[AngularJs] un autocomplete asynchrone sur base de données avec Js-Custom-Select

Introduction :


Avec AngularJs, on est vite tenté de charger tout un modèle de données en mémoire vive, même pour l’afficher dans un select dropdown, c’est tellement facile … Par exemple comme ici :https://desgeeksetdeslettres.com/programmation-java/auto-completion-avec-angularjs

Pourtant, c’est forcément couteux dès que l’on a des centaines d’objets, d’ou l’idée de réserver la partie recherche au BACK END dès que les résultats dépassent la centaine de cas, en gros .

Qu’entends–t-on par modèle de données ? Par exemple : Toutes les villes de France (Des milliers), tous les utilisateurs de facebook (Des millions). Alors évidemment, on ne va pas tout charger dans le Front End et donc faire du asynchrone.

Pour parler basiquement, il faut qu’ à chaque fois que l’on tape une touche dans un champs INPUT, une requête SQL recherche les occurences dans la base de données, et remontent les resultats au format tableau d’objets JSON  (ARRAY [{},{},{},etc ….]). Ces résultats s’affichent alors dans notre select dropdown, afin de pouvoir faire notre choix.

C’est ce que permet de faire https://github.com/axel-zarate/js-custom-select.

Photo exemple de l’autocomplete sur base de données :

moumoute

Le code :

Je passe sur l’installation de js-custom-select qui est bien expliquée dans le github…


Dans la vue HTML, je mets mon SELECT :

<div custom-select="personne.lastName  for personne in searchAsync($searchTerm)" custom-select-options="{ 'async': true }" ng-model="custom2">
    <div class="pull-left" style="width: 40px">
        <img ng-src="{{ personne.image || 'img_app/gender_neutral_user1600_g.png' }}" style="width: 30px" /></div>
    <div class="pull-left">
        <strong>{{ personne.firstName}}</strong>

        <span>{{ personne.lastName}}</span></div>
    <div class="clearfix"></div>
</div>

On voit que on va afficher les objets personnes qui vont satisfaire le critère $searchTerm. En fait, dès qu’on va écrire dans le select, angularJs va exécuter searchAsync($searchTerm) , $searchTerm étant ce que l’on vient d’écrire. La recherche va se faire sur le lastName (le nom, en anglais)

Dans mon controleur MVC angularJS , j’ai cette fonction :

var wsUrl = 'web_services/mes_web_services.php';

$scope.searchAsync = function(term) {

  if (!term) {
    return false;
  }

  var putResponse;
  var promise = $http.post(wsUrl, {
    readPersonnes: JSON.stringify({
      'lastName': term
    })
  }).then(function(data, status, headers, config) {
    putResponse = data.data;
    console.log(putResponse); // this gets called after the server responds ( defined )
    return putResponse;

  })
  console.log(putResponse); // this gets called before the server responds ( undefined )
  return promise;

};

On voit qu’une requête HTTP est exécutée vers la base de données lors de chaque changement de la variable ‘term’ dans le select.

Et enfin, mon code BACK END en PHP MYSQLI, qui retourne à chaque fois la ou les réponses au format Array d’objets JSON habituel :

if(!empty($_POST["readPersonnes"])){
       $json = $_POST["readPersonnes"];
	$data = json_decode($json); 
  	echo json_encode($db->readPersonnes($data));
} 
  
  
// Read Personnes
public function readPersonnes($data)
{
	$sql = " SELECT p.* WHERE 1=1 ";
	

	if ($data->lastName) {
	   
		$sql .= " AND p.lastName LIKE '" .$data->lastName. "%'";
	}

	$responseArray = array();
	
	if ($result = $this->conn->query($sql)) {
		while ($obj = $result->fetch_object()) {
			array_push($responseArray, $obj);
		}
		mysqli_free_result($result); // Free result set
	}
	
	mysqli_close($this->conn);
	return $responseArray;
}

Explication : Si le back end detecte la présence de $data->lastName , alors, il filtre avec LIKE « nomDeLaPersone % » sur le nom, le % veut dire qu’il cherche avec toutes les lettres possibles derrière la variable.
Si l’on ne recherche rien, alors aucun modèle de données n’est chargé, grace à

if (!term) {
return false;
}

NOTE : Ici je fait un select *, mais bien sur, je peux restreindre plus afin de soulager encore le traitement, je peux faire un p.lastName, p.id par exemple dans le select à la place de p.*
Pourquoi le WHERE 1 = 1 ? Et bien c’est pour pouvoir créer des requêtes SQL à la volée qu’on doit écrire cela.

Conclusion :

Avec cette méthode, on obtient des applications pas du tout couteuses, qui ne chargent pas des tas de modèles de données lorsqu’il y a plus de 5 champs autocomplete simultanés porant sur des modèles de données différents (Par exemple : Personnes, Villes, Départements …) dans une vue par exemple.

En d’autres terme, dès que l’on peut soulager le front end, on le fait , avec cette méthode, on peut rechercher sur des millions d’occurences sans dommage pour la mémoire vive .

Il ne nous reste plus qu’à afficher un petit LOADER avec ng-show pour rassurer l’utilisateur … Qui comprends bien qu’une requête SQL est en cours même sans être informaticien.

Note : Avec Jquery, c’est plus facile …

Publicités

[AngularJs + Php-SQL] Astuce : Copier-Coller des CRUDS pour aller plus vite.

angularjsphp_1_logo-mysql-170x170_400x400

Introduction


Dans les applications informatique, le CRUD revient tout le temps.

Il s’agit de faire de la Creation/Lecture/Mise à jour/Suppression.

L’idée est donc de faire du copié-collé d’un crud standard, puis de changer uniquement le nom du modèle de données, en faisant « controle+h » dans notepad, afin d’aller beaucoup plus vite.

Note : Java Hibernate permettrait de faire cela encore plus simplement( méthode comin’ soon ), sans compter les méthodes de création automatiques des POJO, mais ce n’est pas le sujet de ce post … Là on est sur du back end PHP-MYSQL

Un exemple en temps réel dans une App !


Dans mon application RdvJuristes, j’ai un Crud sur les personnes :

http://nicolash.org/rdvj/index.html#/personnes

crd1.jpg

 

Il est évident que je ne vais pas me retaper tout le code pour créer un CRUD sur les juristes :

http://nicolash.org/rdvj/index.html#/juristes

crd2.jpg

On comprends qu’on a affaire à 2 modèles de données relativement similaires, que l’on peut copier-coller, puis, ensuite adapter à notre convenance.

Lire la suite

[HighCharts] Elaborer une statistique simple avec High Charts dans une application SAAS.

highcharts-logo

Introduction


Dans l’application RdvJuristes, je décide de calculer la somme des notes de frais de tous les rendez vous de la semaine en cours, puis de les afficher dans un graphique High Charts en barres.

Technologie utilisée


  • Highcharts
  • Php-Mysql en technologie PDO pour le back end
  • AngularJs pour le front end

Ordonnancement


  1. Examiner la conception de la base de donnée relationnelle.
  2. Elaborer la requête SQL
  3. Concevoir le Back End
  4. Concevoir le Front End
  5. Tester.

Lire la suite

[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