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)

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)

DataTables en version beta 1.7

Posté par seiyar81 le 28 mai 2010 | Laisser un commentaire (0)

Datatables ce plugin pour jQuery, que j’ai déjà présenté par deux fois, permettant la gestion des tableaux HTML créé et maintenu par Allan Jardine viens d’être mis à jour en version beta 1.7.

Au programme, plusieurs corrections de bug concernant les cookies, les performances, les données, l’ajout du scrolling vertical et horizontal dans le tableau, on peut maintenant récupérer l’objet dataTables créé ou bien d’empêcher qu’on le récupère etc.
Pour essayer cette nouvelle version, plus d’infos sur la page officielle du plugin.
Catégorie: Brèves, Développement Web, Javascript | Laisser un commentaire (0)

DataTables : base de données, traduction et jQuery-UI

Posté par seiyar81 le 2 février 2010 | Laisser un commentaire (17)

J’avais présenté ce fabuleux plugin pour jQuery qu’est Datatables et expliqué rapidement ce dont il est capable.
Aujourd’hui je vous propose une mise en situation, avec comme objectif l’interaction avec une base de données, une traduction en français (ou une autre langue parmi les 29 disponibles), la mise en forme avec l’aide jQuery-UI, et d’autres fonctionnalités.

Tout d’abord si vous ne possédez pas encore le plugin téléchargez-le ici.
Ensuite nous allons placer le code de notre tableau dans notre page, imaginons que l’on souhaite afficher des utilisateurs :

<table id="datatable" >
  <thead>
       <tr>
            <th>Nom</th>
            <th>Prénom</th>
            <th>Inscription</th>
            <th>Mail</th>
            <th></th>
        </tr>
  </thead>
 <tbody>
       <tr>
            <td colspan="4">Chargement des données...</td>
        </tr>
  </tbody>
</table>

Maintenant le code Javascript. Nous allond indiquer que l’on souhaite récupérer les données via un fichier côté serveur :

$(document).ready(function() {
	$('#datatable').dataTable( {
		"bProcessing": true,
		"bServerSide": true,
		"sAjaxSource": "get_data.php"
	} );
} );

Le plugin ira donc récupérer le fichier get_data.php pour remplir le tableau. Les données renvoyées par le fichier php doivent être au format JSON.
Voici un exemple du contenu de get_data.php inspiré de la documentation de Datatables mais vous êtes libre de modifier le code pour utiliser PDO, ou une autre méthode d’accès à la base de données si vous utilisez un autre SGBD que MySQL.

<?php
  /* MySQL connection */
	$gaSql['user']       = "username";
	$gaSql['password']   = "password";
	$gaSql['db']         = "mydb";
	$gaSql['server']     = "localhost";
	$gaSql['type']       = "mysql";
	
	$gaSql['link'] =  mysql_pconnect( $gaSql['server'], $gaSql['user'], $gaSql['password']  ) or
		die( 'Could not open connection to server' );
	
	mysql_select_db( $gaSql['db'], $gaSql['link'] ) or 
		die( 'Could not select database '. $gaSql['db'] );
	
	/* Paging */
	$sLimit = "";
	if ( isset( $_GET['iDisplayStart'] ) )
	{
		$sLimit = "LIMIT ".mysql_real_escape_string( $_GET['iDisplayStart'] ).", ".
			mysql_real_escape_string( $_GET['iDisplayLength'] );
	}
	
	/* Ordering */
	if ( isset( $_GET['iSortCol_0'] ) )
	{
		$sOrder = "ORDER BY  ";
		for ( $i=0 ; $i<mysql_real_escape_string( $_GET['iSortingCols'] ) ; $i++ )
		{
			$sOrder .= fnColumnToField(mysql_real_escape_string( $_GET['iSortCol_'.$i] ))."
			 	".mysql_real_escape_string( $_GET['sSortDir_'.$i] ) .", ";
		}
		$sOrder = substr_replace( $sOrder, "", -2 );
	}
	
	/* Filtrage - Remplace le filtrage côté client, peut donc être long si la base de données est importante
	 */
	$sWhere = "";
	if ( $_GET['sSearch'] != "" )
	{
		$sWhere = "WHERE nom LIKE '%".mysql_real_escape_string( $_GET['sSearch'] )."%' OR ".
		                "prenom LIKE '%".mysql_real_escape_string( $_GET['sSearch'] )."%' OR ".
		                "inscription = '".mysql_real_escape_string( $_GET['sSearch'] )."' OR ".
		                "mail = '".mysql_real_escape_string( $_GET['sSearch'] )."'";
	}
	
	$sQuery = "SELECT SQL_CALC_FOUND_ROWS id, nom, prenom, inscription, mail FROM users $sWhere $sOrder $sLimit";
	$rResult = mysql_query( $sQuery, $gaSql['link'] ) or die(mysql_error());
	
	$sQuery = "SELECT FOUND_ROWS()";
	
	$rResultFilterTotal = mysql_query( $sQuery, $gaSql['link'] ) or die(mysql_error());
	$aResultFilterTotal = mysql_fetch_array($rResultFilterTotal);
	$iFilteredTotal = $aResultFilterTotal[0];
	
	$sQuery = "SELECT COUNT(id)	FROM users";
	$rResultTotal = mysql_query( $sQuery, $gaSql['link'] ) or die(mysql_error());
	$aResultTotal = mysql_fetch_array($rResultTotal);
	$iTotal = $aResultTotal[0];
	
	$sOutput = '{';
	$sOutput .= '"sEcho": '.intval($_GET['sEcho']).', ';
	$sOutput .= '"iTotalRecords": '.$iTotal.', ';
	$sOutput .= '"iTotalDisplayRecords": '.$iFilteredTotal.', ';
	$sOutput .= '"aaData": [ ';
	while ( $aRow = mysql_fetch_array( $rResult ) )
	{
		$sOutput .= "[";
		$sOutput .= '"'.addslashes($aRow['nom']).'",';
		$sOutput .= '"'.addslashes($aRow['prenom']).'",';
		$sOutput .= '"'.addslashes(date('H:i d/m/Y', $aRow['inscription'])).'",';
		$sOutput .= '"'.addslashes($aRow['mail']).'"';
		$sOutput .= '"Détails"';
		$sOutput .= "],";
	}
	$sOutput = substr_replace( $sOutput, "", -1 );
	$sOutput .= '] }';
	
	echo $sOutput;
	
	
	function fnColumnToField( $i )
	{
		if ( $i == 0 )
			return "nom";
		else if ( $i == 1 )
			return "prenom";
		else if ( $i == 2 )
			return "inscription";
		else if ( $i == 3 )
			return "mail";
	}
?>

Et voilà notre tableau se remplit automatiquement avec les données renvoyées par le fichier get_data.php.
La méthode utilisée dans l’exemple pour renvoyer les données au format JSON est un peu barbare, utiliser json-encode sur un array serait à mon humble avis plus approprié, à vous de voir.

  <?php  
 $sOutput = array('sEcho'=>intval($_GET['sEcho']), 
				  'iTotalRecords'=>$iTotal,
				  'iTotalDisplayRecords'=>$iFilteredTotal);
 $aaData = array();        
	
	while ( $aRow = mysql_fetch_array( $rResult ) )
	{
            $tmp = array();
	    $tmp[] = addslashes($aRow['nom']);
		$tmp[] = addslashes($aRow['prenom']);
		$tmp[] = date(H:i d/m/Y'', $aRow['inscription']);
		$tmp[] = addslashes($aRow['mail']);
		$tmp[] = '<a href="user.php?id='.$aRow['id'].'">Détails</a>';
		
		$aaData[] = $tmp;
	}
   $sOutput['aaData'] = $aaData;
  
   echo json_encode($sOutput);

Je n’ai pas testé le code mais cela devrait fonctionner.

Bon tout ça c’est bien beau mais on aimerait bien avoir une traduction en français plutôt que d’avoir Show 10 entries, Search ect, car même si on comprend ça fait tâche.
Et bien le plugin nous offre la possibilité de traduire le plugin dans pas moins de 29 langues dont l’anglais, l’allemand, l’espagnol, le portugais, le chinois etc.
Pour mettre en place la traduction il n’y a rien de plus simple, on va rajouter une option dans la déclaration de notre tableau :

$(document).ready(function() {
	$('#datatable').dataTable( {
		"bProcessing": true,
		"bServerSide": true,
		"sAjaxSource": "get_data.php",
                "oLanguage": { "sUrl": "datatable_fr.txt" }
	} );
} );

Il suffit ensuite de placer la traduction correspondante dans le fichier datatable_fr.txt. La liste des codes à placer est disponible ici.
Vous pouvez modifier les traductions ou bien créer les vôtres très simplement. Pour éviter un appel du fichier sur le serveur vous pouvez également faire comme ceci :

$(document).ready(function() {
	$('#datatable').dataTable( {
		"bProcessing": true,
		"bServerSide": true,
		"sAjaxSource": "get_data.php",
                "oLanguage": { "sProcessing":   "Traitement en cours...",
                   "sLengthMenu":   "Afficher _MENU_ éléments",
	           "sZeroRecords":  "Aucun élément à afficher",
	           "sInfo": "Affichage de l'élement _START_ à _END_ sur _TOTAL_ éléments",
	           "sInfoEmpty": "Affichage de l'élement 0 à 0 sur 0 éléments",
	           "sInfoFiltered": "(filtré de _MAX_ éléments au total)",
	           "sInfoPostFix":  "",
	           "sSearch":       "Rechercher:",
	           "sUrl":          "",
	           "oPaginate": {
		        "sFirst":    "Premier",
		        "sPrevious": "Précédent",
		        "sNext":     "Suivant",
		        "sLast":     "Dernier"
	               }
                }
	} );
} );

Enfin on aimerait styliser notre tableau et donc utiliser la puissance de jQuery-UI. Pour cela rien de plus simple, il suffit de posséder les fichiers de jQuery-UI (.js, .css et les images) et de les avoir inclus. Comme pour la traduction une simple ligne suffit :

       ...
       "bJQueryUI": true,
       ...

Vous pouvez voir encore plus d’exemple sur cette page.

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