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)


17 commentaires pour “DataTables : base de données, traduction et jQuery-UI”

  • Bonjour, j’ai juste une question, qui peut-être, sera idiote, mais je ne comprend pas le fait d’avoir deux tableaux lors de la récupération des données (la simplifiée),$aaData et $tmp?(ligne 4 et 5)
    Merci d’avance pour la réponse.

  • Merci pour la question car n’ayant pas testé le code, je n’avais pas vu la grossière erreur que j’ai oubliée dedans :s
    En fait on souhaite obtenir un tableau au format : array(0 => array(‘nom’ => ‘Pierre’ etc …) , 1 => array(‘nom’ => ‘Martin’ etc …)). Donc on créé un tableau temporaire à chaque itération de mysql_fetch_array qu’on ajoute ensuite dans notre tableau qui stocke toutes les données, ce qui nous permet d’obtenir le format souhaité.
    Cependant l’erreur (pas taper) que j’ai faite c’est d’initialiser le tableau tmp avant la boucle. Du coup il ne se vide pas et on se retrouve avec des doublons. J’ai mis à jour l’exemple, mais dis moi si je n’ai pas été assez clair.

  • Ok, je comprend mieux. Par contre, je sais pas si ton code proposé est un bout de code à remplacer dans celui du départ, ou alors si il suffit juste de le mettre après une connexion et il gère tout.
    Par exemple, est-ce qu’il faut gérer les filtres comme le fait le script de départ?

  • Enfait, je ne comprend pas bien les lignes
    01 intval($_GET[‘sEcho’]),
    02 ‘iTotalRecords’=>$iTotal,
    03 ‘iTotalDisplayRecords’=>$iFilteredTotal);

    Et je ne vois pas la parenthèse ouverte qui correspond à celle fermé après FilteredTotal.

  • Datatables envoit une requete AJAX en GET sur la page indiquée pour récupérer les données avec en paramètre toutes les options qu’on a spécifié.
    Le paramètre sEcho est envoyé par Datatables pour le rendu (d’après la doc, “sEcho : Information for DataTables to use for rendering”).
    iTotalRecords indique le nombre lignes total, qu’on a récupérer avec notre requête SQL avant d’etre filtrées et iTotalDisplayRecords le nombre de lignes après le filtrage.
    Mais le filtrage n’est pas obligatoire il est utilisé dans l’exemple pour montrer qu’on peut ensuite effectuer la recherche coté serveur.
    Le bout de code que je donne remplace la façon dont les données sont rendues. Dans l’exemple de la documentation que je donne, ils “écrivent” eux-memes le JSON, alors que PHP dispose d’une fonction toute faite que je préfère utiliser et que je trouve plus “propre” mais chacun est libre de faire ce qu’il veut 🙂

  • Ok, j’ai continué à me gratter la tête en attendant ta réponse, et j’ai compris l’histoire des paramètres, merci.

    Par contre ça fonctionne si je ne met pas la partie :
    intval($_GET[‘sEcho’]);
    ‘iTotalRecords’=>$iTotal,
    ‘iTotalDisplayRecords’=>$iFilteredTotal);
    Si je met ce bout de code, ça fonctionne pas, j’ai une erreur sur firebug. Pour moi il manquerai une parenthèse (ouverte) dans ce petit bout de code. Peux-tu me dire de où vient la parenthès de “$iFilteredTotal);” ?

    Étrangement quand ça fonctionne (donc sans le bout de code), le texte n’est pas entier. Dès qu’il y a un accent le texte s’arrête. Mais là c’est peut-être un problème avec mon UTF-8. Je verrais ça.

    En tout cas un grand merci pour ton aide.

  • La parenthèse ferme celle ouverte par la déclaration de l’array $sOutput, vérifie bien qu’il ne te manque pas de code.
    Les paramètres sont attendus par Datatables et par conséquent obligatoires.
    Tu as une liste bien détaillée sur cette page.

  • Hello.
    Et bien écoutes. Je suis vraiment navré de t’avoir déranger. Le problème vient de mon navigateur en fait. Chose assez étrange. J’utilise firefox 3.6.3 et le début du code n’est pas le même, il manque une ligne. Je me disais aussi que c’était louche 🙂
    Enfin le plus louche c’est que les navigateur traduise pas le site pareil.
    Preuve en image:
    http://img717.imageshack.us/img717/9854/avecff363.png
    http://img248.imageshack.us/img248/4180/avecie8.png

    Un grand merci pour ta patience, je pense que je devrais mieux m’en sortir maintenant 🙂

    Encore merci

  • Oula oui en effet c’est assez embêtant ça… Je vais me pencher dessus.
    Pour une fois que c’est Firefox qui foire l’affichage :p

  • “Pour une fois que c’est Firefox qui foire l’affichage”

    Pas faut. Bon courage en tout cas. 😉

  • Me revoilà 🙂
    Bon ça fonctionne.
    J’ai un autre soucis, c’est que mon tableau ce replis correctement, mais quand je clique sur les th, il marque traitement en cours, mais me renvoie le même tableau au lieu de trier selon la colonne où j’ai cliqué.

    Je le vois bien avec Firebug, le code Json retourné est le même.

    Bizarre :/ As-tu une idée?

  • Est-ce que tu trie bien les données dans ton fichier php ?

  • Je déterre un peu ce sujet mais je ne trouve pas grand chose sur le web a part ici …

    J’ai bien réussi a faire fonctionner le DATATABLE par contre il m’est impossible d’afficher des données comportant des accents (ça renvois NULL à la place). J’ai pourtant tout mis en utf-8 de la page html à la base mysql.. Est ce que quelqu’un à une solution ?

  • Merci pour cet exemple 🙂

    Petite faute de frappe à la ligne 2 du bloc où tu présente le formatage du tableau avec json_encode :

    $sOutput = array(‘sEcho’=>intval($_GET[‘sEcho’]),

    au lieu de
    $sOutput = array(‘sEcho’=–>intval($_GET[‘sEcho’]),

    Bonne journée.

  • Il s’agissait d’une erreur d’affichage des chevrons qui ne sont pas tous bien encodés dans mes articles :s
    Merci pour l’info 😉

  • Pas de soucis 🙂

    J’en ai trouvé une autre qui empêchait le système de pagination de fonctionner : ligne 46 il faut rajouter SQL_CALC_FOUND_ROWS dans ta requête :

    $sQuery = “SELECT SQL_CALC_FOUND_ROWS id, nom, prenom, inscription, mail FROM users $sWhere $sOrder $sLimit”;

    :3

  • Bonjour,

    Juste un petit message pour signaler une petite erreur dans le script :
    H:i d/m/Y” à remplacer par ‘H:i d/m/Y’

    En tout cas merci pour le tuto.

Laissez un commentaire