Outils pour utilisateurs

Outils du site


cours2011:jquery_semestre_4:tp:definitions_en_tooltip_ajax_simple

Définitions en Tooltip (Ajax Simple)

Le but est de réaliser :

Remarque : Vous ne pouvez tester AJAX en local avec Google Chrome à moins de lancer l'exécutable avec l'option --allow-file-access-from-files (me demander).

Explication

Les mots ont des liens avec des ancres qui pointent vers les définitions.

La méthode jQuery .load() permets de charger des données (en 'AJAX') depuis le serveur et les insérer dans l'élément à qui elle est appliquée.

Dans la console, tester les commandes suivantes dans une page ou jQuery est chargé :

  • tooltip = jQuery('<div>')
    • Fais un élément DIV
  • tooltip = jQuery("<div>").load("test-ajax-glossaire.html#terme-consectetur")
    • Fais un élément DIV puis charge le contenu passé en URL
    • Le contenu n'est pas chargé immédiatement (le A dans AJAX veut dire asynchrone).
      • Redemander tooltip dans la console pour le voir (avec Firebug, il faut cliquer dessus).
  • tooltip = jQuery("<div>").load("test-ajax-glossaire.html #terme-consectetur")
    • Si l'on met un espace avant l'ancre, jQuery ne garde que la partie correspondant à l'identifiant.
  • tooltip = jQuery("<div>").load("test-ajax-glossaire.html#terme-consectetur".replace("#"," #"))

Vous devez voir :

Travail

Vous n'avez plus qu'a écouté les survole des liens (qui pointent vers une définition) pour :

  • Créez le 'tooltip'.
  • L'ajouter au bon endroit et avec la bonne position (absolue).
  • Le retirer quand l'on quitte le lien.
/* Mode strict */
"use strict";
 
/* Execute le code quand la page est prête 
  ".noConflict()" est optionnel */
jQuery.noConflict()(function ($) {
	/* Ici on utilise $ en toute sécurité */
	$(document).on("mouseenter",'a[href^="test-ajax-glossaire.html#terme-"]',function (event) {
 
		/* travail à faire */
 
	})
});

Explication sur le gestionnaire d'événement :

  • On écoute document pour :
    • Ne mettre en place qu'un gestionnaire d'événement (meilleure performance).
    • Pouvoir réagir aux liens qui seraient ajoutés après sa mise en place.
  • On utilise la méthode jQuery : .on()
    • Elle permet d'ajouter un filtre (sélecteur) pour :
      • N'avoir que les événements sur les éléments A .
      • Qui ont un attribut href qui est une ancre vers une entrée du glossaire.

Vous pouvez télécharger une archive avec le code à HTML/CSS.

Aide pour version simple

/* Mode strict */
"use strict";
 
/* Execute le code quand la page est prête 
  ".noConflict()" est optionnel */
jQuery.noConflict()(function ($) {
	/* Ici on utilise $ en toute sécurité */
	$(document).on("mouseenter",'a[href^="test-ajax-glossaire.html#terme-"]',function (event) {
		// Fait de 'this' un objet jQuery : $this
		// var $this= .... ;
		// Création du Tooltip : http://api.jquery.com/jQuery/#jQuery2
		// var tooltip = ..... ;
		// Lui ajouter un class CSS pour la mise en forme http://api.jquery.com/addClass/
		// tooltip. ..... ;
		// Lui ajouter des propriétés CSS : http://api.jquery.com/css/#css2
		tooltip.css({
			// Sa position gauche : idem la position de $this (utilisez : http://api.jquery.com/position/ )
			left:$this.position().left,
			// Idem pour top, mais ajouter la hauteur : http://api.jquery.com/outerHeight/
 
			// Le mettre en position absolue
			position:"absolute"
		});
		// L'ajouter à $this : http://api.jquery.com/appendTo/
 
		// Obtenir l'URL de $this (attribut 'href') : http://api.jquery.com/attr/
		// var href = .... ;
		// Charger dedans la définition avec load : http://api.jquery.com/load/
		tooltip.load(href.replace("#"," #"));
		/* Utilser un événement à usage "unique" (one) : http://api.jquery.com/one/
			Pour l'événement "mouseleave"
		*/
		$this.one("mouseleave",function (event) {
			// Supprimer le tooltip : http://api.jquery.com/remove/
 
		});
	})
});

Petites améliorations

Comme les indications données vous ont permis d'avoir un code qui fonctionne assez rapidement, maintenant vous pouvez prendre le temps d'améliorer !

Animations

Apparition

Ajouter un appel à la méthode .fadeIn() sur le “tooltip”.

Disparition

À peine plus complexe.

Ajouter un appel à la méthode .fadeOut() sur le “tooltip” AVANT de le supprimer.

Ne supprimer le “tooltip” que quand l'animation est finie, le faire dans un “callback” (fonction anonyme) passé à .fadeOut() .

Vous pouvez aussi utiliser .stop() pour vous assuré que l'animation d'apparition du “tooltip” s'arrête de suite quand on lance celle de disparition.

Autre intégration HTML/CSS

Actuellement vous ajouter le “tooltip” à la fin de l'élément A :

<a href="  ">
    text...
    <div class="tooltip">Définition chargée par AJAX</div>
</a>

Un des inconvénient est que le “tooltip” est dans le lien.

On cherche à obtenir :

<a href="  ">text...</a>
<div class="tooltip">Définition chargée par AJAX</div>

Vous avez besoin de :

Utilisation de JSON

Actuellement on utilise un astuce très élégante qui consiste à charge la liste de définitions depuis une page avec une ancre (id) correspondant à l'élément à affiché (“fragment” extrait par .load() ).

Si les données venaient d'un base de données, il serait plus pratique de les formater en JSON (fichier : ”test-ajax-glossaire.json”) :

{
	"consectetur":"Adipisicing elit, sed do eiusmod tempor",
	"duis":"Aute irure dolor in reprehenderit in voluptate velit esse cillum",
	"ut":"Enim ad minim veniam",
	"excepteur":"Sint occaecat cupidatat non proident",
	"laboris":"Nisi ut aliquip ex ea commodo consequat"
}

On peut le lire avec :

jQuery.getJSON('test-ajax-glossaire.json')
        .done(function (data) {console.log(data)})
        .fail(function (e) {console.log("erreur :",e)});

A tester dans la console.

JSON c'est du JavaScript

La simplicité et l'élégance de JSON viennent du fait que c'est du JavaScript, des valeurs en notation littérale.

Avant de charger les définitions par AJAX, l'on va simplement les placer dans le code JavaScript, modifier votre code de la façon suivante :

/* Mode strict */
"use strict";
 
/* Execute le code quand la page est prête 
  ".noConflict()" est optionnel */
jQuery.noConflict()(function ($) {
	/* Ici on utilise $ en toute sécurité */
	// Les définitions 
	var definitions = {
			"consectetur":"Adipisicing elit, sed do eiusmod tempor",
			"duis":"Aute irure dolor in reprehenderit in voluptate velit esse cillum",
			"ut":"Enim ad minim veniam",
			"excepteur":"Sint occaecat cupidatat non proident",
			"laboris":"Nisi ut aliquip ex ea commodo consequat"
		};
 
	$(document).on("mouseenter",'a[href^="test-ajax-glossaire.html#terme-"]',function (event) {
 
 
		// Remplace l'usage de .load
		// extraire le terme c.-à-d. contenu texte de A ($this) : http://api.jquery.com/text/
		// la méthode toLowerCase sert à supprimer l'éventuelle majuscule.
		var terme = $this.text().toLowerCase(); 
		// Mettre le texte de la définition dans le tooltip
		tooltip.text(definitions[terme]);
 
 
	});
});

Réaliser les modifications est vérifier le bon fonctionnement.

La suite consiste en des modifications visant à charger les définitions dynamiquement (par AJAX).

Appeler une fonction plutôt que référencer une variable

Comme la liste des définitions sera plus tard le résultat d'un traitement, l'on va remplacer l'usage de la variable par l'appel d'une fonction (qui retourne la valeur désirée).

Faire les changements et tester.

Utiliser "when" quand un résultat peut être asynchrone

Comme la liste des définitions peut être le résultat d'un appel AJAX (asynchrone), on va utiliser :

$.when(  ).done(function(val) { /* utilise val */ });

On utilise le concept de Deferred / promise qui sert à exprimer la “future” valeur retournée par un traitement (éventuellement) asynchrone.

Faire les changements et tester.

L'élégance du concept de “promise” c'est que pour l'instant l'on n'a pas changé le code pour obtenir la liste de définitions.

Obtenir les définitions par AJAX

Le changement est d'une simplicité !

C'est toute l'élégance du concept, que l'on ait une valeur ou la promesse d'une valeur, cela ne change RIEN

Usage avancé des "promise"

Cacher un résultat AJAX

Le concept est :

  • Une variable (initialement vide) sert de cache.
  • Quand on demande la liste des définitions :
    • Si il y déjà une valeur (non vide), on l'utilise
    • Sinon on place la “promise” donnée par une requête AJAX
      • Quand la requête AJAX aura abouti, on placera la valeur dans le cache (variable).
Traitement sur des Deferred

Le code qui fixe le texte du tooltip est conçu pour recevoir la liste des définitions. Ce n'est pas très correct, car l'on peut vouloir changer la façon de recevoir les définitions (exemple un service ne retournant que la définition demandée).

Il devrait donc prendre la forme suivante :

Faire le changement, on va écrire le code de ”getDefinition(terme)

La tâche de getDefinition est de prendre l'entrée correspondant au “terme” dans la liste de définition. Si l'on écrit, cela donne :

function getDefinition(terme) {
	return getListeDefinitions()[terme];
}

Mais cela ne fonctionne pas, car getListeDefinitions() peut retourné une “promise” et non la valeur.

Pour tenir compte d'une éventuelle “promise”, cela donne :

function getDefinition(terme) {
	$.when(getListeDefinitions()).done(function (listDefs) {
		return listDefs[terme];
	});
}

Mais cela ne fonctionne pas, car l'on retourne la valeur dans le “callback”, la fonction anonyme qui est appelée quand les données ont été reçues. Et non pas immédiatement, comme résultat de la fonction getDefinition

On a besoin que getDefinition retourne une “promise” pour le cas ou les données ne sont pas encore reçues. C'est ce que fait la méthode deferred.pipe .

Faire les changements et tester.

Si cela vous laisse perplexe, c'est normal…

Utilisation de JSON sans "promise"

Si on n'utilise pas les “promise” , le code est bien plus simple :

Vous pouvez essayer, remplacer tout les changements précédents par celui-ci.

Mais il sera alors difficile de :

  • Placer le code qui récupérer les données dans une fonction (pour qu'il ne soit plus dans l'affichage du tooltip où il n'a rien à faire) !
  • Mettre les résultats en cache !
  • Changer la façon de récupérer les données !

Bref, le concept de “promise” n’est pas simple. Mais il offre plein de facilité pour traiter des problèmes qui sans lui seraient bien complexes à programmer.

cours2011/jquery_semestre_4/tp/definitions_en_tooltip_ajax_simple.txt · Dernière modification: 2012/02/12 23:00 (modification externe)