JQuery ou le javascript revisité

Javascript a été créé dans les années 1990 pour permettre de donner de l’interactivité aux pages web. C’est un langage qualifié de fonctionnel, c’est à dire qu’il permet une gestion des fonctions dynamiques. Ainsi, il est possible de créer des fonctions «à la volée », une fonction pouvant même retourner une autre fonction au lieu de renvoyer une valeur.

Il est largement utilisé aujourd’hui pour créer des animations, faire des tests, afficher des messages, envoyer ou recevoir des informations du serveur, en s’appuyant sur un protocole, Ajax, et un format d’échanges, JSON.

Ajax (Asynchronous Javascript and XML) permet d’obtenir (ou d’envoyer) des informations vers un serveur, en conservant le mécanisme asynchrone : le navigateur n’a pas à attendre la réponse du serveur, et l’utilisateur peut continuer à travailler dans la page. Quand le serveur renvoie la réponse, le script récupère l’information, et la traite, en général pour modifier l’affichage dans la page. C’est souvent ce mécanisme qui est utilisé pour alimenter une liste déroulante qui serait trop volumineuse à charger, par exemple pour afficher une liste des communes à partir du code postal.

JSON est un format qui dérive de la notation des objets en javascript. Par rapport à XML, il est beaucoup moins verbeux, ce qui fait que les échanges avec le serveur sont moins volumineux. De plus, en raison de sa structure, il est très facile à manipuler en javascript.

JQUERY est une fonction Javascript créée en 2006, qui permet de programmer très rapidement des actions dans une page. Largement répandue, elle est plébiscitée pour la facilité de gestion des balises et des événements dans une page HTML qu’elle procure.

Le principe général de la syntaxe est la suivante : la fonction est appelée avec, en paramètre, un ou plusieurs sélecteurs (une classe, un type de balise, un élément nommé - attribut id). Elle est chaînée avec une fonction qui peut être le traitement d’un événement, l’assignation de valeurs ou la lecture de valeurs.

Cette fonction prend elle même en paramètre soit une action directe (assignation), soit la définition d’une fonction, qui permettra de réaliser l’action attendue.

Un exemple...

Voici un exemple qui illustre quelques possibilités offertes :

$(document).ready(function() {

var modif = 0;

$("input").change( function() {

modif = 1;

} ) ;

$(".time").attr( {

pattern: "[0-9][0-9]\:[0-9][0-9]",

placeholder: "hh:mm",

size: "5em", autocomplete: "false" });

$("#repartitionPrint").click( function () {

if (modif == 1 ) {

alert ("L'impression ne peut pas etre declenchee : des modifications ont ete apportees dans le formulaire");

return false;

}

} ) ;

$('select'.change(function() {

this.form.submit();

)};

} );

$ correspond au raccourci pour le nom de la fonction jQuery.

$(document).ready(function() {

permet de définir que le code JQuery ne doit être exécuté qu’une fois la page totalement chargée. Dans le cas contraire, certaines assignations pourraient ne pas être prises en compte.

var modif = 0;

est une assignation de variable classique. La variable modif vaut 0.

$("input").change( function() {

modif = 1;

} ) ;

JQuery va traiter tous les événement change des balises input : à chaque fois qu’une information sera modifiée dans un champ, la variable modif basculera à 1. Dans ce cas particulier, si au moins une information a été modifiée, alors le programme sait qu’une modification a été apportée.

$(".time").attr( { pattern: "[0-9][0-9]\:[0-9][0-9]", placeholder: "hh:mm", size: "5em", autocomplete: "false" });

Ici, JQuery va modifier le contenu des balises dont la classe vaut time (ici, une zone de saisie). Nous voyons un exemple d’attribution multiple, où chaque valeur à modifier est séparée par une virgule. Le code définit le modèle à respecter lors de la saisie (attribut pattern), placeholder permet d’afficher le modèle attendu, size donne la taille de la zone de saisie, et autocomplete demande au navigateur de ne pas conserver l’historique des saisies déjà faites et de ne pas les proposer comme aide à la saisie.

Si un seul attribut a besoin d’être modifié, nous pourrions utiliser la syntaxe :

$(".time").att("title", "Heure...") ;

qui permet de définir le libellé affiché au survol de la souris.

Voici le traitement d’un événement, ici la capture du clic de la souris sur un lien, dont l’attribut id vaut repartitionPrint :

$("#repartitionPrint").click( function () {

if (modif == 1 ) {

alert ("L'impression ne peut pas etre declenchee : des modifications ont ete apportees dans le formulaire");

return false;

}

} ) ;

dans ce cas de figure, l’impression ne peut être réalisée que si aucune modification n’a été effectuée. Le programme teste donc la variable modif que nous avons défini précédemment. Si elle vaut 1, la fonction retourne false, et l’événement défini par le lien ne sera pas exécuté.

Et, pour terminer, le déclenchement de l’envoi du formulaire lorsque le contenu d’une liste déroulante (balise select) change :

$('select').change(function () {

this.form.submit();

});

Nous demandons ici à JQuery de capturer tout changement dans les balises <select>, et de déclencher la fonction d’envoi du formulaire associé. C’est un mécanisme souvent utilisé dans les formulaires de recherche à critères multiples.

Des requêtes Ajax simplifiées

Prenons un autre exemple. L’utilisateur va devoir sélectionner une espèce (en l’occurrence, de poisson), dans une liste déroulante. Comme cette liste dépasse les 500 enregistrements, nous lui simplifions le travail en lui demandant de taper quelques caractères dans une zone de texte. Au fur et à mesure de sa saisie, la liste va être alimentée automatiquement par l’intermédiaire d’une requête Ajax.

Voici, dans un premier temps, notre code HTML avec le script JQuery :

<script>

$(document).ready(function() {

$("#recherche").keyup(function() {

/*

* Traitement de la recherche d'une espece

*/ var texte = $(this).val();

if (texte.length > 2) {

/*

* declenchement de la recherche

*/ var url = "index.php?module=especeSearchAjax";

$.getJSON ( url, { "libelle": texte } , function( data ) {

var options = '';

for (var i = 0; i < data.length; i++) {

options += '<option value="' + data[i].id + '">' + data[i].val + '</option>';

};

$("#espece_id").html(options);

} ) ;

};

} );

) };

</script>

<form method="post" action="index.php?module=echantillonWrite" >

(...)

<input id="recherche" autocomplete="off" autofocus placeholder="espece a chercher" title="Tapez au moins 3 caracteres...">

<select name="espece_id" id="espece_id">

(...)

</form>

Quelques explications...

La recherche est lancée en interceptant l’événement keyup de la balise dont l’attribut id vaut recherche, ce qui correspond au moment où la touche du clavier est relâchée.

Le programme assigne alors le contenu de la balise <input> à la variable texte, avec la commande $(this).val(). Si le contenu de la balise a une longueur supérieure à 2 caractères, la recherche est lancée, en appelant la page index.php?module=especeSearchAjax, et en lui fournissant une variable en paramètre, la variable libelle, qui contient le texte saisi. Cette taille minimale de 2 caractères évite de lancer une recherche sur l’ensemble des références, par exemple en utilisation de la touche de suppression ou de retour arrière (backspace).

L’appel de la fonction $.getJSON permet de traiter à la fois l’appel Ajax, et le retour du serveur : c’est le troisième argument (function (data) { (...) }) qui permet de traiter les données retournées.

Les données retournées par le serveur sont disponibles dans la variable data, et il n’y a plus qu’à reconstituer les différentes options de notre balise <select>, ce qui est fait dans la boucle for.

Une fois ces options écrites, le programme les insère dans la page html avec la commande :

\$("#espece_id").html(options);

Voici maintenant à quoi ressemble notre code PHP, qui va préparer les données : ,

/*

* Recherche la liste et la retourne au format Ajax

*/ if (strlen($_REQUEST["libelle"]) > 0) {

$data = $dataClass->getListByName($_REQUEST["libelle"]);

$dataJson = array(); $i = 0;

/*

* Mise en forme du tableau pour etre facile a manipuler cote client

*/

foreach ($data as $key => $value) {

$dataJson[$i]["id"] = $value["espece_id"];

$valeur = $value["nom"];

if (strlen($value["nom_fr"]) > 0 ) {

$valeur .= " - ".$value["nom_fr"];

}

$dataJson[$i]["val"] = $valeur;

$i ++;

}

echo json_encode ($dataJson) ;

}

Le programme PHP va d’abord tester que la variable libelle, fournie par le navigateur, n’est pas nulle. Il appelle ensuite la classe qui permet de réaliser la requête SQL, et récupère un tableau dynamique (une ligne par enregistrement retourné). Le tableau est alors transformé en associant l’identifiant, qui a la valeur id, à un libellé. Il est constitué du nom latin (colonne nom) et, au cas où le nom français est connu, celui-ci est rajouté.

Pour finir, voici un exemple du code Json retourné, en faisant une recherche avec le mot bar :

[{"id":"55","val":"Dicentrarchus labrax - Bar europ\u00e9en"},{"id":"67","val":"Dicentrarchus punctatus - Bar tachet\u00e9"}]

Pour chaque enregistrement, nous avons retourné deux variables : id, qui contient l’identifiant de l’espèce dans la base de données, et val, qui contient la valeur à afficher.

Ainsi, nous avons pu réaliser une interrogation Ajax avec peu de lignes de code, sans avoir ni à gérer les codes de retour du protocole Ajax, ni la réécriture de la balise <select>. En Javascript traditionnel, nous aurions dû gérer les codes de retour fournis par le protocole Ajax, ainsi que les différents modes d’appel selon les navigateurs. De plus, la réécriture de la balise <select> aurait pu nécessiter des commandes plus fastidieuses.

C’est un exemple parmi d’autres de la facilité qu’apporte JQuery dans l’écriture des interfaces web.

Un écosystème riche et varié

Ne serait-ce que pour la facilité de manipuler les éléments dans la page web, JQuery devient vite indispensable. Mais sa vraie richesse n’est pas là uniquement : de nombreux programmeurs ont créé des objets complémentaires, avec des effets graphiques parfois assez bluffants.

Les dates

Pour faciliter la saisie des dates par les utilisateurs, au début des années 2000, il était fréquent de recourir à de la programmation PHP. Ensuite, des classes Javascript ont vu le jour, parfois assez complexes à implémenter : il fallait souvent associer un bouton à un champ du formulaire pour les faire fonctionner, et la gestion du multi-langage n’était pas toujours très aisée.

Aujourd’hui, des composants prêts à l’emploi sont disponibles, et ne demandent quasiment aucun effort... Voici un exemple avec la classe datepicker (https://jqueryui.com/datepicker/ :

Pour l’utiliser dans votre page HTML, insérez le code suivant :

<script type="text/javascript" charset="utf-8" src="display/javascript/jquery-ui-timepicker-addon.js"></script>

Vous pourrez ensuite l’utiliser dans votre page web ainsi :

<script> $(document).ready(function() {

$(".date").datepicker( { dateFormat: "dd/mm/yy" } );

});

</script>

<input class="date" name="ma_date">

Nous avons utilisé une classe, la classe date, pour identifier notre champ. Ainsi, si vous avez plusieurs champs de sélection de la date, par exemple pour définir un intervalle, une seule définition permet de rattacher le composant de sélection de la date datepicker à l’ensemble de nos champs.

Autre avantage : nous allons pouvoir modifier notre feuille de style pour afficher une icône dans notre champ, pour que l’utilisateur identifie bien qu’il s’agit d’une date. Voici l’entrée correspondante dans notre feuille CSS :

input.date {

background-image: url("images/calendar-small.gif");

background-repeat: no-repeat;

background-position: 100% 50%;

width: 10em;

}

Le style que nous venons de définir ne sera utilisé que pour les champs (balise input), dont la classe vaut date. Il affiche une petite image, un calendrier, et le positionne à droite du champ (background-position 100%), en position centrée (50%).

Enfin, la zone a une largeur standardisée dans l’ensemble de l’application.

Bien qu’un clic permette d’afficher le contrôle, la zone reste éditable, et l’utilisateur peut saisir manuellement une date.

La classe Datepicker fonctionne avec JQueryUI (https://jqueryui.com), un ensemble de classes complémentaires qui permettent de gérer tous les événements graphiques dans une page. Si vous avez besoin de créer des animations, de dessiner des objets, vous en aurez besoin.

Le composant de gestion des tableaux : DataTables

Autre classe très répandue : DataTables (https://datatables.net/. C’est une classe JQuery qui va étendre les possibilités d’affichage des tableaux, en proposant une pagination automatique, une recherche plein texte dans l’ensemble des données, mais également des possibilités d’export direct au format CSV, PDF, XLS en lui adjoignant l’extension TableTools (https://datatables.net/extensions/tabletools/). Sa configuration n’est pas des plus aisée : nous verrons dans le chapitre traitant de l’ergonomie comment créer une fonction qui permet d’en simplifier l’usage.

Pour l’utiliser, votre tableau, en plus des balises classiques de description de lignes et de colonnes doit contenir les balises <thead> et <tbody> :

<link rel="stylesheet" type="text/css" href="/javascript/DataTables-1.10.5/media/css/jquery.dataTables.css">

<script type="text/javascript" charset="utf8" src="/javascript/DataTables-1.10.5/media/js/jquery.js"></script>

<script type="text/javascript" charset="utf8" src="/javascript/DataTables-1.10.5/media/js/jquery.dataTables.js"></script>

$(document).ready( function () {

$('#tableId').DataTable();

} );

<table id="tableId" class="display"> <thead> <tr> <th>Entete colonne 1</th> <th>Entete colonne 2</th> </tr> </thead> <tbody> <tr> <td>donnee 1</td> <td>donnee 2</td> </tr> <tr> <td>donnee 1 - ligne 2</td> <td>donnee 2 - ligne 2</td> </tr> </tbody> </table>

L’utilisation commence par la définition des fichiers à importer, ici une feuille de styles, puis le fichier jquery.js, et enfin le composant lui-même.

L’activation du composant pour le tableau s’effectue de manière classique en JQuery, en associant Datatable au tableau dont l’identifiant vaut tableId.

Vous pouvez également définir un pied de tableau, en utilisant la balise <tfoot>.

Il est possible d’y associer l’extension TableTools https://datatables.net/extensions/tabletools/, qui rajoute des boutons permettant des exports en CSV, PDF, XLS, ou d’imprimer directement le tableau. Cette extension travaille avec un fichier Shockwave Flash. Cela impose que le navigateur dispose d’un module pour gérer ce type d’extension, en principe Flash Player.

Le composant Datatables est très utile, mais si vous avez plusieurs tableaux à afficher, son instanciation peut être compliquée, notamment si vous souhaitez modifier son comportement ou franciser certains libellés. Une des solutions consiste à créer une fonction javascript, qui va se charger de réaliser l’instanciation à votre place, et surtout, de manière unique dans votre application. Voici un exemple d’une telle fonction.

function setDataTables(nomTable, bPaginate, bSort, bFilter, iDisplayLength, bLengthChange) {

if (bPaginate == null) bPaginate = true;

if (bSort == null) bSort = false;

if (bFilter == null) bFilter = false;

if (iDisplayLength == null) iDisplayLength = 25;

if (bLengthChange == null) bLengthChange = true;

$(document).ready( function () {

$('#'+nomTable).dataTable( {

"bPaginate": bPaginate,

"bFilter": bFilter,

"bSort": bSort,

"iDisplayLength": iDisplayLength,

"bLengthChange": bLengthChange,

"oLanguage": {

"sLengthMenu": "Afficher _MENU_ lignes par page",

"sZeroRecords": "Pas de données"

,*) "sInfo": "_START_ - _END_ / _TOTAL_ lignes",

"sInfoEmpty": "0 - 0 / 0 lignes",

"sInfoFiltered": "(Filtré*) pour _MAX_ total lignes)",

"sSearch": "Chercher...",

"oPaginate": { "sFirst": "Premier",

"sPrevious": "Pr&eacute;c&eacute;dent",

"sNext": "Suivant",

"sLast": "Dernier" }

},

"sDom": 'T<"clear">lfrtip',

"oTableTools": {

"sSwfPath": "display/javascript/DataTables-1.9.4/extras/TableTools/media/swf/copy_csv_xls_pdf.swf",

"aButtons": [ { "sExtends": "print",

"sButtonText": "Imprimer",

"sToolTip": "Imprimer le tableau" },

{ "sExtends": "pdf", "sButtonText": "PDF", "sToolTip": "Exporter au format PDF" },

{ "sExtends": "csv", "sButtonText": "CSV", "sToolTip": "Exporter au format CSV (séparateur*) : virgule)" },

{ "sExtends": "copy", "sButtonText": "Copier", "sToolTip": "Copier dans le presse-papiers" } ] }

} );

} );

}

La fonction setDataTables accepte les arguments suivants :

  • l’identifiant (la balise id) de votre table ;
  • un booléen, pour indiquer que vous voulez une pagination de vos enregistrements (activé par défaut). Dans le cas contraire, toutes vos lignes seront affichées à l’écran ;
  • un booléen pour indiquer si vous voulez activer le mécanisme de tri. Attention toutefois avec cette fonction : elle ne fonctionne bien que pour les zones de texte, sauf à définir des comportements particuliers pour chaque colonne concernée. Par défaut, le tri n’est pas activé ;
  • un entier indiquant le nombre de lignes à afficher, quand la pagination est activée. Par défaut, 25 lignes sont affichées ;
  • enfin, un booléen pour afficher la liste déroulante permettant de changer le nombre de lignes affichées à la fois.

Le principal intérêt de cette fonction est de traduire les libellés, et de définir les boutons que vous voulez utiliser avec le module Flash d’export.

Une fois cette fonction définie, l’ajout du composant à votre table devient très simple :

<script> setDataTables("tableId");

</script> <table id="tableId" class="display">

<thead

> (...)

Un foisonnement d’autres composants...

Il y a quelques années, il était courant de créer les graphiques en PHP, puis d’envoyer l’image au navigateur. Aujourd’hui, le recours à une classe de dessin de graphique permet de n’envoyer que les données à afficher. Et les classes modernes permettent des interactions (affichage des étiquettes au survol de la souris, courbes dessinées les unes après les autres, etc.) qui n’étaient pas possibles auparavant. Vous retrouverez également des classes permettant de réaliser des diaporamas, de retoucher des images, etc.

Charger les fichiers JQuery

Jusqu’à présent, nous avons vu comment utiliser JQuery. Auparavant, vous devrez avoir chargé les fichiers dans le navigateur.

Deux solutions s’offrent à vous : soit vous référencez le fournisseur de la classe, ce qui vous garantit la disponibilité de la dernière version publiée dans la branche considérée, soit vous téléchargez les classes dans votre serveur, et vous les référencez dans vos pages.

La première solution est souvent la plus simple, mais elle peut présenter quelques inconvénients. Si vous travaillez en entreprise, et que celle-ci a mis en place une politique stricte d’accès à Internet, il est possible que le téléchargement de la classe JQuery impose la saisie d’un mot de passe pour franchir le proxy, alors même que votre application n’est accessible qu’en interne. De plus, si un utilisateur ne dispose pas d’un accès à Internet, l’application ne fonctionnera plus.

Sinon, vous pouvez télécharger les classes. Vous les trouverez souvent sous deux formes : la forme de base ou de développement, qui comprend le code avec les commentaires, et une forme compressée, qui se termine par min.js. Le code a été expurgé de toutes les lignes blanches, de tous les commentaires et de tous les retours à la ligne : le fichier est plus petit, mais également, illisible si vous voulez le consulter. Par contre, il se chargera plus vite vers les ordinateurs de vos utilisateurs.

Certaines classes peuvent également nécessiter des feuilles de styles CSS adaptées, pour gérer un affichage correct des composants utilisés. Vous serez parfois obligé de modifier ces feuilles de style pour les adapter à l’ergonomie générale de votre site. Faites tout de même attention à ne pas dénaturer le fonctionnement du composant ; dans certains cas, des liens ou des boutons pourraient ne plus être actifs.

Voici un exemple de chargement de classes JQuery :

<script type="text/javascript" charset="utf-8" src="display/javascript/jquery-1.11.0.min.js"></script>

<script type="text/javascript" charset="utf-8" src="display/javascript/jquery-ui-1.10.4.custom.min.js"></script>

<script type="text/javascript" charset="utf-8" src="display/javascript//DataTables-1.9.4/media/js/jquery.dataTables.js"></script>

<script type="text/javascript" charset="utf-8" src="display/javascript/DataTables-1.9.4/extras/TableTools/media/js/TableTools.js"></script>

<script type="text/javascript" charset="utf-8" src="display/javascript/DataTables-1.9.4/extras/TableTools/media/js/ZeroClipboard.js"></script>

<style type="text/css" >

@import "display/CSS/TableTools.css";

@import "display/CSS/dataTables.css";

@import "display/CSS/jquery-ui-1.10.4.custom.css";

</style>

Les classes JQuery sont stockées ici dans le dossier display/javascript, les feuilles de style dans le dossier display/CSS. Si vous utilisez Smarty, vous pouvez intégrer ce code dans un fichier indépendant, qui sera appelé systématiquement dans toutes vos pages. Ainsi, vous aurez toujours «sous la main » l’ensemble de vos composants JQuery.

Et si vous voulez définir des comportements standards pour l’ensemble de vos formulaires, pour pallier les limites du CSS (cf. précédemment), rien ne vous empêche de rajouter ce script au fichier précédent :

<!-- Definition des attributs de comportement par defaut -->

<script>

$(document).ready(function() {

$(".date").datepicker( { dateFormat: "dd/mm/yy" } );

$('.taux').attr( { 'pattern': '[0-9]+(\.[0-9]+)?', 'maxlength' : "10", 'title' : 'Valeur numérique...'*) } );

$('.nombre').attr( { 'pattern': '[0-9]+', 'maxlength' : "10", 'title' : 'Valeur numérique...'*) } );

} ) ;

</script>

Dans cet exemple, nous avons défini que les balises dont la classe vaut date utilisent un composant de sélection de date (datepicker) en lui indiquant le format d’affichage. Pour les balises taux et nombre, c’est le pattern, c’est à dire le format que les données doivent respecter, la longueur maximale, ou le contenu du message affiché au survol de la souris qui sont précisés.

JQuery n’est pas la seule solution disponible...

Bien sûr, il existe des composants qui sont équivalents. Vous entendrez probablement parler de PrototypeJS (http://prototypejs.org/, par exemple.

Choisissez l’environnement qui vous convient : l’important est de s’appuyer sur des outils performants, et de ne pas perdre de temps à les réinventer.