Développement Web, Javascript

Base de données en Javascript avec TaffyDB

Posté par seiyar81 le 6 octobre 2014 | Laisser un commentaire (0)
TaffyDB

Lors de mes développements, une tâche qui revient quasiment à chaque fois est l’implémentation de la gestion de collection en Javascript. Faire une recherche dans une collection, ajouter/supprimer des éléments etc …

Si la gestion de ces opérations n’est pas compliquée il n’en reste pas moins que le plus simple est d’utiliser une librairie dédiée à cette gestion.

C’est alors qu’intervient TaffyDB, une librairie de gestion de base de données en Javascript.
Elle gère les opérations de type CRUD, est facilement extensible et est aussi bien utilisable en front avec jQuery et compagnie qu’en back via NodeJS par exemple.

Sans tarder voici ci dessous un exemple complet de ce qu’il est possible de faire avec la librairie :

	// Déclaration de la table employés
	var employees = new TAFFY([
		{"id":1,"gender":"M","first":"John","last":"Smith","branch":"Seattle, WA","department":1},
		{"id":2,"gender":"F","first":"Kelly","last":"Ruth","branch":"Seattle, TX","department":2},
		{"id":3,"gender":"M","first":"Jeff","last":"Stevenson","branch":"Washington, D.C.","department":1},
		{"id":4,"gender":"F","first":"Jennifer","last":"Gill","branch":"Seattle, WA","department":3}	
	]);
		
	// Déclaration de la table départements
	var departments = TAFFY([
	  {id: 1, name: 'Sales', abbreviation: 'SA'},
	  {id: 2, name: 'Accounting', abbreviation: 'AC'},
	  {id: 3, name: 'Human Resources', abbreviation: 'HR'}
	]);

Vous pouvez donc initialiser vos bases de données en récupérant le contenu d’une requête AJAX.

	
	// Tri sur la colonne last et récupération du premier de la liste
	employees.order("last").first().name;

	// Select sur la colonne branch et count
	employees({branch:"Seattle"}).count();

	// Update de la colonne branch
	employees({id:"1"}).update({ branch: "Washington, D.C." });

	// Delete
	employees({id:"4"}).remove();
	
	// Insert d'un nouveau département
	departments.insert({id: 4, name:"IT Support", abbreviation:"IT"});

Enfin sachez que les jointures sont gérées :


	// Jointure sur la table departments et récupération du nom du premier élément : Sales
	employees().join( departments, [ 'department', 'id' ]).first().name;

Attention si les deux tables jointes ont des noms de colonnes en commun alors le nom de colonne de la table jointe sera préfixé avec right_.

Et voilà il n’y a plus qu’à se servir des multiples fonctions de TaffyDB pour gérer au mieux ses jeux de données.

Catégorie: Développement Web, Javascript | Laisser un commentaire (0)

jQuery UI DatePicker : désactiver certains jours de la semaine

Posté par seiyar81 le 28 janvier 2014 | Laisser un commentaire (3)
jQuery UI DatePicker

jQuery UI propose bon nombre de widgets très utiles lorsqu’on développe des applications Web dynamiques.
Parmis ces derniers le DatePicker, ou calendrier, qui propose plusieurs options de configuration très précises.

Prenons par exemple le cas suivant : le client pour qui vous développez une application de réservation de restaurants vous informe que tous les réservations ne sont pas possibles les lundis et jeudis.

Et bien pas de problèmes, la fonction beforeShowDay permet de pré-filtrer chaque date et de définir si elle est sélectionnable ou pas.
Ce qui donne dans notre cas :


	jQuery(document).ready(function() {
		jQuery("#calendar").datepicker({
			beforeShowDay: function (date) {
				if (date.getDay() == 1 || date.getDay() == 4) { // La semaine commence à 0 = Dimanche
					return [false, ''];
				} else {
					return [true, ''];
				}
			}
		});
	});

Et voilà c’est tout simple.

On peut également utiliser la même méthode pour supprimer certaines semaines ou mois de l’année (vacances par exemple) :


	jQuery(document).ready(function() {
		jQuery("#calendar").datepicker({
			beforeShowDay: function (date) {
				if (date.getMonth() == 6 || date.getMonth() == 7) { // Mois Juillet et Août
					return [false, ''];
				} else {
					return [true, ''];
				}
			}
		});
	});

Si vous souhaitez par contre mettre une date minimum, utilisez plutôt l’option minDate :


	jQuery(document).ready(function() {
		jQuery("#calendar").datepicker({
			minDate: new Date(2014, 1 - 1, 1)
		});
	});

A vos claviers !

Catégorie: Développement Web, Javascript | Laisser un commentaire (3)

Remplir un formulaire avec jQuery

Posté par seiyar81 le 7 janvier 2014 | Laisser un commentaire (0)
jQuery Populate

Lorsque vous developpez une application Web, disons en PHP par exemple et que vous devez assigner vous-même les valeurs aux champs d’un formulaire, le mélange HTML/PHP peut vite s’avérer indigeste.

Si vous disposez de données JSON, ou de la possibilité de formater des données dans ce format, pour remplir votre formulaire, alors le plugin jQuery Populate devrait répondre à tous vos besoins.

Imaginons le formulaire HTML suivant :

	

Vous récupérez un jeu de données JSON via une requête AJAX ou bien directement formaté dans la page du type :

  var data = {

		name: "Yriase",

		type: ["0","2"],

		valider: false,

		comment: "Commentaire plus long"

	}

Grâce à Populate vous n’avez plus qu’à réaliser l’appel suivant :


	$('form["myform"]').populate(data);

Et le tour est joué !

Catégorie: Développement Web, Javascript | Laisser un commentaire (0)

FullCalendar : chargement et mise à jour des évènements dans une base de données

Posté par seiyar81 le 7 août 2013 | Laisser un commentaire (7)

Pour faire suite au précédent article présentant le plugin FullCalendar, nous allons voir comment charger des évènements depuis une base de données pour peupler notre calendrier et ensuite comment les mettre à jour.

Nous allons pour cela mettre en place un calendrier avec affichage simple (mois/semaine/jour) sur notre page web :


<html>
<head>
<link href='fullcalendar/fullcalendar/fullcalendar.css' rel='stylesheet' />
<link href='fullcalendar/fullcalendar/fullcalendar.print.css' rel='stylesheet' media='print' />
<script src='fullcalendar/jquery/jquery.min.js'></script>
<script src='fullcalendar/jquery/jquery-ui.min.js'></script>
<script src='fullcalendar/fullcalendar/fullcalendar.js'></script>

<style>

	body {
		margin-top: 40px;
		text-align: center;
		font-size: 14px;
		font-family: "Lucida Grande",Helvetica,Arial,Verdana,sans-serif;
		}

	#calendar {
		width: 900px;
		margin: 0 auto;
		}

</style>
</head>
<body>
<div id='calendar'></div>
</body>
</html>

Côté serveur, il va nous falloir une base de données, forcément, avec une table pour stocker les évènements pouvant ressembler à ceci :



--
-- Table structure for table `event`
--

CREATE TABLE IF NOT EXISTS `event` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `title` varchar(55) NOT NULL,
  `start` datetime NOT NULL,
  `end` datetime DEFAULT NULL,
  `allDay` tinyint(1) DEFAULT NULL,
  `url` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=2 ;

On va ensuite ajouter le code Javascript pour charger et mettre à jour les évènements :


    $(document).ready(function() {
	
        function updateEvent(event,dayDelta,minuteDelta,allDay)
        {
            $.ajax({ 'url': 'ajax.php?action=update', 'type': 'POST', 
                'data': {'id':event.id, 'dayDelta': dayDelta, 'minuteDelta': minuteDelta, 'allDay': allDay},
                success: function(data) {
                    if(data.error)
                        alert(data.error);
                },
                error: function(data) {
                   alert('Une erreur est survenue.'); 
                }
            });
        }
		
				$('#calendar').fullCalendar({
            header: {
    					left: 'prev,next today',
							center: 'title',
							right: 'month,agendaWeek,agendaDay'
						},
            editable: true,
            eventSources: [
                'ajax.php?action=get'
            ],
            eventDrop: function(event,dayDelta,minuteDelta,allDay,revertFunc) {    
                if (!confirm("Valider la modification ?")) {
                    revertFunc();
                } else {
                    updateEvent(event,dayDelta,minuteDelta,allDay);
                }
            },
            eventResize: function(event,dayDelta,minuteDelta,revertFunc) {
                if (!confirm("Valider la modification ?")) {
                    revertFunc();
                } else {
                    updateEvent(event,dayDelta,minuteDelta,0);
                }
            }
		});
		
	});

On note donc que le paramètre d’initialisation eventSources indique au calendrier une (ou plusieurs) url à interroger pour charger les évènements.
Le résultat attendu étant un tableau au format JSON.
Les callbacks eventDrop et eventResize sont appellés dès qu’un évènement est modifié sur le calendrier.
Si l’utilisateur valide l’action, alors on appelle la fonction updateEvent qui enverra la requête d’update au serveur.
Les paramètres dayDelta, minuteDelta et allDay correspondent aux modifications apportées à l’évènement.

Pour fournir ce tableau c’est très simple.
On va créer une page PHP pour recevoir et traiter les requêtes AJAX :


    $dsn = 'mysql:dbname=fullcalendar;host=127.0.0.1';
    $user = 'root';
    $password = 'root';

    if(isset($_GET['action']))
    {
        switch($_GET['action'])
        {
            case 'get':
                try {
                    $db = new PDO($dsn, $user, $password);
                    
                    $sql = 'SELECT * FROM event';
                    $events = array();
                    
                    foreach ($db->query($sql) as $row) {
                        $events[] = $row;
                    }
                    
                    echo json_encode($events);
                    
                } catch (PDOException $e) {
                    echo json_encode(array('error' => 'Connection failed: ' . $e->getMessage()));
                }                
                break;
            default:
                break;
        }
    }
    

Très simple donc, on contrôle l’action reçue en paramètre, si c’est get alors on renvoit un tableau contenant les évènement stockés dans la base de données.
Un simple json_encode des évènements suffit.

Avec ce code on possède donc un calendrier affichant nos évènements.
Pour maintenant mettre à jour nos évènements en base de données, il faut juste ajouter l’action update côté serveur :


case 'update':
  try {
    $db = new PDO($dsn, $user, $password);
    
    $query = $db->query('SELECT * FROM event WHERE id = ' . $_POST['id']);
    $event = $query->fetch(PDO::FETCH_ASSOC);
    
    // Mise a jour de la date
    $diff = calculateDiff($_POST['dayDelta'], $_POST['minuteDelta']);
    
    $newStart = DateTime::createFromFormat('Y-m-d H:i:s', $event['start']);
    $newStart->modify($diff);
    
    $newEnd = DateTime::createFromFormat('Y-m-d H:i:s', $event['end']);
    $newEnd->modify($diff);
    
    $sql = 'UPDATE event SET start = "'.$newStart->format('Y-m-d H:i:s').'",
    end = "'.$newEnd->format('Y-m-d H:i:s').'",
    allDay = "'.$_POST['allDay'].'"
    WHERE id = ' . $_POST['id'];
    $row = $db->query($sql);
    
    echo json_encode(array('updated' => true));
  
  } catch (PDOException $e) {
    echo json_encode(array('error' => 'Db error : ' . $e->getMessage()));
  } catch (Exception $e) {
    echo json_encode(array('error' => $e->getMessage()));
  }       
break;

Le traitement est assez simple, on utilise la classe DateTime pour calculer les changements de dates avec sa méthode modify et deux fonctions que l’on va utiliser pour transformer les dayDelta et minuteDelta en chaîne compréhensible par DateTime :


	function pluralize($string) 
  {
      preg_match("|^([0-9]+)(.*)|",$string,$matched);
      if($matched[1] > 1) {
          return number_format($matched[1]) . $matched[2] . 's';
      }
      return $string;
  }

  function calculateDiff($dayDelta, $minuteDelta)
  {
      if($dayDelta != 'null' && $dayDelta != '0') {
          if($dayDelta < 0)
              $diff = "-".pluralize(abs(intval($dayDelta))." day");
          else if($dayDelta > 0)
              $diff = "+".pluralize(intval($dayDelta)." day");
      }
      else
          $diff = "";

			if($minuteDelta != 'null' && $minuteDelta != '0') {
          if($minuteDelta < 0)
              $diff .= "-".pluralize(abs(intval($minuteDelta))." minute");
          else
              $diff .= "+".pluralize(intval($minuteDelta)." minute");
      }
        
      return $diff;
  }

Ces fonctions vont par exemple transformer dayDelta = +2 : +30 en la chaîne "+2 days"

Et voilà on a maintenant un calendrier affichant nos propres évènements et les enregistrant en base de données.

Catégorie: Développement Web, Javascript | Laisser un commentaire (7)

Des div toujours visibles avec Sticky, un plugin jQuery

Posté par seiyar81 le 5 juillet 2013 | Laisser un commentaire (1)
Sticky

Lorsqu’on développe des sites ou applications Web, on peut être amenés à vouloir garder une partie de la page toujours visible lorsqu’on scroll.
Que ce soit pour un effet esthétique ou pour une question de praticité comme avec une barre d’actions ou un menu de navigation par exemple.

Plusieurs manières existent pour réaliser cet effet, mais je parlerai ici d’un plugin jQuery : Sticky.

Ci-dessous un petit exemple d’un header toujours visible :

  Sticky
  
  
  
  

  
  

Une première div qui va disparaître.

Une deuxième div qui va disparaître.

Une troisième div qui va disparaître.

Nous centrons donc notre header en CSS et nous indiquons ensuite à Sticky via la propriété center:true que l’on souhaite qu’il reste centré une fois collé en haut de la page.

Sticky est léger et configurable via 5 options :

  • topSpacing: Pixels entre le haut de la page et le haut de l’élément
  • bottomSpacing: Pixels entre le bas de la page et le bas de l’élément
  • className: Classe CSS ajouté à l’élément et à son wrapper quand il est collé
  • wrapperClassName: Classe CSS ajouté au wrapper
  • getWidthFrom: Sélecteur d’un élément utilisé pour régler la largeur fixe de l’élément collé

Libre à vous d’utiliser le CSS que vous souhaitez pour placer/dessiner votre élément.

Pour récupérer le plugin ou y contribuer, direction Github.

Catégorie: Développement Web, Javascript | Laisser un commentaire (1)

Réaliser un scheduler AJAX avec jQuery et PeriodicalUpdater

Posté par seiyar81 le 21 mai 2013 | Laisser un commentaire (0)
jQuery

jQuery est un outil formidable.
Il fait non seulement partie des meilleurs frameworks du moment, je dis bien des car nombreux sont ceux qui rivalisent en terme de fonctionnalités, légèreté, et simplicité d’utilisation : ExtJS, Prototype, Mootools ou encore YUI pour ne pas les citer.

Mais sa véritable force, comme j’ai déjà pu l’évoquer avec le génial DataTables, réside dans la variété de plugins disponibles.

Nous nous intéressons ici à un plugin, qui est en fait un portage d’une fonctionnalité de Prototype vers jQuery, j’ai nommé PeriodicalUpdater.

Petit exemple concret : qui n’a jamais eu à mettre en place un rafraîchissement automatique du contenu d’une page Web à base de setInterval ? C’est fastidieux, pas pratique à écrire et s’écarte un peu de la logique d’utilisation d’un framework.

PeriodicalUpdater nous permet via une méthode unique de mettre en place une requête AJAX périodique, facilement paramétrable.

Rien de tel qu’un peu de code pour tout comprendre, la méthode prend trois paramètres : l’URL à interroger, les paramètres de la requête, une fonction callback.

Les paramètres ne sont ni plus ni moins que les paramètres normalement passés à une requête $.ajax classique avec en plus ceux de PeriodicalUpdater.

$('#myDiv').PeriodicalUpdater('/news/list/', 
{
        method: 'get',          // méthode; get ou post
        data: {},               // tableau de valeurs passées à l'URL - e.g. {nom: "Yriase", msg: "Hello World"}
        minTimeout: 1000,       // valeur de départ du timeout en millisecondes
        maxTimeout: 8000,       // valeur maximum du timeout en millisecondes
        multiplier: 2,          // valeur pour incrémenter le timeout si la réponse n'a pas changé (jusqu'à maxTimeout)
        type: 'text',           // type de la réponse : text, xml, json, etc.  Voir $.ajax
        maxCalls: 0,            // nombre maximum d'appels. 0 = pas de limite.
        autoStop: 0,            // arrête automatiquement la requête après plusieurs retours renvoyant les mêmes données. 0 = désactivé.
        autoStopCallback: function() { ... } // Callback a exécuter quand l'autoStop est déclenché
        cookie: {},             // configuration du cookie pour stocker le timeout
        verbose: 0              // niveau de verbosité des logs : 0=aucuns, 1=moyen, 2=tout 
}
, function(remoteData, success, xhr, handle) { 
    // this référence $('#myDiv') 
});

Il est également possible d’appeler librement la méthode sans l’attacher à un élément :

$.PeriodicalUpdater('/news/list/', {}, function(remoteData, success, xhr, handle) {});

Et voilà en quelques lignes vous avez paramétré votre scheduler 😉

Pour récupérer le plugin direction GitHub.

Catégorie: Développement Web, Internet, Javascript | Laisser un commentaire (0)

PHPUi : Du nouveau et des examples

Posté par seiyar81 le 26 février 2013 | Laisser un commentaire (0)

PHPUi Logo

Beaucoup de changements pour PHPUi, on avance petit à petit vers une librairie utilisable pour développer et créer ses interfaces utilisateurs.

La réécriture de la librairie avec les namespaces de PHP5 a apporté entre autres une meilleur abstraction et modularité des fonctionnalités.

Le support de jQuery ( et de jQuery Ui ) est toujours d’actualité mais est complété par le support de Javascript basique.
Cela nous permet de mieux intégrer dans nos pages des fonctionnalités simples mais nécessaires telles que l’ouverture de popup ou le clic sur un bouton sans avoir besoin d’un framework complet.

Un petit exemple :

	$button = new Xhtml\Element('button', array('onClick' => PHPUi::getInstance()->js()->console->log('[OnClick] Hello world !')), true, 'Click me !');
	$button->onMouseOver = $button->js()->console->log('[MouseOver] Hello world !');
	echo $button;

        $button2 = new Xhtml\Element('button', array('onClick' => PHPUi::getInstance()->js()->window->open("http://localhost/phpui/examples/","PHPUi Examples","menubar=1,resizable=1,width=350,height=250")), true, 'Open pop-up !');
        echo $button2;

Comme vous pouvez le voir, le chaînage des appels Javascript est pleinement supporté.

Cette fonctionnalité devrait également faire son apparition dans l’adapter jQuery en plus du support des spécificités de ce dernier.
A l’heure actuelle vous pouvez déjà réaliser ceci :

        $gs = PHPUi::getInstance()->gs(array('columns' => 16));
        $gs->addChild(new Xhtml\Element('h2', null, true, '16 Column Grid - 960Gs'));
        $gs->jquery()->click( $gs->js()->console->log("Hello from the console") ); 
        $gs->jquery()->click( 
            $gs->jquery()->ajax( 
                array( 
                    'url' => 'ajax.php', 
                    'type' => 'POST', 
                    'data' => array( 'html' => $jsonString ), 
                    'dataType' => 'html',
                    'success' => 'function(data) { $(".container_16").append(data); }' 
                ) 
            ) 
        );
        echo $gs;

Le chaînage des appels Javascript dans un appel jQuery est actuellement supporté.

Pour plus d’exemples ou d’informations voyez le GitHub du projet.

Catégorie: Développement Web, Javascript, PHP | Laisser un commentaire (0)

DataTables : Personnalisation du template

Posté par seiyar81 le 12 décembre 2012 | Laisser un commentaire (0)

Encore un article sur DataTables, et oui je dois bien me l’avouer, la librairie me plaît elle est très ouverte et flexible c’est donc tout normalement que je me permets de donner des petites astuces sur son utilisation.

Il existe une option de configuration que vous n’avez peut-être pas encore utilisée, car pas nécessairement configurable si on se sert de la version basique de DataTables, mais qui se révèle pourtant très utile.
Chaque tableau possède un header et un footer (balises <thead> et <tfoot>) qui servent à afficher un certain nombre de contrôles : pages, filtre etc …

Et bien le plugin nous offre la possibilité de pleinement configurer tout ça !
C’est donc via l’option de configuration sDom que l’on va choisir quoi afficher, et où.

Un petit exemple tout simple :

    $(document).ready(function() {
        $('#example').dataTable( {
            "sDom": '<"top"lp>rt<"bottom"if>'
        } );
    } );

Cette configuration inverse les contrôles par défaut, ceux du header se retrouvent dans le footer et vice-versa.

Mais plus intéressant cette option nous permet de rajouter des contrôles personnalisés. Imaginons que pour une raison particulière on ai besoin d’ajouter un filtre sur une colonne et que l’on ai envie de mettre ce filtre à la place du champ de recherche.

Rien de plus simple :

    

$(document).ready(function() {

        $.fn.dataTableExt.aoFeatures.push( {
                "fnInit": function( oSettings ) {
                    return $("<select id='filter'>...</select>").get(0); 
                }, 
                "cFeature": "S", 
                "sFeature": "Filtre" 
        } ); 

        $('#example').dataTable( { 
                     "sDom": '<"top"Si>rt<"bottom"lp>' 
              } 
        ); 

} );

Un petit coup de CSS et le tour est joué !

La prochaine fois je parlerai des options de filtrage, triage de DataTables.

Catégorie: Développement Web, Javascript | Laisser un commentaire (0)

PHPUi : créer et manipuler des interfaces utilisateurs en PHP

Posté par seiyar81 le 21 septembre 2012 | Laisser un commentaire (2)

PHPUi Logo

Je présente aujourd’hui un projet commencé pour mon mémoire de fin d’études, puis mis en pause, puis repris, puis complètement réécris …

Il s’agit d’une librairie qui permet de générer des interfaces utilisateurs en écrivant uniquement du PHP (ou presque :p).
Le but est de simplifier la vie aux développeurs qui souhaitent générer dynamiquement du code HTML/CSS ou Javascript côté serveur.
A l’heure actuelle, le support du CSS et du Javascript est en cours d’implémentation/optimisation.

La librairie se veut 100% objet PHP5, utilise les namespaces, est facilement extensible via une abstraction de la plupart de ses fonctionnalités, supporte l’autoload, utilise le pattern Observer etc …
De plus un support particulier des frameworks CSS 960gs et Blueprint a été implémenté (via le système d’abstraction, donc applicable à d’autres frameworks/librairies) afin de réellement faciliter la mise en place d’interfaces aux développeurs.

Si vous souhaitez plus d’infos sur les frameworks cités : 960gs, Blueprint.

Un petit exemple de code :

    $blue = PHPUi::getInstance()->blueprint(array('class' => 'container', 'id' => 'blueprint'));
    $blue->addChild(new Xhtml\Element('h2', array('span' => 24), true, '24 Column Grid - Blueprint'));
    $blue->addChild(new Xhtml\Element('div', array('notice' => true), true, 'This is a div with class notice'));
    $blue->addChild(new Xhtml\Element('div', array('error' => true), true, 'This is a div with class error'));
    $blue->jquery()->click( 
        $blue->jquery()->ajax( 
             array( 
                 'url' => 'ajax.php', 
                 'type' => 'POST', 
                 'dataType' => 'html',
                 'success' => 'function(data) { $("#blueprint").append(data); }' 
             ) 
        ) 
    );

On créé ici un nouvel élément utilisant l’adapter Blueprint, on peut donc directement initialiser des div de type error, notice ou alert en passant le paramètre à true. On applique ensuite un filtre jQuery qui au clic sur la div lancera un appel AJAX avec les paramètres donnés.
La librairie se charge ensuite de générer le code correspondant aux appels effectués.

Sachez qu’il est également possible de charger/décharger un ensemble d’éléments via un système d’adapter.
Exemple avec notre élément $blue de tout à l’heure :

     $dump = Xhtml\Dumper\DumperJson::dump( $blue );
     $loaderJson = new Xhtml\Loader\LoaderJson(array('content' => $dump));
     echo $loaderJson->load();

Ici on dump et on load un élément en JSON mais à terme il sera possible d’exporter/charger via n’importe quel format puisqu’il est possible de définir ses propres classes.

Si vous souhaitez regarder les exemples ou bien le code de la librairie, un dépôt Github existe :
https://github.com/seiyar81/phpui

La librairie est toujours en cours de développement, je suis donc ouvert aux propositions d’améliorations ou aux fonctionnalités à implémenter.

Catégorie: Développement Web, Javascript, PHP | Laisser un commentaire (2)

DataTables : Tri et filtre personnalisés des données

Posté par seiyar81 le 7 avril 2012 | Laisser un commentaire (2)

Un petit moment que je n’ai pas posté de tutoriel ou tout du moins d’articles plus techniques, mais l’occasion s’est présentée lorsque je suis tombé sur un problème avec la librairie DataTables.

Je dis volontairement librairie car aujourd’hui le plugin pour jQuery a tellement évolué qu’on peut le considérer comme une librairie à part entière.

Une des fonctionnalités très pratique et intéressante de DataTables est de permettre l’ajout de de fonctions personnalisées de tri et de filtrage sur les donénes des tableaux.

L’intérêt d’une telle pratique est de pouvoir offrir aux utilisateurs des fonctionnalités avancées de manipulation des données.

Pour commencer voici un exemple tiré permettant d’ajouter un filtrage pour des adresses IP : 

function ip2long (IP) {
 IP = IP.match(/^([1-9]\d*|0[0-7]*|0x[\da-f]+)(?:\.([1-9]\d*|0[0-7]*|0x[\da-f]+))?(?:\.([1-9]\d*|0[0-7]*|0x[\da-f]+))?(?:\.([1-9]\d*|0[0-7]*|0x[\da-f]+))?$/i); // Verify IP format.
 if (!IP) {        return false;
 }
 IP[0] = 0;
 for (i = 1; i < 5; i += 1) {        IP[0] += !! ((IP[i] || '').length);
     IP[i] = parseInt(IP[i]) || 0;
 }
 IP[4 + IP[0]] *= Math.pow(256, 4 - IP[0]);
 if (IP[1] >= IP[5] || IP[2] >= IP[6] || IP[3] >= IP[7] || IP[4] >= IP[8]) {
     return false;    }
 return IP[1] * (IP[0] === 1 || 16777216) + IP[2] * (IP[0] <= 2 || 65536) + IP[3] * (IP[0] <= 3 || 256) + IP[4] * 1;
}

$.fn.dataTableExt.oSort['ip_address-asc'] = function(a, b) {
	var ipA = ip2long(a);
	var ipB = ip2long(b);
	return ((ipA < ipB) ? -1 : ((ipA > ipB) ?  1 : 0));
};

$.fn.dataTableExt.oSort['ip_address-desc'] = function(a, b) {
	var ipA = ip2long(a);
	var ipB = ip2long(b);
	return ((ipA < ipB) ? 1 : ((ipA > ipB) ?  -1 : 0));
};

On a tout d’abord une fonction pour transformer une adresse IP en entier puis deux fonctions pour comparer deux adresses et les trier par ordre ascendant ou descendant.

Une fois ces fonctions ajoutées, il suffit de spécifier le type de données de la colonne lors de la déclaration du tableau :

$('#example').dataTable( {
        "aoColumns": [
             null,
             null,
             null,
             { "sType": "ip_address" },
             null
         ]
} );

Il est donc très simple d’ajouter des fonctions de tri si nos tableaux utilisent des données d’un format un peu exotique.
Plusieurs fonctions sont d’ailleurs disponibles dans la documentation de la librairie.

Si ces fonctions nous permettent d’améliorer le tri des données, on peut également ajouter des fonctionnalités de filtrage.
Imaginons l’exemple suivant : vous disposez d’un tableau listant des factures avec leur état et vous souhaitez filtrer ce tableau en fonction d’une liste de checkbox représentant chacune un état.
A chaque changement d’état d’une de ces checkbox vous souhaitez donc filtrer le tableau.


var etatsCheckbox = new Array("filtre_etat_1", "filtre_etat_2", "filtre_etat_3", "filtre_etat_4", "filtre_etat_5", "filtre_etat_6"); 

var etatsGlobal = null;

$("#filter_etat input").click(function(){
    if($(this).attr("id") != "no_filter_etat") {
	 if(!$(this).is(":checked")) {
               if(getEtatsFiltres().length == 0)
                      $("#no_filter_etat").attr('checked', 'checked');
               }
	       else
		   $("#no_filter_etat").removeAttr('checked');
	 } else if($(this).attr("id") == "no_filter_etat") {
               if(!$(this).is(":checked")) {
                      $("#filtre_etat_1").attr('checked', 'checked');
               } else {
		      for(var i = 0; i < etatsCheckbox .length; i++) {
			$("input[name="+etatsCheckbox [i]+"]").removeAttr("checked");
		      }
               }
         }
	 etatsGlobal = getEtatFiltres();
	 oTable.fnDraw();
});

function getEtatFiltres() {
	var f = new Array();
	if($("#no_filter_etat").is(":checked"))
           return null;
	else {
	   for(var i = 0; i < etatsCheckbox .length; i++) {
		if($("input[name="+etatsCheckbox [i]+"]").is(":checked"))
		      f.push($("input[name="+etatsCk[i]+"]").attr("value"));
	   }
	   return f;
	}
};

On a tout d'abord un tableau avec les id de nos checkbox, un tableau global qui sera utilisé pour le tri, puis une fonction qui a chaque clic va relancer le filtrage du tableau en effectuant quelques contrôles avant (si on coche "no_filter_etat" décocher les autres checkbox ou bien cocher "filtre_etat_1" par défaut) et enfin une fonction pour récupérer les attributs value des checkbox cochées.

Maintenant il ne nous reste plus qu'à ajouter notre fonction à l'API de DataTables :


$.fn.dataTableExt.afnFiltering.push(
	function( oSettings, aData, iDataIndex ) {
		var iColumn = 2; // Numéro de la colonne dans votre tableau
			
		if(etats === null)
			return true;
		
		var iEtat = aData[iColumn];
			
		if(iEtat) {
			if(iEtat.length == 0)
				return false;
			else if(etatsGlobal.indexOf(iEtat) >= 0) {
				return true;
			} else {
				return false;
			}
		} else {
			return true;
		}
	}
);

Petite explication : si la colonne ou est définie l'état de la facture est contenue dans notre tableau global etatsGlobal, elle sera affichée, sinon cachée.

C'est donc très simple et à la portée de tout le monde d'ajouter des fonctions de tri et de filtrage, à vos claviers !

Catégorie: Développement Web, Javascript | Laisser un commentaire (2)