IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Débuter avec jQuery

La bibliothèque qui simplifie l'interaction


précédentsommairesuivant

5. Modification du DOM

L'intérêt majeur de JavaScript, facilité par l'utilisation de JQuery, est de pouvoir modifier l'apparence de la page pendant qu'elle est affichée. Traditionnellement, une page web est générée soit de façon statique par un fichier HTML (chaque appel de ce fichier affichera le même résultat) soit de façon dynamique par un langage serveur, par exemple PHP, qui affichera un résultat en fonction de paramètres reçus et d'un traitement spécifique sur le serveur. Mais une fois la page créée et envoyée au navigateur, elle est considérée comme fixe, c'est-à-dire que pour modifier l'affichage, il faut changer de page.

JavaScript (et donc jQuery) donne la possibilité, en fonction de certaines actions de l'utilisateur ou de certains paramètres prédéfinis, de changer l'affichage sans recharger la page. Il sera même possible avec AJAX d'échanger des informations avec le serveur (envoi de données à traiter, voire à enregistrer et / ou récupération d'informations permettant d'ajuster l'affichage).

Il est cependant important de bien comprendre ce mécanisme de création pour garder à l'esprit les limites de JavaScript.

C'est bien le serveur web qui stocke les fichiers HTML et les envoie au navigateur. Si vous utilisez un langage serveur, par exemple PHP, c'est encore le serveur qui stocke le fichier PHP qui va générer une page HTML et l'envoyer au navigateur. Dans ce cas, tous les traitements (vérification des données reçues, connexion à une base de données et récupération d'informations spécifiques……) sont faits par le serveur et invisibles par l'utilisateur. Par exemple, il est impossible de voir le code source d'un script PHP, tout ce que vous pouvez obtenir est le code source du résultat renvoyé par un script PHP. En particulier, cela signifie qu'une fois affichée, il n'existe plus aucun lien avec le fichier (statique en HTML ou dynamique en PHP) stocké sur le serveur et la page affichée. Sinon, cela voudrait dire que n'importe quel ordinateur affichant une page Web pourrait avoir un contrôle sur le serveur qui héberge la page affichée. Ce serait bien évidemment une faille de sécurité importante dont tous les pirates du Web pourraient rêver.

Surtout, cela implique que toutes les modifications que vous pourrez faire sur une page ne seront qu'éphémères et limitées au temps d'affichage de la page. Il s'agit donc principalement de choix ergonomiques créés pour être utiles à l'utilisateur afin de rendre sa navigation plus agréable et donc d'améliorer sa satisfaction sur votre site.

Bien entendu, certains feront remarquer que sur certaines pages, des informations liées à l'interaction avec l'utilisateur sont enregistrées. Cela est rendu possible grâce à AJAX (que nous verrons ultérieurement), mais permet uniquement d'ouvrir une communication avec un serveur et d'en recevoir une réponse. En tout état de cause, JavaScript (et donc jQuery) reste cantonné à l'environnement de la page Web et n'a accès ni au système de fichiers de l'ordinateur (cela donnerait trop de « pouvoir » au concepteur du script sur l'environnement de celui qui l'exécute) ni au serveur envoyant le document (cela donnerait trop de « pouvoir » à l'utilisateur sur les données d'un site). Même si les fonctionnalités apportées par le prochain HTML5 vont permettre d'aller bien au-delà des cookies actuels pour conserver des informations sur le poste client, cela restera de façon limitée.

La modification du DOM est donc, vous l'aurez compris, la partie la plus importante d'un script JavaScript, celle qui lui donne sa raison d'être dans la quasi intégralité des cas.

Il ne s'agit pas pour autant d'une partie compliquée, bien qu'il existe de nombreux pièges et erreurs à éviter, des subtilités à connaître. Fort heureusement, jQuery est là pour déjouer ces contrariétés à votre place. Vous pourrez constater que la seule chose que vous demande jQuery est de savoir ce que vous souhaitez faire !

5-1. Créer un nouvel élément HTML

Créer de nouveaux éléments afin de les intégrer à la page est très courant. Il existe plusieurs façons de le faire avec jQuery, mais finalement, toutes reviennent à utiliser la méthode que l'on a déjà évoquée en utilisant la fonction $() en lui passant en paramètre un fragment de HTML.

En HTML pur (aussi appelé vanilla JavaScript), il existe différents moyens de créer du contenu HTML. Le plus courant d'entre eux est d'utiliser la propriété innerHTML des éléments du DOM. Il suffit d'attribuer à cette propriété une chaîne de caractères correspondant au contenu HTML à insérer pour que cette chaîne soit transformée en éléments DOM et intégrée :

 
Sélectionnez
document.getElementById('element').innerHTML =
      '<span id="nouveau">Nouvelle balise span</span>';

Bien que très répandue parce que très pratique, cette méthode n'est pourtant pas normalisée. Il s'agit à l'origine d'une méthode propre à Internet Explorer 4, implémentée en pleine « guerre des navigateurs » qui sévissait à la fin des années 90 entre Internet Explorer et Netscape. Cette méthode faisait d'ailleurs partie d'un ensemble comprenant aussi innerText, outerHTML et outerText. Pour des raisons obscures, seule la première a été largement adoptée par l'ensemble des navigateurs et est aujourd'hui disponible sur tous les moteurs JavaScript. Cependant, cette méthode possède certaines limites, en particulier parce que la création et l'insertion se font en même temps ce qui empêche de finaliser la création de l'élément entre les deux étapes. Enfin, cette méthode est peu compatible avec les méthodes dites du DOM.

La seconde possibilité consiste donc à utiliser les méthodes (normalisées quant à elles) spécifiques au DOM (X)HTML. Par exemple, l'insertion précédente serait équivalente à

 
Sélectionnez
var newSpan = document.createElement('span');
newSpan.id = 'nouveau';
newSpan.appendChild(document.createTextNode('Nouvelle balise span'));
document.getElementById('element').appendChild(newSpan);

Dans le code précédent, j'attribue l'identifiant avec la propriété id de l'élément nouvellement créé. J'aurais pu aussi utiliser la méthode du DOM XML setAttribute('id', 'nouveau'). Dans le cas d'un attribut « standard », il n'y a pas de grande différence entre les deux syntaxes. En revanche, il faut bien penser que ces deux notations prennent un sens radicalement différent si vous souhaitez attribuer une propriété JavaScript qui n'est pas un attribut ou un attribut qui n'est pas standard. Etant dans un cadre de script JavaScript, il me semble préférable d'utiliser autant que possible la notation de propriété JavaScript plutôt que celle de l'attribut DOM.

Vous constatez que la syntaxe du DOM est plus verbeuse que celle avec innerHTML. Elle n'en est pas moins simple pour autant. Du moins pour l'instant… Cela se complique pour certains types d'éléments, comme les tableaux ou les options de balises <select>. Dans ce cas, des méthodes spécifiques (new Option(), createTHead(), createTFoot(), insertRow(), insertCell(), etc., si bien que l'on finit par s'y perdre facilement.

Note concernant les tableaux

Les tableaux sont des éléments extrêmement complexes à afficher pour le navigateur (d'autant qu'il est rare qu'ils soient codés dans les règles de l'art…), si bien que la méthode à utiliser pour la création ou la modification d'un tableau est primordiale, ce qui explique le nombre de méthodes spécifiques dédiées à cette tâche. Sachez que bien souvent, la modification des propriétés d'un tableau (comme par exemple changer la couleur de fond d'une ligne au survol) entraîne ce que l'on appelle un repaint ou reflow, c'est-à-dire que cela force le navigateur à recalculer l'ensemble des dimensions du tableau, ce qui est rapidement très lourd, proportionnellement à la taille de celui-ci. C'est une des principales raisons qui expliquent que la mise en page en tableau est rarement une bonne façon de procéder.

Comme toujours, jQuery est donc là pour traiter de ces problèmes techniques et vous permettre de vous concentrer uniquement sur les fonctionnalités du code. Ainsi, la création du span se fera le plus simplement du monde

 
Sélectionnez
$('<span id="nouveau">Nouvelle balise span</span>');

C'est ensuite à jQuery de se débrouiller à partir de cette chaîne pour créer tous les éléments nécessaires. Par exemple, le code suivant :

 
Sélectionnez
var newSpan = $('<span>Balise span</span><span>Autre balise span 
</span>');
alert(newSpan.length);

affiche bien la figure 4-1.

Image non disponible
Figure 4.1. Création de deux éléments

Alors que ce code :

 
Sélectionnez
var newSpan = $('<span>Balise span</span><br />
        <span>Autre balise span</span>');
alert(newSpan.length);

affiche le résultat de l'image 4-2.

Image non disponible
Figure 4.2. Création de trois éléments

De la même manière, les syntaxes :

 
Sélectionnez
$('<a></a>');
$('<a>');

créeront toutes deux une balise <a>, à laquelle vous pourrez ajouter par la suite (nous verrons comment bientôt) des propriétés et du contenu.

Tout semble donc pour le mieux dans le meilleur des mondes possibles. Mais cela doit forcément se gâter à un moment ou un autre…

La création d'éléments avec jQuery fonctionne est très efficace puisqu'il est possible de différencier différentes balises et leur contenu. En revanche, si vous commencez à imbriquer le code HTML à créer, alors jQuery n'est plus capable de faire cette différenciation. Non pas que l'élément ne sera pas créé, mais il le sera avec d'autres méthodes, à base de innerHTML, comme le montre l'exemple suivant :

 
Sélectionnez
var contenu = $('<div>Voici du contenu <span>dynamique</span></div>');
alert(contenu.length);

qui affiche la figure 4-3.

Image non disponible
Figure 4.3. Création d'éléments imbriqués

Ces exemples sont présentés dans le fichier jquery-4-1.html.

D'autre part, pour éviter toute mauvaise surprise, assurez-vous bien que la portion de code passée en paramètre est valide (c'est-à-dire que les balises sont bien imbriquées et fermées en particulier). Si ce n'est pas le cas, alors le résultat obtenu dépendra de la tolérance du navigateur à une syntaxe non conforme, ce qui signifie que vous n'êtes plus maître du comportement de votre page. Bien entendu, dans ce genre de cas, jQuery (et le navigateur) essayent de répondre au mieux à ce qu'ils reçoivent comme contenu, mais ils ne font pas toujours des miracles !

Sachez aussi que dans le cadre de fragments HTML complexes passés en paramètres, c'est donc la propriété innerHTML qui est utilisée pour créer les éléments. Mais dans ce cas, les navigateurs reformulent parfois ce qu'ils ont reçu (par exemple, les liens sont souvent transformés en URL absolues), donc le résultat obtenu pourra être différent de celui que vous avez indiqué. Il est donc préférable de créer les fragments morceaux par morceaux et de les imbriquer après leur création.

Concernant Internet Explorer, certains pièges spécifiques sont à éviter.

Les attributs type et name des balises <input /> sont de type read-only sur certaines versions, c'est-à-dire qu'une fois créées, vous ne pouvez pas les modifier. Il faut donc les attribuer à la création de la balise :

 
Sélectionnez
$('<input type="button" name="nom" />');

De la même manière, Internet Explorer, jusqu'à sa version 9, ne reconnaît pas la majorité des nouvelles balises HTML5. En dehors de ne pas leur donner le rendu visuel attendu, il n'est pas possible, à priori, de leur donner un style CSS, sauf si on les a déjà créées à l'aide de la méthode createElement(). Ainsi, en fonction des versions d'Internet Explorer utilisées, les codes suivants ne réagiront pas de la même façon.

Ceci ne fonctionnera pas avec Internet Explorer jusqu'à la version 9 :

 
Sélectionnez
var contenu = $('<div><section>Nouvelle balise</section></div>');
$('section').css('color', 'red');
$('body').append(contenu);

Ce code fonctionnera, a priori uniquement pour IE9 :

 
Sélectionnez
var contenu = $('<section>Nouvelle balise</section>');
$('section').css('color', 'red');
$('body').append(contenu);

Ce code reste la méthode la plus sûre.

 
Sélectionnez
var contenu = $('<section></section>');
contenu.text('Nouvelle balise');
$('section').css('color', 'red');
$('body').append(contenu);

Il existe toutefois des scripts disponibles sur Internet pour « initialiser » les balises HTML5 pour Internet Explorer.

Enfin, il est possible de passer un paramètre supplémentaire lors de la création d'un élément qui correspond à un objet de couples propriété ou attribut / valeur :

 
Sélectionnez
$('<div></div>', {
    'click': function(){
        alert('clic');
    },
    id: 'identifiant',
    'class': 'classeCSS',
    text: 'Cliquer'
});

Ce code va créer une balise <div> et lui affecter les méthodes et propriétés passées en second paramètre. Les propriétés peuvent être passées soit de façon littérale (id, text) soit sous forme de chaîne (click, class) et elles peuvent correspondre soit à des attributs habituels d'une balise (id, class) soit à des méthodes jQuery (click, text). Une contrainte importante est que class doit obligatoirement (tout comme l'attribut for) être passé sous forme de chaîne, car class (comme for) est un mot réservé en JavaScript.

De même, dans ce contexte, le premier argument doit être juste le nom de la balise (ici '<div></div>'), le résultat n'est pas garanti si vous insérez le contenu de la balise (par exemple '<div>Contenu de la balise </div>').

Il existe d'autres façons de créer des éléments avec jQuery, que nous verrons au cours de ce chapitre, mais toutes utilisent celles que l'on vient d'évoquer.

5-2. Remplacer le contenu d'une balise

Comme nous l'avons déjà vu, JavaScript sert essentiellement à faire évoluer le contenu d'une page web en fonction des actions de l'utilisateur. Un besoin fréquent va donc être de modifier les informations affichées. Pour cela, il faudra régulièrement modifier, soit le contenu textuel d'une balise, soit le contenu HTML, soit la valeur d'un champ de formulaire. Les méthodes jQuery text(), html() et val() vont permettre cela. Notez bien que ces méthodes (comme d'ailleurs un grand nombre de méthodes jQuery) agissent aussi bien en setter (c'est-à-dire affectation de valeur) qu'en getter (récupération de valeur) : on récupère la valeur souhaitée si l'on ne passe pas de paramètre, sinon on l'affecte.

La méthode html() permet donc d'affecter à une balise le contenu HTML qui lui est passé en paramètre ou de récupérer son contenu HTML.

Par exemple, si l'on considère la page suivante :

jquery-4-2.html
Sélectionnez
<!DOCTYPE HTML>
<html lang="fr">
  <head>
    <meta charset="iso-8859-1">
    <title>Modification de contenu</title>
    <script type="text/javascript" src="http://ajax.googleapis.com/ 
          ajax/libs/jquery/1.6.1/jquery.min.js"></script>
  </head>
  <body>
    <div id="contenant">
  Ceci est une balise <strong>div</strong> qui contient
        <span style="color: navy;">des éléments HTML</span>
    </div>
  </body>
</html>

et que l'on tape dans la console du navigateur l'instruction :

 
Sélectionnez
alert($('#contenant').html());

on obtiendra le message que l'on voit à la capture 4-4.

Image non disponible
Figure 4.4. Méthode html()

De la même manière, l'instruction :

 
Sélectionnez
$('#contenant').html('Contenu <span style="text-decoration:
underline;">modifié</span> contenant <a href="http://www.google.com">un
lien</a>');

transformera l'affichage. Il est illustré en figure 4-5.

Le contenu initial de la balise a bien été remplacé par le code HTML passé en paramètre.

Vous noterez au passage que la console de Firebug (un module complémentaire de Firefox indispensable au développement web) permet d'afficher la valeur retournée par l'instruction, ici [div#contenant] qui correspond à l'objet jQuery en cours de traitement. souvenez-vous que c'est le fait de renvoyer cette valeur qui permet de chaîner les instructions jQuery.

Image non disponible
Figure 4.5. Méthode html (contenu)

Notez aussi que le paramètre passé à la méthode html() peut ne pas comporter de balise et être du simple texte.

Cependant, si vous souhaitez uniquement insérer du contenu textuel comme contenu de la balise, vous pouvez aussi utiliser la méthode text().

Cette méthode est particulièrement intéressante pour récupérer uniquement le contenu textuel d'une balise (et de ses balises descendantes) en expurgeant son formatage HTML. Par exemple, la méthode text() sur l'exemple précédent affichera le résultat de la figure 4-6.

Image non disponible
Figure 4.6. Méthode text()

À l'inverse, si vous passez du contenu HTML en paramètre, vous obtiendrez le résultat illustré à la figure 4-7.

Image non disponible
Figure 4.7. Méthode text(contenuHTML)

On constate que le code HTML n'est cette fois pas interprété et qu'il apparaît tel quel à l'affichage. En fait, la méthode text() utilise en interne la méthode JavaScript createTextNode() qui permet, comme son nom l'indique, de créer un nœud texte en échappant les caractères de formatage de code.

Ceci dit, il est assez peu courant de vouloir afficher du code HTML de cette façon, on peut donc légitimement se poser la question de savoir s'il vaut mieux utiliser la méthode html() ou la méthode text() pour insérer du contenu textuel dans une balise.

En dehors de l'aspect purement sémantique de leur nom, c'est surtout au niveau des performances que la réponse va être pertinente.

Le script suivant va donc récapituler l'utilisation de ces deux méthodes. Il vous permet de sélectionner au choix un texte ou un fragment HTML et de l'insérer dans une balise englobante. Enfin, une fonction permet de tester sur une dizaine de millier d'itérations les performances de chaque option.

 
Sélectionnez
<!DOCTYPE HTML>
<html lang="fr">
  <head>
    <meta charset="iso-8859-1">
    <title>Modification de contenu</title>
    <script type="text/javascript" src="http://ajax.googleapis.com/ 
            ajax/libs/jquery/1.6.1/jquery.min.js"></script>
    <script type="text/javascript">
      $(function(){
                var newContent = '<a href="http://www.google.com">Lien
                vers Google.</a>';
        function ajout(methode){
          $('#contenu')[methode](newContent);
        }
        function stress(){
          var resultat = '', debut, fin, i;
          $.each(['text', 'html'], function(index, methode){
            newContent = '<a href="http://www.google.com">Lien
                    vers Google.</a>';
            debut = new Date().getTime();
            for(i=0; i < 10000; i++){
              ajout(methode);
            }
            fin = new Date().getTime() - debut;
            resultat+= 'Méthode ' + methode + ' (HTML) :
<strong>' + fin + '</strong>ms<br />';
            newContent = 'Nouveau contenu à afficher.';
            debut = new Date().getTime();
            for(i=0; i < 10000; i++){
              ajout(methode);
            }
            fin = new Date().getTime() - debut;
            resultat+= 'Méthode ' + methode + ' (Texte) :
<strong>' + fin + '</strong>ms<br />';
          });
          $('#resultat').html(resultat);
        }
        $('#choix').click(function(){
          newContent = $(this).find('input:checked').val();
        });
        $('#texte').click(function(){
          ajout('text');
        });
        $('#html').click(function(){
          ajout('html');
        });
        $('#perfs').click(stress);
      });
    </script>
  </head>
  <body>
    <p id="contenu">Information initiale affichée sur la page.</p>
    <p id="choix">
      <label for="ajoutTexte">Ajouter du texte : </label>
      <input type="radio" name="option" id="ajoutTexte"  
            value="Nouveau contenu à afficher." /><br />
      <label for="ajoutHTML">Ajouter du HTML : </label>
      <input type="radio" name="option" id="ajoutHTML" value= 
      "<a href='http://www.google.com'>Lien vers Google.</a>" />
    </p>
    <div>
      <button id="texte">Méthode text()</button>
      <button id="html">Méthode html()</button>
    </div>
    <p>
      <button id="perfs">Tester    les    performances</button>
    </p>
    <p id="resultat"></p>
  </body>
</html>

Détaillons un peu le fonctionnement de ce script.

  • Deux boutons radios permettent de définir le type de contenu à insérer. Plutôt que de gérer le clic sur chaque bouton, nous observons l'événement clic sur la balise <p> qui les contient. Lors du clic, on récupère le bouton coché ($(this).find(‹input:checked›) et on affecte à la variable newContent sa valeur (attribut value).
  • Le clic sur les deux boutons « Méthode … » appellent une fonction ajout() à laquelle on passe en paramètre la méthode d'insertion à utiliser.
  • Notez la méthode employée pour appeler une méthode d'objet en fonction du paramètre reçu. Si nous avions employé la syntaxe $(‹#contenu›).methode(newContent); alors jQuery aurait cherché la méthode methode qui n'existe pas dans sa syntaxe et aurait généré une erreur. Ce que nous souhaitons, c'est utiliser la méthode dont le nom est la valeur du paramètre, pas son nom. Nous utilisons donc la notation à crochets pour indiquer qu'il faut bien appeler la méthode dont le nom correspond à la valeur du paramètre reçu. La notation $(‹#contenu›)[methode] sera donc transformée par JavaScript en $(‹#contenu›)['html'] (par exemple) qui est équivalent à $(‹#contenu›).html(). On appelle donc bien la bonne méthode.
  • Enfin, le bouton « Tester » va lancer la fonction stress() qui va itérer sur les valeurs d'un tableau, ce qui va permettre d'alterner avec toutes les combinaisons possibles de méthode et type de contenu pour effectuer 10 000 boucles d'insertion. Pour chaque boucle, on récupère le timestamp (nombre de millisecondes depuis le 1er janvier 1970) au début et à la fin, on les soustrait et on stocke le résultat dans une chaîne que l'on affiche à la fin de l'exécution de la fonction. Attention, les résultats dépendent beaucoup de l'environnement dans lequel vous travaillez. Pas uniquement les performances pures de votre ordinateur, mais aussi par exemple des différents modules utilisés dans le navigateur. Ne vous étonnez donc pas si les résultats issus de vos propres tests ne correspondent pas à ceux affichés. L'important étant de constater les ordres de grandeur des différentes méthodes testées.

Le résultat affiché par la fonction stress() dans Firefox est visible à la figure 4-8.

Image non disponible
Figure 4.8. Performances des méthodes html() et text()

Le seul résultat utile de ce test concerne l'insertion de contenu textuel (puisque l'insertion de contenu HTML par les deux méthodes ne produit pas le même résultat) et il apparaît clairement que l'ajout par la méthode html() est plus performant que par la méthode text() (attention, le test sur un seul environnement avec un nombre fixe d'itérations ne permet pas de conclure que html() est deux fois plus performant que text(), juste que html() est plus performant que text() . Il est donc recommandé, sauf besoins spécifiques, d'utiliser en priorité la méthode html() pour modifier le contenu d'une balise.

Retenez toutefois que l'un des besoins spécifiques pour utiliser text() plutôt que html() est le cas des documents XML (typiquement, des résultats renvoyés par une requête AJAX). Seul text() est capable de remplacer le contenu d'une balise XML ; html() ne gère pas les documents de type XML.

Les champs de formulaire constituent des cas particuliers. Ces balises étant de type autofermantes, elles ne contiennent ni contenu texte ni contenu HTML, mais il est très courant d'avoir à modifier leur valeur. Pour cela, jQuery propose la méthode val() (utilisée dans le script précédent pour changer la valeur de la variable spécifiant le type de contenu à insérer). Il est donc possible avec cette méthode de récupérer ou d'affecter la valeur de l'attribut value d'une balise de type input, select ou textarea. Ces valeurs ne pouvant être que textuelles et l'utilisation de cette méthode étant assez triviale, nous ne nous attarderons pas dessus. Le seul aspect particulier à noter est : dans le cas d'une balise <select> de type multiple, la valeur retournée par val() sera un tableau des attributs value des balises <option> sélectionnées.

Les trois méthodes html(), text() et val() peuvent donc prendre en paramètre une chaîne à insérer soit en contenu de la balise soit en attribut value. Il est aussi possible de leur passer une fonction, qui prendra en paramètres l'indice de l'élément dans l'objet jQuery en cours et le texte à remplacer.

jquery-4-4.html
Sélectionnez
<!DOCTYPE HTML>
<html lang="fr">
  <head>
    <meta charset="iso-8859-1">
    <title>Modification de contenu</title>
    <script type="text/javascript" src="http://ajax.googleapis.com/ 
            ajax/libs/jquery/1.6.1/jquery.min.js"></script>
    <script type="text/javascript">
      $(function(){
                var remplace = ['a', 'e', 'i', 'o', 'u', 'y'];
                $('#modifier').click(function(){
                    $('li').html(function(i, texte){
                        return texte.replace(/o/g, remplace[i]);
                    });
                });
      });
    </script>
  </head>
  <body>
    <ul>
<li>toto</li><li>toto</li><li>toto</li><li>toto</li>
          <li>toto</li><li>toto</li>
    </ul>
    <p><button id="modifier">Changer la liste</button></p>
  </body>
</html>

Ce code affichera après le clic sur le bouton le résultat de la figure 4-9.

Image non disponible
Figure 4.9. Utilisation d'une fonction de rappel

Notez bien que la nouvelle valeur affectée correspond à celle retournée par la fonction, il est donc obligatoire d'utiliser le mot-clé return.

5-3. Ajouter du contenu au document

Dans de nombreux cas, vous aurez besoin d'ajouter des informations dans la page plutôt que de modifier le contenu d'une balise comme nous l'avons fait précédemment. Pour cela, il faudra d'abord créer le nouveau contenu, qu'il soit HTML ou textuel, puis l'insérer à un emplacement choisi.

Pour ce qui est de l'insertion, les méthodes natives du DOM JavaScript sont relativement pauvres. De façon globale, il n'existe que les méthodes appendChild(), appendData() (étonnamment, cette dernière est assez peu fréquente) et insertBefore(), auxquelles on peut ajouter certaines méthodes spécifiques à des éléments particuliers : add(), insertRow(), insertCell()…… Cela signifie que les seules opérations réalisables directement sont assez limitées (insérer le nouveau contenu à la suite de celui existant dans une balise ou avant un élément précis) et ne couvrent pas l'ensemble des besoins usuels des développeurs. Dans la plupart des cas, il faut donc parcourir l'arbre DOM avant de pouvoir insérer le nouveau contenu à l'endroit souhaité. Heureusement, jQuery élargi la gamme des méthodes d'insertion afin de faire à votre place une partie du travail (souvenez-vous que de façon interne, jQuery utilise les méthodes du DOM pour réaliser ces actions).

Il existe deux types d'insertion dans le document avec le JavaScript natif, à l'extérieur ou à l'intérieur d'un élément de référence. Jquery ajoute à cela un troisième type qui va consister à entourer des éléments avec d'autres nouvellement créés.

Concernant les insertions à l'extérieur, il est possible, à partir d'un ensemble d'éléments jQuery, d'ajouter le nouveau contenu après ou avant avec les méthodes after() et before(). Ces méthodes prennent en paramètre le contenu à insérer :

 
Sélectionnez
$(element).after(contenu);
$(element).before(contenu);

Si vous avez plusieurs éléments à insérer, il est possible de passer autant de paramètres à ces méthodes que vous le souhaitez.

Généralement, contenu sera un nouvel élément nouvellement créé avec jQuery, par exemple :

 
Sélectionnez
var contenu = $('<p>Bonjour</p>');
$('#reference').before(contenu);

Mais d'autres formes sont possibles, en particulier de passer en paramètre une chaîne représentant le code HTML à insérer, dans ce cas, le nouvel élément sera créé de façon interne avant d'être inséré :

 
Sélectionnez
$('#reference').before('<p>Bonjour</p>');

Notez que vous pouvez aussi passer en paramètre un sélecteur jQuery, dans ce cas, les éléments récupérés seront déplacés (et non pas copiés) après ou avant l'élément (ou les éléments) de référence :

 
Sélectionnez
$('#reference').after($('.aDeplacer'));

Il est aussi possible d'utiliser ces méthodes sur des éléments qui ne sont pas dans le DOM :

 
Sélectionnez
$('<h1>Titre</h1>').after('<p>Bienvenue !</p>');

Le code 4-5 récapitule les différentes possibilités d'utilisation de ces méthodes.

jquery-4-5.html
Sélectionnez
<!DOCTYPE HTML>
<html lang="fr">
  <head>
    <meta charset="iso-8859-1">
    <title>Insertion de    contenu</title>
        <style type="text/css">
            .nouveau{outline: 1px solid  red;  
              background-color: #f0f0f0;}
        </style>
    <script type="text/javascript" src="http://ajax.googleapis.com/ 
        ajax/libs/jquery/1.6.1/jquery.min.js"></script>
    <script type="text/javascript">
      $(function(){
                $('#reference').after('<div class="nouveau"> 
Méthode after()</div>')
                               .before($('<h1></h1>',  
          {'class': 'nouveau'}).html('Bonjour !')
        .after('<div class="nouveau">Méthode before()</div>'));
      });
    </script>
  </head>
  <body>
    <div id="reference">Contenu initial du document</div>
  </body>
</html>

À l'exécution, on obtiendra le résultat de la figure 4-10.

Vous noterez que la création de la balise <h1> n'est pas possible en une seule instruction ($('<h1 class=« nouveau »>Bonjour !</h1>') car dans ce cas, la construction est trop complexe et jQuery ne peut pas la transformer en élément avant l'insertion.

Image non disponible
Figure 4.10. Méthodes after() et before()

Enfin, il est aussi possible de passer à ces éléments une fonction, le contenu inséré sera alors le résultat retourné par cette fonction qui sera appelée pour chaque élément de la collection de référence.

Par exemple, le code 4-6 ajoutera un élément de liste après tous ceux existant avec comme texte une référence à l'indice de chaque élément initial.

jquery-4-6.html
Sélectionnez
<!DOCTYPE HTML>
<html lang="fr">
  <head>
    <meta charset="iso-8859-1">
    <title>Modification de contenu</title>
    <script type="text/javascript" src="http://ajax.googleapis.com/ 
          ajax/libs/jquery/1.6.1/jquery.min.js"></script>
    <script type="text/javascript">
      $(function(){
                $('li').after(function(i){
                    return $('<li></li>').html('Ajouté après l\'élément ' + i);
                });
            });
    </script>
  </head>
  <body>
    <ul>
                <li>toto</li>
                <li>toto</li>
                <li>toto</li>
                <li>toto</li>
                <li>toto</li>
                <li>toto</li>
    </ul>
  </body>
</html>

La figure 4.11 illustre le résultat.

Image non disponible
Figure 4.11. Méthode after (fonction)

Les méthodes after() et before() fonctionnent selon le principe d'une sélection d'éléments à laquelle on applique la méthode souhaitée. Il est possible de faire l'inverse, c'est-à-dire d'appliquer les méthodes d'insertion au contenu à ajouter en passant en paramètre la collection à partir de laquelle effectuer l'insertion. On utilise pour cela les méthodes insertAfter() et insertBefore(). En dehors de cela, le fonctionnement est le même. Par exemple, pour obtenir le résultat de la figure 4-11 avec ces méthodes, il faudrait remplacer le code jQuery par :

 
Sélectionnez
$(function(){
    $('<div class="nouveau">Méthode after()</div>')
              .insertAfter($('#reference'));
    $('<h1></h1>', {'class': 'nouveau'}).html('Bonjour !')
    .after('<div class="nouveau">Méthode before()</div>')
    .insertBefore($('#reference'));
});

L'utilité de disposer de ces deux façons distinctes de procéder pour obtenir le même résultat peut ne pas vous sembler évident. Mais rappelez-vous qu'une des grandes forces de jQuery est la capacité de chaîner les instructions sur un même ensemble d'éléments. Ces deux méthodologies distinctes vont donc vous permettre d'opter pour l'une ou l'autre des méthodes en fonction des éléments sur lesquels vous souhaiterez continuer à travailler et donc sur lesquels vous voudrez chaîner d'autres instructions.

Un autre type d'insertion dont vous aurez couramment besoin est l'ajout à l'intérieur d'un élément.

Nous avons déjà évoqué les méthodes html() et text(), mais celles-ci remplacent le contenu existant s'il y en a. Les méthodes append() et prepend() vous permettent cette fois-ci d'ajouter le nouveau contenu sans toucher à celui existant. La méthode append() va insérer son (ou ses) paramètre(s) après le contenu existant, prepend() fera l'ajout avant le contenu existant.

 
Sélectionnez
$(reference).append(contenu);
$(reference).prepend(contenu);

Le fonctionnement de ces méthodes étant strictement identique à celui de after() et before(), nous ne nous attarderons pas plus dessus. La seule différence se situe au niveau de l'utilisation avec une fonction de rappel, dans le cas de after() et before(), nous avons vu que cette fonction recevait en paramètre le rang de l'élément en cours dans la collection de référence, avec append() et prepend(), un second paramètre contient le code HTML de l'élément avant l'insertion.

De la même manière qu'avec insertBefore() et insertAfter(), les méthodes appendTo() et prependTo() permettent de garder en référence le nouveau contenu afin de pouvoir chaîner d'autres actions dessus.

 
Sélectionnez
$(contenu).appendTo(reference);
$(contenu).prependTo(reference);

Enfin, le dernier type d'insertion, propre à jQuery, consiste à entourer des éléments avec d'autres. Cela revient en fait à ajouter un élément dans le DOM puis lui insérer les éléments référencés.

La méthode wrap() permet de faire cela. Elle prend en paramètre un élément jQuery, un élément du DOM ou une chaîne correspondant à un fragment HTML et l'ajoute autour de chaque élément de l'objet jQuery de référence (notez que cette fonction retourne l'objet de référence, pas les éléments créés).

L'exemple suivant vous montre un exemple d'utilisation de wrap() :

 
Sélectionnez
<!DOCTYPE HTML>
<html lang="fr">
  <head>
    <meta charset="iso-8859-1">
    <title>Méthode wrap()</title>
        <style type="text/css">.nouveau{outline: 1px solid red;  
background-color: #f0f0f0;}</style>
    <script type="text/javascript" src="http://ajax.googleapis.com/ 
        ajax/libs/jquery/1.6.1/jquery.min.js"></script>
    <script type="text/javascript">
      $(function(){
                $('p').wrap('<div class="nouveau"></div>')
      });
    </script>
  </head>
  <body>
    <p>Paragraphe 1</p>
    <p>Paragraphe 2</p>
    <p>Paragraphe 3</p>
    <p>Paragraphe 4</p>
    <p>Paragraphe 5</p>
  </body>
</html>

Le code va récupérer toutes les balises paragraphe et les insérer dans une balise <div>, ce qui affichera la figure 4-12.

Image non disponible
Figure 4.12. Méthode wrap()

Bien entendu, le paramètre passé dans cet exemple est relativement simple (ce qui est d'ailleurs recommandé), mais il est néanmoins possible de passer en paramètre une portion HTML plus complexe notamment avec des imbrications de balises. Dans ce cas, il est nécessaire que la structure soit verticale (c'est-à-dire uniquement composée de relations parent / enfant), par exemple la structure :

 
Sélectionnez
wrap('<div><strong><span></span></strong></div>')

sera correctement interprétée mais pas :

 
Sélectionnez
wrap('<div><strong><span></span></strong></div><div></div>')

puisqu'elle contient deux niveaux d'arborescence.

Il est aussi possible d'utiliser un élément existant comme contenant ; le code qui suit en est un exemple.

jquery-4-8.html
Sélectionnez
<!DOCTYPE HTML>
<html lang="fr">
  <head>
    <meta charset="iso-8859-1">
    <title>Méthode wrap()</title>
        <style type="text/css">.nouveau{outline: 1px solid red;  
              background-color: #f0f0f0;}</style>
    <script type="text/javascript" src="http://ajax.googleapis.com/ 
            ajax/libs/jquery/1.6.1/jquery.min.js"></script>
    <script type="text/javascript">
      $(function(){
                $('p').wrap($('#conteneur'));
      });
    </script>
  </head>
  <body>
    <p>Paragraphe 1</p>
    <p>Paragraphe 2</p>
    <p>Paragraphe 3</p>
    <p>Paragraphe 4</p>
        <div class="nouveau" id="conteneur">Balise à insérer</div>
  </body>
</html>

Ce code affichera le résultat de la figure 4-13.

Image non disponible
Figure 4.13. Méthode wrap($(element))

On constate ici que contrairement à ce que l'on a vu précédemment, wrap() se contente de copier l'élément <div>, sans le retirer du document. Dans ce cas aussi, il est important de bien cibler le sélecteur à passer en paramètre, par exemple s'il contient plusieurs élément, c'est uniquement le premier qui sera utilisé par wrap().

Enfin, il est aussi possible de passer en paramètre une fonction de rappel (à laquelle sera passé en paramètre le rang de l'élément en cours dans la collection) qui devra retourner comme résultat le paramètre à utiliser par wrap() pour chaque élément.

La méthode wrapInner() se comporte exactement de la même façon que wrap() sauf qu'elle entoure non pas chaque élément en référence, mais le contenu de ces éléments. Par exemple, avec le code HTML précédent, l'instruction :

 
Sélectionnez
$('p').wrapInner('<strong></strong>');

permettrait d'insérer tout le contenu des balises <p> dans des balises <strong>.

Il est aussi possible de créer une balise contenante autour de l'ensemble des éléments de la collection grâce à la méthode wrapAll(). Par exemple, l'instruction :

 
Sélectionnez
$('p').wrapAll('<div></div>');

génèrera une balise <div> contenant toutes les balises <p> du document. Dans le cas où les éléments de référence ne soient pas adjacents, alors les autres éléments seront déplacés et l'insertion se fera, au niveau de l'arborescence, à l'endroit du premier élément de la collection initiale.

jquery-4-9.html
Sélectionnez
<!DOCTYPE HTML>
<html lang="fr">
  <head>
    <meta charset="iso-8859-1">
    <title>Méthode wrapAll()</title>
        <style type="text/css">
            .autour{outline: 1px solid red; background-color: #f0f0f0; 
            height: 50px;}
            .nouveau{outline: 2px solid green;}
            p{outline: 1px solid blue;}
        </style>
    <script type="text/javascript" src="http://ajax.googleapis.com/ 
          ajax/libs/jquery/1.6.1/jquery.min.js"></script>
    <script type="text/javascript">
      $(function(){
                $('p').wrapAll('<div class="nouveau"></div>');
      });
    </script>
  </head>
  <body>
    <p>Paragraphe 1</p>
    <div class="autour"><p>Paragraphe 2</p></div>
    <p>Paragraphe 3</p>
        <div>Une balise div perdue...</div>
    <p>Paragraphe 4</p>
  </body>
</html>

Ce code affichera le résultat illustré en figure 4-14.

Image non disponible
Figure 4.14. Méthode wrapAll()

Les balises <p> ont bien été déplacées (mais leur conteneur conservé).

5-4. Supprimer des éléments

Un autre type fréquemment rencontré de modification du document est de supprimer du contenu. Dans ce cadre aussi, jQuery enrichit les méthodes proposées nativement par JavaScript.

La méthode remove() permet de supprimer un élément du DOM. Notez que cette action, qui est pourtant fréquente, nécessite plusieurs instructions en JavaScript :

 
Sélectionnez
var elem = document.getElementById('element');
elem.parentNode.removeChild(elem);

Il faut donc d'abord référencer l'élément à supprimer, puis son élément parent auquel on applique la méthode de suppression. Avec jQuery, l'opération est plus directe :

 
Sélectionnez
$('#element').remove();

La méthode remove() peut aussi recevoir un paramètre (de type sélecteur) pour permettre de filtrer les éléments à supprimer, par exemple l'instruction

 
Sélectionnez
$('div').remove('.supprimer');

va supprimer tous les éléments ayant la classe CSS supprimer présentes dans une balise <div>. Cependant, cela ne fonctionne pas si vous passez en paramètre un nom de balise. Vous aurez donc avantage à filtrer les éléments à supprimer au préalable, par exemple avec :

 
Sélectionnez
$('div').find('span').remove();

Il est important de garder à l'esprit que la méthode remove() est destructive, c'est-à-dire qu'avant de supprimer l'élément, elle va d'abord supprimer tous ses enfants ainsi que tous les événements ou autres données attachées à ces éléments. Ce comportement est très utile car il permet d'éviter les phénomènes de fuite de mémoire (memory leak) que peut engendrer la suppression trop « brutale » d'éléments du DOM. Ceci dit, vous pouvez avoir besoin de supprimer un élément et de le remettre dans le document ultérieurement, dans ce cas, il faudra utiliser la méthode detach(). L'exemple suivant vous montre comment fonctionnent ces deux méthodes.

jquery-4-7.html
Sélectionnez
<!DOCTYPE HTML>
<html lang="fr">
  <head>
    <meta charset="iso-8859-1">
    <title>Suppression de contenu</title>
        <style type="text/css">
            p{
                outline:  1px solid red;
                background-color: #f0f0f0;
                cursor: pointer;
                padding: 10px;
            }
        </style>
    <script type="text/javascript" src="http://ajax.googleapis.com/ 
            ajax/libs/jquery/1.6.1/jquery.min.js"></script>
    <script type="text/javascript">
      $(function(){
                var elem1, elem2;
                $('p').click(function(){
                    alert('Identifiant : ' + this.id);
                });
                $('#removeP').toggle(function(){
                        $(this).html('Réinsérer le paragraphe remove');
                        elem1 = $('#remove').remove();
                    }, function(){
                        $(this).html('Supprimer le paragraphe remove');
                        $('#removeP').before(elem1);
                    }
                );
                $('#detachP').toggle(function(){
                        $(this).html('Réinsérer le paragraphe detach');
                        elem2 = $('#detach').detach();
                    },function(){
                        $(this).html('Supprimer le paragraphe detach');
                        $('#detachP').before(elem2);
                    }
                );
            });
    </script>
  </head>
  <body>
    <p id="remove">Elément géré par la méthode remove(). Cliquez
            dessus pour afficher son id</p>
        <div><button id="removeP">Supprimer le paragraphe remove
        </button></div>
    <p id="detach">Elément géré par la méthode detach(). Cliquez
            dessus pour afficher son id</p>
        <div><button id="detachP">Supprimer le paragraphe detach
        </button></div>
  </body>
</html>

Lorsque vous supprimez le premier paragraphe et que vous le réinsérez, il n'y a plus de message affiché lorsque vous cliquez sur le paragraphe. Avec la méthode detach() (second paragraphe), l'événement reste disponible.

Si vous souhaitez supprimer le contenu d'un élément mais pas l'élément lui-même, une première approche pourrait être d'utiliser par exemple la méthode html('') avec comme paramètre une chaîne vide (attention, si vous ne passez pas de paramètre, la méthode se contente de renvoyer le contenu HTML de l'élément mais ne le vide pas). Cela fonctionne correctement, mais avant d'affecter un nouveau contenu avec la méthode html(), jQuery commence par vider l'élément, or la méthode empty(), permettant de vider un élément est disponible. Il est donc préférable de l'utiliser puisque cela évitera d'effectuer les traitements d'insertion (inutiles dans ce cas de figure) de la méthode html(). Notez que la méthode empty() supprime tous les nœuds, y compris ceux de type texte et que vous n'avez pas de moyen de les récupérer.

Enfin, la méthode unwrap() permet d'effectuer l'opération inverse de wrap(), c'est-à-dire qu'elle supprime, pour chaque élément passé en référence, sa balise parente (attention, cette opération affecte aussi toutes les autres balises présentes dans la balise parente).

L'exemple qui suit montre l'utilisation de cette méthode dans différents cas typiques :

jquery-4-10.html
Sélectionnez
<!DOCTYPE HTML>
<html lang="fr">
  <head>
    <meta charset="iso-8859-1">
    <title>Méthode unwrap()</title>
        <style type="text/css">
            .autour{outline: 1px solid red; background-color: #f0f0f0; 
            height: 50px;}
            p{outline: 1px solid blue;}
            h2{border: 1px dotted gray;}
        </style>
    <script type="text/javascript" src="http://ajax.googleapis.com/ 
              ajax/libs/jquery/1.6.1/jquery.min.js"></script>
    <script type="text/javascript">
      $(function(){
                $('button').click(function(){
                    $('p').unwrap();
                });
      });
    </script>
  </head>
  <body>
    <h2>
            <p>Paragraphe 1</p>
        <div class="autour">
                <p>Paragraphe 2</p>
            </div>
        </h2>
    <p>Paragraphe 3</p>
        <div>Une balise div perdue...</div>
    <div class="parent1">
            <div class="parent2">
                <p>Paragraphe 4</p>
                <p>Paragraphe 5</p>
            </div>
        </div>
        <button>$('p').unwrap()</button>
  </body>
</html>

Dans le premier groupe de paragraphes, nous avons une balise englobante (<h2>) et le paragraphe 2 est lui-même inclus dans une balise <div>. Dans le second groupe, deux paragraphes sont intégrés dans deux balises <div> imbriquées.

Les rendus dans le navigateur sont montrés aux figures 4-15 et 4-16.

Image non disponible
Figure 4.15. Méthode unwrap() avant
Image non disponible
Figure 4.16. Méthode unwrap() après

Firebug nous montre bien que si le résultat était prévisible pour le premier groupe de paragraphes, puisque unwrap() a supprimé la balise <h2> pour le paragraphe 1 et la balise autour pour le paragraphe 2, en revanche, le résultat est plus surprenant pour le second groupe. En effet, on aurait pu s'attendre à ce que la méthode supprime la balise parent2 pour le paragraphe 4 puis parent1 pour le paragraphe 5, ce qui aurait résulté que ces deux paragraphes n'aient plus de <div> parent, au lieu de cela, seule la balise parent2 a été supprimée.

5-5. Copier, déplacer et remplacer des éléments

Nous avons déjà vu que certaines méthodes d'insertion dans le DOM (after(), before(), append(), prepend()……) permettent, si on leur passe en paramètre des éléments existants de la page, de déplacer ces éléments. De la même façon, wrapAll(), lorsque les éléments auxquels elle s'applique ne sont pas adjacents, déplace ceux pour lesquels c'est nécessaire.

Cependant, plutôt que de déplacer un élément, vous pourrez avoir envie d'en placer une copie à un autre endroit du document. La méthode clone() vous offre cette possibilité. Cette méthode permet de créer une copie d'un objet jQuery que vous pouvez ensuite utiliser comme bon vous semble sans affecter l'objet initial. Le code 4-11 vous montre une utilisation de cette méthode.

jquery-4-11.html
Sélectionnez
<!DOCTYPE HTML>
<html lang="fr">
  <head>
    <meta charset="iso-8859-1">
    <title>Méthode clone()</title>
        <style type="text/css">
            #ref{background-color: yellow; padding: 10px; margin: 5px;}
            #lien{background-color: silver; cursor: pointer;}
        </style>
    <script type="text/javascript" src="http://ajax.googleapis.com/ 
              ajax/libs/jquery/1.6.1/jquery.min.js"></script>
    <script type="text/javascript">
      $(function(){
                $('#ref').hover(
                        function(){
                            $(this).css('text-decoration', 'underline');
                        },
                        function(){
                            $(this).css('text-decoration', '');
                        }
                );
                $('#lien').click(function(){
                    alert(this.id);
                });
                $('#clone1').click(function(){
                    var aDeplacer = $('#ref').clone();
                    $('#ref').after(aDeplacer);
                });
            });
    </script>
  </head>
  <body>
    <div id="ref">
    Element initialement présent dans la page.<br />
            Cliquez <span id="lien">sur ce lien</span> pour afficher
son identifiant.
        </div>
        <button id="clone1">clone()</button>
  </body>
</html>

Si l'on clique sur le bouton, on obtient le résultat de la figure 4-17.

Image non disponible
Figure 4.17. Méthode clone()

Plusieurs choses importantes sont à noter au niveau du résultat obtenu. Comme vous pouvez le constater dans la console HTML de Firebug, l'élément ajouté est identique à celui d'origine, en particulier, il a conservé son identifiant (y compris pour les balises inclues) ce qui est contraire à la règle qui veut qu'un identifiant soit unique dans le document. Notamment, cela vous empêchera de récupérer ce nouvel élément via l'instruction $('#ref'). Il est très important de prendre ce point en considération lorsque vous utiliserez cette méthode. D'autre part, ce n'est pas visible sur la capture d'écran mais les événements existants sur l'élément d'origine n'ont eux pas été copiés, ainsi le survol de la balise et le clic sur la balise <span> sont inactifs sur l'élément copié. Pour y pallier (si besoin), il est possible de passer un ou deux paramètres de type booléen à la méthode clone(). Le premier indique s'il faut conserver ou non les événements liés à l'élément à copier sur la copie, le second précise s'il faut aussi conserver les événements liés aux éléments enfants. Les valeurs par défaut de ces paramètres sont false pour le premier et la valeur du premier pour le second. C'est-à-dire que si aucun paramètre n'est transmis, ils vaudront tous les deux false et si un seul est transmis, les deux paramètres prendront cette valeur.

Attention lors de l'utilisation de ces paramètres concernant les événements attachés avec les méthodes live() et delegate(). En effet, live() affecte l'événement à la racine du document et delegate() à l'élément qui a appelé la méthode. Donc, dans ces cas précis, le résultat obtenu pourra, en cas d'étourderie, ne pas être celui désiré !

Enfin, vous avez aussi la possibilité de remplacer un élément par un autre nouvellement créé avec les méthodes replaceWith() et replaceAll(). L'utilisation de replaceWith() est similaire à celle de html() sauf qu'ici, plutôt que de remplacer le contenu de l'élément par le paramètre reçu, c'est l'élément lui-même (ou plus exactement chaque élément de l'objet jQuery qui appelle la méthode) qui sera remplacé. Ainsi l'instruction

 
Sélectionnez
$('.bonjour').replaceWith('<h2>Bonjour !</h2>');

Remplacera toutes les balises ayant bonjour comme classe CSS par une balise titre de niveau 2.

La méthode replaceAll(), quant à elle, est la version inversée, c'est-à-dire que ce sont les éléments de la collection passée en paramètre qui seront remplacés par l'objet appelant la méthode. Ainsi, l'exemple précédent deviendrait :

 
Sélectionnez
$('<h2>Bonjour :</h2>').replaceAll('.bonjour');

Ceci offre la possibilité d'enchaîner d'autres instructions à appliquer à la nouvelle balise <h2>.

Notez enfin qu'il est possible de passer en paramètre de replaceWith() une fonction de rappel qui devra avoir comme valeur de retour l'élément de remplacement, l'exemple 4-12 illustre ceci.

jquery-4-12.html
Sélectionnez
<!DOCTYPE HTML>
<html lang="fr">
  <head>
    <meta charset="iso-8859-1">
    <title>Méthode replaceWith()</title>
    <script type="text/javascript" src="http://ajax.googleapis.com/ 
              ajax/libs/jquery/1.6.1/jquery.min.js"></script>
    <script type="text/javascript">
      $(function(){
                var titre = 0;
                $('.bonjour').replaceWith(function(){
                    titre = Math.min(titre, 5);
                    return '<h' + (++titre) + '>Bonjour !</h' + titre + '>';
                });
            });
    </script>
  </head>
  <body>
    <div class="bonjour">Div bonjour 1</div>
    <p class="bonjour">Div bonjour 2</p>
    <div class="bonjour">Div bonjour 3</div>
    <pre class="bonjour">Div bonjour 4</pre>
    <div class="bonjour">Div bonjour 5</div>
    <div class="bonjour">Div bonjour 6</div>
    <div class="bonjour">Div bonjour 7</div>
    <div class="bonjour">Div bonjour 8</div>
  </body>
</html>

Vous pourrez remarquer la forme particulièrement condensée de la fonction de rappel, qui permet de réduire le nombre d'instructions à exécuter. Cependant, ce genre de code (utilisé ici pour ne pas alourdir le code de la page dont l'intérêt est de présenter le fonctionnement de la méthode replaceWith()) est à utiliser avec beaucoup de précautions. En effet, s'il permet de réduire la taille du code, il rend aussi celui-ci plus difficile à lire et donc à en comprendre le but, de ce fait, si vous avez à le reprendre ultérieurement (peut-être plusieurs mois voire années plus tard), ou pire, si d'autres que vous ont à le maintenir, cela rendra cette tâche plus compliquée qu'avec un code plus détaillé.

Notez aussi la préincrémentation de la variable (++titre). Si nous avions utilisé une postincrémentation (titre++), alors c'est la valeur de titre avant l'incrémentation qui aurait été insérée pour l'ouverture de la balise, puis l'incrémentation aurait eu lieu, ce qui aurait produit un code erroné puisque l'indice de la balise ouvrante aurait été différent de celui de la balise fermante et qu'à la première itération, c'est une balise <h0> qui aurait finalement été créée, mais cette balise n'existe pas. Si nous avions plus décomposé le code et écrit l'incrémentation sur une seule instruction, alors le résultat aurait été le même quel que soit le type d'incrémentation.

Comme on peut le constater, la fonction permet de remplacer chaque élément ayant comme classe bonjour par une balise titre dont le niveau dépend de la valeur d'une variable. Pour conserver un code correct, l'incrémentation de la variable n'excède pas 6 (voir figure 4-18).

Image non disponible
Figure 4.18. Méthode replaceWith()

5-6. Propriétés et attributs

En plus de pouvoir modifier le contenu de la page, jQuery permet de modifier les valeurs des propriétés et attributs des balises. Avant d'entrer dans le détail des différentes méthodes disponibles, il est important de faire un rappel sur les notions de propriété et d'attributs ainsi que du lien existant entre ces valeurs. Ce rappel est d'autant plus important que depuis la version 1.6, jQuery utilise une gestion différenciée de ces éléments.

Les attributs sont des valeurs des balises HTML initialisées dans le code lui-même. Selon le type de document que vous créez (spécifié par la DTD, définition du type de document ou Document Type Definition), chaque balise peut ou non posséder certains attributs avec parfois des gammes de valeurs définies. Ces valeurs sont récupérables ou modifiables par script, notamment avec les méthodes DOM getAttribute() et setAttribute(). Par ailleurs, lorsque la page est créée, le moteur JavaScript transforme tous les éléments qu'il rencontre (et en particulier mais pas seulement les balises) en objets. Comme pour tout langage orienté objet, un objet JavaScript se définit par un ensemble de propriétés et de méthodes (nous avons régulièrement utilisé ce terme jusqu'à présent). Une propriété est comparable à une variable qui ne serait accessible que depuis l'objet et similairement, une méthode serait assimilable à une fonction que seul l'objet peut appeler. Pour chaque balise rencontrée, JavaScript lui associe donc, en fonction de sa nature, un ensemble de propriétés et de méthodes. En particulier, pour chaque type de balise, JavaScript lui reconnaît un certain nombre d'attributs possibles (qui ne sont pas nécessairement calqués sur les attributs autorisés par la DTD) et associe donc à l'objet correspondant des propriétés similaires à ces attributs (et ce, que les attributs soient déclarés dans le code ou non). Notez à titre d'exemple que l'attribut autocomplete, non conforme aux DTD émises par le W3C est reconnu par tous les navigateurs (cet attribut détermine si un champ de formulaire de type texte doit ou non vous proposer des suggestions liées à vos précédentes saisies). Ces attributs sont accessibles comme toute propriété d'objet par des syntaxes de la forme elementHTML.attribut. Malgré tout, si vous souhaitez modifier les valeurs associées, cela oblige de gérer à la fois les attributs et les propriétés. En réalité, pas tout à fait, car JavaScript n'est pas si sournois et offre une correspondance entre les deux qui fait que chaque modification de l'un est supposée entraîner la modification de l'autre. Je dis bien « supposée » car, bien entendu, ce n'est pas toujours le cas…

Un exemple classique est l'attribut value d'un champ texte (qui est pourtant un attribut autorisé). Dans ce cas, le comportement de la propriété et de l'attribut value est différent. Pour HTML, cet attribut correspond uniquement à la valeur à afficher au chargement de la page, sans se soucier que cette valeur devra, en toute logique, être modifiée. À l'inverse, pour JavaScript, la propriété value correspond à la valeur actuellement affichée, qui évoluera donc en même temps que le champ est modifié. Ainsi, si vous affectez une valeur avec la méthode set Attribute(), cette valeur modifiera l'attribut, mais pas la valeur affichée, inversement, si vous affectez une valeur par la propriété value, le texte du champ sera modifié, mais pas la valeur de l'attribut. Un autre cas classique est celui des attributs dits booléens (par exemple l'attribut checked d'une case à cocher). La norme XHTML vous oblige (contrairement à la norme HTML) à ce que tout attribut possède une valeur, on écrit donc habituellement checked=« checked », qui est la seule valeur autorisée pour cet attribut. Ceci dit, le seul élément déterminant l'état initial est la présence de l'attribut, pas sa valeur et vous pourriez aussi bien mettre checked=« unchecked », le comportement serait strictement identique (mais la page ne serait pas valide pour le W3C). De son coté, JavaScript associe à cet attribut une valeur booléenne, mais là aussi, si vous attribuez la valeur false à l'élément correspondant, cela aura pour effet de décocher la case, mais pas de supprimer l'attribut. Mais finalement, ceci a assez peu d'importance. En réalité, HTML et JavaScript gèrent ces propriétés et attributs en fonction des besoins usuels et il est assez peu fréquent d'avoir besoin du code HTML une fois la page chargée. Donc, ce qui intéresse JavaScript concernant les formulaires, ce sont les valeurs des champs qui seront envoyées à la soumission du formulaire et non leurs valeurs initiales (qui peuvent d'ailleurs être récupérées via la propriété defaultValue ou la méthode getAttribute().

En revanche, il existe de nombreux cas où la distinction entre propriété et attribut aura une importance majeure. En effet, vous pouvez avoir besoin d'utiliser des attributs personnels (pour autant que la validation du document vous importe peu ou que vous ayez créé votre propre DTD, ce qui est tout à fait autorisé) ou à l'inverse (et ce cas est très fréquent) de fixer des propriétés à vos éléments HTML. Dans ce cas, aucun lien n'existe entre le code HTML et les objets JavaScript, il est donc important de savoir si l'on souhaite utiliser un attribut ou une propriété. Ce sont ces cas qui seront gérés par jQuery et ils sont, encore une fois, très fréquents.

Avec jQuery, si vous souhaitez récupérer ou affecter un attribut à un élément (ou une collection d'éléments), vous utiliserez la méthode attr(), dans le cas d'une propriété, ce sera la méthode prop(). Quant aux valeurs des champs de formulaire, c'est la méthode val() qui permet soit de récupérer la valeur, soit de la définir.

Le code suivant permet de se rendre compte de la différence entre la méthode prop() (pour retrouver une propriété spécifique aux objets JavaScript de type élément HTML) et la méthode attr() (pour retrouver la valeur d'un attribut personnalisé), puis pour voir comment value, getAttribute(), prop() et attr() gèrent les champs de formulaire.

jquery-4-13.html
Sélectionnez
<!DOCTYPE HTML>
<html lang="fr">
  <head>
    <meta charset="iso-8859-1">
    <title>Attributs et propriétés</title>
        <style type="text/css">
            input{margin: 5px;}
        </style>
    <script type="text/javascript" src="http://ajax.googleapis.com/ 
            ajax/libs/jquery/1.6.1/jquery.min.js"></script>
    <script type="text/javascript">
            function valeur(){
                var elem = document.getElementById('test');
                var alerte = 'Propriété value : ' + elem.value + '\n';
                alerte += 'Attribut value : ' + elem. 
getAttribute('value') + '\n';
                alerte += 'Méthode prop() : ' + $(elem).prop('value') + '\n';
                alerte += 'Méthode attr() : ' + $(elem).attr('value') + '\n';
                alert(alerte);
            }
            $(function(){
                var alerte = 'Propriété tagName :
               ' + $('#test').attr('tagName') + ' / ';
                alerte += $('#test').prop('tagName') + '\n';
                alerte += 'Attribut perso :
 ' + $('#test').attr('perso') + ' / ';
                alerte += $('#test').prop('perso');
                alert(alerte);
            })
    </script>
  </head>
  <body>
        <input type="text" value="Test" id="test" perso= 
"Mon attribut" /><br />
        <button onclick="valeur()">Modifier le champ texte et
vérifiez les valeurs</button>
  </body>
</html>

Le premier message d'alerte affichera la figure 4-19.

Image non disponible
Figure 4.19. Propriétés et attributs

et si l'on modifie le champ et que l'on clique sur le bouton, on obtiendra la figure 4-20.

Image non disponible
Figure 4.20. Modification de champ texte

Le premier message montre que prop() arrive bien à récupérer une valeur de propriété JavaScript mais pas celle d'un attribut HTML et inversement pour attr(). Le second message montre que jQuery parvient bien à surpasser les lacunes de JavaScript concernant certains attributs HTML.

Les méthodes attr() et prop() fonctionnent de façon identique.

Ces lignes de code renverront la valeur de l'attribut ou de la propriété du premier élément retourné par $(element) :

 
Sélectionnez
$(element).attr(attribut);
$(element).prop(propriete);

Ce code attribuera à l'attribut ou la propriété de tous les éléments retournés par $(element) la valeur passée en second paramètre,

 
Sélectionnez
$(element).attr(attribut, valeur);
$(element).prop(propriete, valeur);

Ce code donnera aux attributs ou propriétés nomX de tous les éléments retournés par $(element) la valeur valeurX

 
Sélectionnez
$(element).attr({nom1: valeur1, nom2: valeur2, ..., nomN: valeurN});
$(element).prop({nom1: valeur1, nom2: valeur2, ..., nomN: valeurN});

Enfin :

 
Sélectionnez
$(element).attr(nom, function(rang, ancienneValeur){});
$(element).prop(nom, function(rang, ancienneValeur){});

affectera, pour chaque élément retourné par $(element), à l'attribut ou la propriété nom la valeur retournée par la fonction de rappel qui reçoit comme paramètres le rang de l'élément en cours et la valeur actuelle de nom pour cet élément.

Notez toutefois, que la méthode prop() est habituellement utilisée pour manipuler les propriétés natives des objets du DOM JavaScript, voire des valeurs primitives (de type booléennes, numériques ou textuelles), pour gérer des données plus complexes (tableaux, objets ou fonctions), il est préférable d'utiliser l'objet jQuery Data que nous verrons bientôt.

Si vous souhaitez supprimer un attribut ou une propriété, il faudra utiliser les méthodes removeAttr() et removeProp(). Ainsi :

 
Sélectionnez
$(element).removeAttr(nom);
$(element).removeProp(nom);

supprimera l'attribut ou la propriété nom pour tous les éléments retournés par $(element).

Nous ne reviendrons pas plus longuement sur l'utilisation de la méthode val(), qui permet, si aucun paramètre n'est passé, de récupérer la valeur du premier élément de l'objet jQuery en cours, sinon d'affecter à chaque élément de la collection la valeur passée en paramètre.

Une autre manipulation très fréquente concernant les propriétés des objets HTML est la récupération ou l'affectation de styles. En JavaScript, la récupération est particulièrement délicate, car elle dépend de la façon dont ces styles ont été déclarés.

Il existe deux façons distinctes d'attribuer des styles à des éléments. La première méthode consiste à intégrer un fichier CSS externe ou à définir les styles dans la balise <style>. La seconde consiste à utiliser les styles dits inline, c'est-à-dire déclarés dans l'attribut style de la balise. Selon le mode d'affectation, la récupération de la valeur ne se fera pas de la même façon en JavaScript. Autant les styles inline se retrouvent facilement à l'aide de la propriété style de chaque objet HTML, autant récupérer les styles déclarés dans des fichiers .css ou dans des balises <style> est plus complexe, car géré différemment selon le navigateur utilisé. D'autre part, les styles déclarés de façon externes déterminent le style par défaut de la propriété style de l'élément. Par exemple, une erreur courante est de masquer ou d'afficher un élément à l'aide de la propriété display de l'objet style de l'élément.

 
Sélectionnez
var elem = document.getElementById('element');
elem.style.display = elem.style.display == 'none' ? '' : 'none';

Avec cette syntaxe, on vérifie la valeur de display, si elle vaut 'none', on affecte une chaîne vide, sinon 'none'. L'utilité de passer une chaîne vide est de rétablir la valeur par défaut, ce qui est souvent très utile car certaines valeurs par défaut de display ne sont pas reconnues par les navigateurs (par exemple les valeurs des éléments de tableau). D'autre part, cela permet de créer une fonction générique quel que soit l'élément en question.

Le problème est que si une feuille de style (c'est-à-dire tous les styles qui ne sont pas inline) définit la valeur de display, alors c'est cette valeur qui devient celle par défaut, ce qui signifie que si elle est définie à 'none', alors le code ci-dessus cachera toujours l'élément. Or pour récupérer la valeur des styles externes, les méthodes ne sont pas les mêmes en fonction du navigateur.

D'autre part, certains styles et en premier lieu l'opacité, ne sont pas non plus gérés de façon identique par les navigateurs.

Enfin, la récupération de la dimension et de la position d'un élément est habituellement un casse-tête pour les développeurs.

La gestion des styles CSS est donc potentiellement très complexe, c'est pourquoi jQuery apporte des solutions simples pour gérer toutes les situations.

La méthode la plus fréquemment utilisée est la méthode css(), que nous avons déjà employée dans certains exemples.

Comme souvent avec jQuery, css() est à la fois un getter et un setter, c'est-à-dire qu'elle sert aussi bien à récupérer un style qu'à en affecter.

Le premier argument de css() sera toujours un sélecteur CSS (donc un nom de propriété). La notation des sélecteurs de style est différente en CSS et en JavaScript. Pour CSS, les noms composés de plusieurs mots prennent comme séparateur un tiret (« - »), mais pour JavaScript, le tiret correspond à l'opérateur moins, il faut donc transformer les noms de propriétés en notation dite camel case, à savoir chaque mot attaché, chacun à partir du deuxième commençant par une majuscule, par exemple la propriété de bordure CSS border-right-style deviendra borderRightStyle. Mais pas de souci pour jQuery, qui comprend les deux types de notation (ainsi d'ailleurs que certains noms particulier comme float en CSS qui ne peut être utilisé tel quel en JavaScript car c'est un mot réservé, jQuery comprendra donc aussi bien float que cssFloat ou styleFloat).

Si le sélecteur CSS est le seul paramètre, alors la méthode jQuery renverra la valeur de cette propriété pour le premier élément de la collection.

Dans ce cas, il convient d'être vigilant. Les valeurs numériques renvoyées ne sont pas toujours homogènes (du fait des différences entre navigateurs), notamment les valeurs des couleurs qui peuvent être retournées soit sous forme hexadécimales (#RRVVBB) soit sous forme RGB (rgb(XXX,XXX,XXX) . D'autre part, les propriétés raccourcies ne sont pas acceptées (par exemple, margin devra être décomposé en marginTop, marginRight, marginBottom et marginLeft).

Si un second paramètre est passé à la méthode, alors chaque élément de la sélection jQuery en cours se verra attribuer pour la propriété donnée la valeur du second paramètre.

D'autre part, comme nous l'avons déjà vu à de nombreuses reprises, il est aussi possible de passer en paramètre un objet de couples propriété / valeur (attention, les noms de propriétés doivent être entre guillemets pour pouvoir interpréter aussi bien la notation CSS que JavaScript) :

 
Sélectionnez
$(element).css({
    'prop1': 'valeur1',
    'prop2': 'valeur2',
    ...,
    'propn': 'valeurn',
});

Enfin, on peut passer en paramètre de css() une fonction de rappel à laquelle seront passés en paramètres le rang de l'élément en cours dans la sélection et la valeur actuelle du style, cette fonction devra renvoyer la valeur attendue pour le style.

 
Sélectionnez
$(element).css('propriete', function(rang, valeurActuelle){});

Si vous utilisez un objet pour affecter plusieurs propriétés d'un coup, la valeur associée à chaque propriété peut aussi être une fonction de rappel.

Notez aussi que la propriété opacity sera reconnue par jQuery qui retournera ou affectera l'opacité quel que soit le navigateur.

La méthode css() de jQuery reste relativement simple à utiliser. Les principaux pièges qui peuvent résulter de son utilisation sont en quasi totalité du ressort des connaissances en CSS et non en JavaScript ou jQuery, c'est pourquoi nous n'irons pas plus loin concernant cette méthode.

Le calcul des dimensions d'un élément est souvent assez compliqué (et périlleux) en JavaScript, jQuery dispose donc d'un ensemble de méthodes spécifiques pour récupérer ces valeurs à votre place. Voici un récapitulatif de ces différentes méthodes.

5-6-1. .height(), .width()

Sans paramètre, renvoie la hauteur ou la largeur du premier élément de l'objet en cours. Cette valeur, exprimée en pixels, est renvoyée sans l'unité (contrairement à .css('height') . La valeur retournée correspond uniquement à la zone de contenu et ne prend en compte ni les marges intérieures (padding), ni les bordures, ni les marges extérieures (margin).

Si un paramètre de type chaîne est passé, jQuery tentera de l'utiliser pour fixer la hauteur ou la largeur. Les formats attendus sont des valeurs numériques, éventuellement suivie de l'unité souhaitée (‘100', ‘50%', ‘5em'……)

Enfin, vous pouvez aussi passer en paramètre une fonction de rappel, qui recevra en argument le rang de l'élément à traiter dans la collection et sa dimension actuelle et qui renverra la nouvelle valeur à affecter.

5-6-2. .innerHeight(), .innerWidth()

Ces méthodes fonctionnent uniquement en tant que getter (récupération de la valeur) et ne prennent pas de paramètre. Elles renvoient un entier correspondant à la hauteur ou la largeur, en pixels, de la zone de contenu et des marges intérieures (padding) du premier élément de la collection en cours.

La valeur retournée correspond donc à la valeur de .height() (respectivement .width() augmentée de la valeur de la marge intérieure haut et bas (respectivement droite et gauche).

5-6-3. .outerHeight(), .outerWidth()

Utilisées uniquement comme getter. Ces méthodes retournent un entier correspondant à la valeur, en pixels, de la hauteur ou de la largeur de la zone de contenu, plus les marges intérieures et les bordures.

Il est aussi possible de passer un paramètre optionnel de type booléen, s'il vaut true, la valeur retournée comprendra aussi la valeur des marges extérieures.

L'exemple suivant montre les différents résultats renvoyés par ces méthodes.

jquery-4-14.html
Sélectionnez
<!DOCTYPE HTML>
<html lang="fr">
  <head>
    <meta charset="iso-8859-1">
    <title>Dimensions</title>
        <style type="text/css">
            #exemple{
                width: 500px;
                height: 200px;
                border: 5px solid black;
                margin: 10px;
                padding: 15px;
                background-color: yellow;
            }
        </style>
    <script type="text/javascript" src="http://ajax.googleapis.com/ 
              ajax/libs/jquery/1.6.1/jquery.min.js"></script>
    <script type="text/javascript">
      $(function(){
                var elem = $('#exemple'),
                    br = '<br />',
                    resultat = '';
                resultat += 'Valeurs de height() et width() : ';
                resultat += elem.height() + ' / ' + elem.width() + br;
                resultat += 'Valeurs de innerHeight() et innerWidth() : ';
                resultat += elem.innerHeight() + ' / ' +  
elem.innerWidth() + br;
                resultat += 'Valeurs de outerHeight() et outerWidth() : ';
                resultat += elem.outerHeight() + ' / ' +  
elem.outerWidth() + br;
                resultat += 'Valeurs de outerHeight(true) et  
          outerWidth(true) : ';
                resultat += elem.outerHeight(true) + ' / '  
+ elem.outerWidth(true) + br + br;
                resultat += 'Valeurs de css(\'height\') et css(\'width\') : ';
                resultat += elem.css('height') + ' / ' +  
elem.css('width') + br;
                $('#resultats').html(resultat);
            });
    </script>
  </head>
  <body>
    <div id="exemple">
Styles CSS :<br />
            <pre>
    width: 500px;
    height: 200px;
    border: 5px solid black;
    margin: 10px;
    padding: 15px;
    background-color: yellow;
            </pre>
    </div>
        <div id="resultats"></div>
  </body>
</html>

Le résultat affiché est illustré en figure 4-21.

Image non disponible
Figure 4.21. Dimensions d'un élément

5-6-4. .offset()

La méthode offset() utilisée sans paramètre permet de récupérer les coordonnées du premier élément de l'objet jQuery en cours par rapport au coin supérieur gauche du document. Le résultat retourné sera un objet au format :

 
Sélectionnez
{
    top: XXX,
    left: XXX
}

Les coordonnées peuvent donc être utilisées de la façon suivante :

 
Sélectionnez
var coords = $(element).offset();
coords.top;
coords.left;

Il est important de garder à l'esprit que les valeurs retournées ne prennent en compte ni les marges intérieures et extérieures ni les bordures attribuées à la balise <body>. D'autre part, cette méthode ne fonctionne pas sur les éléments cachés.

La méthode offset() permet aussi de fixer les coordonnées de tous les éléments de l'objet jQuery en cours. Pour cela, vous devrez lui passer en paramètre un objet dont les propriétés top et left correspondent à celles que vous souhaitez attribuer.

Comme souvent, il est aussi possible de passer en paramètre une fonction de rappel qui recevra en paramètres le rang et les coordonnées actuelles de l'élément en cours dans la collection jQuery et qui devra renvoyer l'objet correspondant aux nouvelles valeurs à affecter.

5-6-5. .position()

Cette méthode ne fonctionne qu'en tant que getter.

La méthode position() fonctionne de façon similaire à offset() mais renvoie les coordonnées du premier élément de l'objet jQuery en cours par rapport à son ancêtre positionné le plus proche (pour rappel, un ancêtre au sens du DOM correspond à une balise contenant celle de référence, quel que soit le niveau d'imbrication). Un élément positionné est un élément dont la propriété CSS position vaut relative, absolute ou fixed.

5-6-6. .scrollLeft(), .scrollTop()

Les méthodes scrollLeft() et scrollTop() permettent de récupérer la valeur en pixels de la partie masquée par l'utilisation des ascenseurs du premier élément de l'objet jQuery en cours. S'il n'y a pas d'ascenseur pour l'axe donné, la méthode associée renverra 0.

Si vous passez un entier en paramètre (attention, cette méthode n'autorise pas les chaînes de caractères, sauf si elles sont uniquement numériques), alors tous les éléments de la collection en cours se déplaceront, si possible, à cette valeur.

5-7. L'objet Data

L'objet Data de jQuery permet d'associer n'importe quel type de données à un ensemble d'éléments jQuery. L'objet Data fonctionne de façon assez similaire à la méthode prop() mais de façon plus étendue.

L'utilisation de l'objet Data pour des données complexes est recommandée car elle permet d'éviter les références croisées à des données, ce qui est susceptible d'entraîner des fuites de mémoire.

C'est cet objet qui permet, entre autre, d'associer les événements jQuery aux différents éléments.

Cet objet dispose de différentes méthodes, dont la principale data(). Cette méthode permet de récupérer ou d'affecter les informations voulues.

Ces lignes permettent de récupérer la valeur de nom associée à element ou au premier élément de l'objet $(element) :

 
Sélectionnez
jQuery.data(element, 'nom');
$(element). data('nom');

Si nom n'est pas passé en paramètre, alors data() renverra l'objet Data associé à l'élément en en créant un vide si aucun objet Data n'existe encore pour cet élément.

À l'inverse :

 
Sélectionnez
jQuery.data(element, 'nom', valeur);
$(element). data('nom', valeur);

permettent d'associer à nom la valeur valeur pour element ou pour l'ensemble des éléments retournés par $(element). Alors qu'avec prop(), il est recommandé de n'associer que des valeurs simples (booléens, chiffres ou textes), valeur peut ici prendre n'importe quel type de valeur.

Il est aussi possible de passer en paramètre un objet de couples nom / valeur, ces couples seront ajoutés à l'objet Data de l'élément en question si nom n'existe pas encore, sinon, la valeur de nom sera modifiée.

Pour supprimer des valeurs associées à un objet, vous devrez utiliser la méthode removeData().

Si vous passez un nom de propriété à cette méthode, la valeur associée sera supprimée de l'objet Data pour les éléments de l'objet jQuery en cours. Si aucun paramètre n'est passé, alors toutes les données seront supprimées.

La méthode hasData() de l'objet jQuery permet de déterminer si un élément possède des données associées, cette méthode retourne un booléen. Contrairement à jQuery.data(), elle n'affecte pas d'objet vide à l'élément s'il n'y a pas d'objet Data associé à l'élément.

 
Sélectionnez
var elem = $('#exemple');
jQuery.hasData(elem);    // false
jQuery.data(elem);    // {}
jQuery.hasData(elem);    // true
jQuery.removeData(elem);
jQuery.hasData(elem);    // false

5-8. Gestion des noms de classe

Plutôt que de modifier les styles CSS de certains éléments ou pour pouvoir intégrer ou non des éléments dans une collection en fonction de certains critères, il est souvent utile de manipuler l'attribut class, ce qui n'est pas toujours simple étant donné qu'un même élément peut posséder plusieurs noms de classes différents. Il existe donc plusieurs méthodes jQuery pour manipuler les classes d'un élément.

Le code :

 
Sélectionnez
$(element).addClass('nom[ nom2 nom3 ...]');

permet d'ajouter un ou plusieurs noms de classe à la collection d'éléments. Le paramètre nom est une chaîne, contenant les différents noms à attribuer séparés par des espaces.

Le code :

 
Sélectionnez
$(element).addClass(function(rang, nomActuel){});

permet d'ajouter aux classes de chaque élément le résultat renvoyé par la fonction.

De façon similaire, il est possible de supprimer des noms de classe avec la méthode removeClass() :

 
Sélectionnez
$(element).removeClass('nom[ nom2 nom3 ...]');
$(element).removeClass(function(rang, nomActuel){});

Par exemple, pour supprimer toutes les classes d'une balise, vous pourrez utiliser le code suivant :

 
Sélectionnez
$('div').removeClass(function(i, nom){
    return nom;
});

Ceci dit, dans ce genre de situation, il reste préférable d'utiliser la méthode attr() pour affecter une chaîne vide :

 
Sélectionnez
$('div').attr('class', '');

Une utilisation couramment utilisée est de faire alterner un nom de classe pour une action définie, dans ce cas, vous pourrez utiliser la méthode toggleClass() :

 
Sélectionnez
$(element).toggleClass('nom[ nom2 nom3 ...]');

Cette méthode appliquera l'une des méthodes addClass() ou removeClass() pour chaque nom présent en paramètre en fonction de la présence ou non de cette classe. Il ne s'agit donc pas de faire alterner entre deux noms de classe différents, mais d'ajouter la classe si elle n'est pas définie pour l'élément, la rajouter sinon. L'exemple suivant permet d'alterner entre deux noms de classe :

 
Sélectionnez
<!DOCTYPE HTML>
<html lang="fr">
  <head>
    <meta charset="iso-8859-1">
    <title>Méthode toggleClass()</title>
        <style type="text/css">
            #exemple{
                width: 500px;
                height: 200px;
                border: 5px solid black;
                margin: 10px;
                padding: 15px;
                background-color: yellow;
            }
        </style>
    <script type="text/javascript" src="http://ajax.googleapis.com/ 
            ajax/libs/jquery/1.6.1/jquery.min.js"></script>
    <script type="text/javascript">
      $(function(){
                $('#exemple').click(function(){
                    $(this).toggleClass('classe1 classe2');
                    $('#resultat').html($(this).attr('class'));
                });
            });
    </script>
  </head>
  <body>
    <div id="exemple" class="classe1">
    </div>
        <div>Nom de classe : <span id="resultat">classe1</span></div>
  </body>
</html>

Alterner entre deux noms de classe a pour but que l'élément doit toujours avoir uniquement l'un des deux noms de classe. On la définit donc au départ dans le code HTML, puis au clic sur la <div>, on utilise toggleClass() sur les deux noms souhaités, ainsi, celui déjà présent sera retiré et l'autre ajouté.

Comme souvent, toggleClass() peut aussi recevoir en paramètre une fonction de rappel

 
Sélectionnez
$(element).toggleClass(function(rang, nomActuel){});

Dont les arguments sont le rang de l'élément en cours et ses noms de classe actuels, cette fonction devant renvoyer les noms de classe à alterner.

Enfin, quel que soit le premier paramètre envoyé (chaîne ou fonction), il est possible d'en passer un second, de type booléen, qui forcera soit l'ajout soit le retrait des noms de classe. Avec ce paramètre, toggleClass(nom, true) est équivalent à addClass(nom) et toggleClass(nom, false) à removeClass(nom). L'intérêt de toggleClass() dans ce cas est que le second paramètre peut être une variable.

Il est aussi possible de tester la présence d'un nom de classe avec la méthode hasClass() :

 
Sélectionnez
$(element).hasClass('nom[ nom2 nom3 ...]');

hasClass() renverra true si au moins un des éléments renvoyé par $(element) possède l'ensemble des noms de classe passés en paramètre, false si aucun ne les possède tous.


précédentsommairesuivant

Licence Creative Commons
Le contenu de cet article est rédigé par Didier Mouronval et est mis à disposition selon les termes de la Licence Creative Commons Attribution - Partage dans les Mêmes Conditions 3.0 non transposé.
Les logos Developpez.com, en-tête, pied de page, css, et look & feel de l'article sont Copyright © 2013 Developpez.com.