[AngularJs] Calculer la moyenne des valeurs d’une colonne de table HTML, avec une seule fonction générique

Introduction

Une fonction qui prends en paramêtre le modèle de données de la table, et le nom de la colonne dont on veut calculer la moyenne .

 

Code




<table class="table table-striped table-bordered table-hover">
   <tr>
   <thead>
      <th>
         
         Période
      </th>
      <th title="Nombre de jours travaillés dans le mois">Nbre de JT </th>
      <th title="Nombre d'appels par jours">
         
         Nb Appels
      </th>
      <th title="Nombre d'appels par jours">
         
         Nbre d'appels/jour
      </th>
      <th title="Nombre de fiches traitées">
         
         Nbre fichestraitées
      </th>
      <th>
         
         Heures Tr 
      </th>
      <th>
         
         Appels/heure
      </th>
      <th>
         
         Tx de rotation
      </th>
      <th>
         
         Nbre contacts PDG
      </th>
      <th>
         
         Nbre contact / JT
      </th>
      <th>
         
         Tx contact
      </th>
      <th>
         
         Nbre de devis créés
      </th>
      <th>
         
         Tx d'accroche devis
      </th>
      <th>
         
         Tx d'efficacité de vente
      </th>
      <th>
         
         Tx efficacité entrant
      </th>
      <th>
         
         Tx efficacité sortant
      </th>
      <th>
         
         Nb de ventes
      </th>
      <th>
         
         Nb Ventes  entrantes
      </th>
      <th>
         
         Nb Ventes sortantes
      </th>
      <!-- <th>Ventes opé</th>	 -->
   </thead>
   <thead>
      <th>
         
         <i class="fa fa-calendar  bg-secondary p-2 font-xl mr-3  ">
      </th>
      <th>
         
         <i class="fa fa-industry  bg-primary p-2 font-xl mr-3 pull-center "> </i>
      </th>
      <th title="Nombre d'appels par jours">
         
         <i class="fa fa-phone  bg-primary p-2 font-xl mr-3 pull-center "> </i>
      </th>
      <th title="Nombre d'appels par jours">
         
         <i class="fa fa-phone  bg-secondary p-2 font-xl mr-3 pull-center "></i>
      </th>
      <th title="Nombre de fiches traitées">
         
         <i class="fa fa-map-o  bg-primary p-2 font-xl mr-3 pull-center "></i>
      </th>
      <th>
         
         <i class="fa fa-industry  bg-primary p-2 font-xl mr-3 pull-center "></i>
      </th>
      <th>
         
         <i class="fa fa-repeat  bg-warning p-2 font-xl mr-3 pull-center "></i>
      </th>
      <th>
         
         <i class="fa fa-eur  bg-secondary p-2 font-xl mr-3  ">
      </th>
      <th>
         
         <i class="fa fa-user-plus  bg-danger p-2 font-xl mr-3 "></i>
      </th>
      <th>
         
         <i class="fa fa-user-plus  bg-secondary p-2 font-xl mr-3 "></i>
      </th>
      <th>
         
         <i class="fa fa-user-plus  bg-secondary p-2 font-xl mr-3  "></i>
      </th>
      <th>
         
         <i class="fa fa-file-o  bg-secondary p-2 font-xl mr-3  "></i>
      </th>
      <th>
         
         <i class="fa fa-file-o  bg-secondary p-2 font-xl mr-3  "></i>
      </th>
      <th>
         
         <i class="fa fa-thumbs-o-up  bg-secondary p-2 font-xl mr-3  "></i>
      </th>
      <th>
         
         <i class="fa fa-thumbs-o-up  bg-secondary p-2 font-xl mr-3  "></i>
      </th>
      <th>
         
         <i class="fa fa-thumbs-o-up  bg-secondary p-2 font-xl mr-3  "></i>
      </th>
      <th>
         
         <i class="fa fa-eur  bg-secondary p-2 font-xl mr-3  "></i>
      </th>
      <th>
         
         <i class="fa fa-eur  bg-secondary p-2 font-xl mr-3  "></i>
      </th>
      <th>
         
         <i class="fa fa-eur  bg-secondary p-2 font-xl mr-3  "></i>
      </th>
      <!-- <th>Ventes opé</th>	 -->
   </thead>
   </tr>
   <tr>
      <td> {{::s.nom}}</td>
      <td> {{::s.nb_j_travailles}}</td>
      <td> {{::s.nb_appels}}</td>
      <td> {{(s.nb_appels / s.nb_j_travailles) | number: 2}}</td>
      <td> {{::s.nbfiches_creees}}</td>
      <td> {{::s.heures_mensuelle}}</td>
      <td> {{(s.nb_appels / s[$index].travail_mois) | number: 2 }}</td>
      <td> {{}}</td>
      <td> {{::s.nb_contacts}}</td>
      <td> {{}}</td>
      <td> {{}}</td>
      <td> {{::s.nbdevis_crees}}</td>
      <td> {{(s.nbdevis_crees/s.nb_argus) | number: 2}}</td>
      <td> {{::s.tx_efficacitevente}}</td>
      <td> {{::s.tx_efficaciteventeentrant}}</td>
      <td> {{::s.tx_efficaciteventesortant}}</td>
      <td> {{::s.nb_vente}}</td>
      <td> {{::s.nb_venteentrant}}</td>
      <td> {{::s.nb_ventesortant}}</td>
      <!-- <td> {{}}</td> -->
   </tr>
   <tr>
      <td>Moyenne</td>
      <td>{{ctrl.calculer_moyenne(ctrl.sc,'nb_j_travailles')}}</td>
      <td>{{ctrl.calculer_moyenne(ctrl.sc,'nb_appels')}}</td>
      <td></td>
      <td>{{ctrl.calculer_moyenne(ctrl.sc,'nbfiches_creees')}}</td>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
   </tr>
   <tr>
      <td>Total</td>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
   </tr>
</table>


La fonction :

this.calculer_moyenne = function(modele, champs) {

    if (modele) {
        var sum = 0;
        for (var i = 0; i < modele.length; i++) {

            if (modele[i][champs]) {
                sum += parseInt(modele[i][champs], 12); //don't forget to add the base 
            }
        }

        var avg = sum / modele.length;

        return (avg).toFixed(2);
    }

}
Publicités

[AngularJs 1.6.2] Communiquer des variables à des components

Introduction

On a 20 graphiques à réaliser, tous avec la même emprunte pattern de modèle de données , on va forcément éviter de créer 20 controllers pour gérer tout ça .
On tente donc de créer un component angularJS qui permet de simplifier tout cela , car on peut lui passer des variables.

Note : La v 1.7 de AngularJs gère le transfert de datas aux components un peu différement.

Lien :

https://stackoverflow.com/questions/53170065/angularjs-template-component-not-rendering-variables

[AngularJs + PHP] Un infinite Scroll sur une table HTML

Introduction :
Un infinite scroll permet à l’utilisateur d’avoir la sensation de lire toutes les données d’une table même si il y en a des milliers, sans faire défaillir le front end .

Fonctionnement :
On charge les enregsitrements (row) 20 par 20 .
Au début on est à 0, puis, JQUERY détecte lorsque l’on atteint la fin de la div (bottom), il relance alors à chaque fois la requete SQL dans le Back End, tout en renvoyant le dernier ID acquis, afin de pouvoir faire un +20 . La lecture de la table devient très smooth et super rapide, la vue en elle même se charge instantanément ! on push à chaque fois les 20 enregistrements suivants dans le modèle de données, qui s’affiche alors dans la table HTML.

infintescroll.png

Lire la suite

[AngularJs] Communiquer avec un ng-repeat parent ( nested ng-repeats)

Introduction

On peut intéragir avec l’objet du ng-repeat parent, en modifiant des choses dans le ng-repeat enfant .
Attention, avec Chrome, il faut utiliser ng-change() dans les select , et pas de ng-click.

Exemple des filtres:
ON récupère le $index du parent avec outerIndex
Ainsi on peut ensuite modifier des variables dans le parent, de par la fonction de l’enfant ng-change().
element est un objet parent provoqué par le ng -repeat et contient des selects aux objets uniques.

Astuce : si on enregsitre tout le modèle de données JSON dans un champs de bdd avec Serialize, ensuite, on retrouve tout tout de suite, tout simplement en désarialisant l’objet puis en l’affectant à la variable JS, et cela en quelques instants un peu comme en big data .
 

		<li class="list-group-item" ng-repeat="element in $ctrl.filtres" ng-init="outerIndex=$index"> 
			<b>Mon critère numéro {{$index}} :</b><br>
					
			<select ng-options="champs.column_name as champs for champs in $ctrl.table  " 
				ng-model="element.champs"  ng-change="$ctrl.verify_data_type(outerIndex,element.champs)" ng-init="innerIndex=$index"> -->
			 <option value=""> </option>
			 </select> 
			
			 <select ng-model="element.champs"  ng-change="$ctrl.verify_data_type(outerIndex,element.champs)" ng-init="innerIndex=$index" class="form-control" >  
				<option value="">Champs</option> 
				 <option  ng-repeat ="champs in $ctrl.table"   value="{{champs.column_name}}" >{{champs.column_name}}</option> 
			 </select> 
			
			
			
			
			<select ng-model="element.operateur" class="form-control"  >
				<option value="">Opérateur</option>
				<option ng-repeat ="operateur in $ctrl.operateurs" value="{{operateur.nom}}" >{{operateur.traduction}}</option>
			</select>
			
			<input ng-if="element.showText" 	ng-model="element.critere" 		type ="text"  	class="form-control" placeholder="Votre recherche" 		title="Entrez plusieurs critères avec des virgules" required></input>
			<input ng-if="element.showDate" 	ng-model="element.critere" 		type ="date"  	class="form-control" placeholder="Une date" 			required></input>
			<input ng-if="element.showInteger " ng-model="element.critere" 		type ="number"  class="form-control" placeholder="Un nombre" 			required></input>
		</li>

Un exemple de fonction qui agit sur le ng-repeat parent, grâce à $index : outerIndex, c’est compatible avec CHROME :

     this.verify_data_type = function(outerIndex,champs){
            
			 console.log(outerIndex);
			 
			 console.log(champs);
			 
			
			
            switch(champs.data_type) {
                case 'integer':
                    this.filtres[outerIndex].showInteger = true;
                    this.filtres[outerIndex].showDate = false;
                    this.filtres[outerIndex].showText = false;
                    break;
                case 'date':
                    this.filtres[outerIndex].showInteger = false;
                    this.filtres[outerIndex].showDate = true;
                    this.filtres[outerIndex].showText = false;
                    break;
                case 'character varying':
                    this.filtres[outerIndex].showInteger = false;
                    this.filtres[outerIndex].showDate = false;
                    this.filtres[outerIndex].showText = true;
                    break;
                default:
                    this.filtres[outerIndex].showInteger = false;
                    this.filtres[outerIndex].showDate = false;
                    this.filtres[outerIndex].showText = true;
            } 
		}

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

[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