Introduction à jQuery - 1 Un peu de JavaScript - Ressources pour IPI/CGI promo 2017

La page est créée Baptiste Gilbert
 
CONTINUER À LIRE
Cours jQuery

Introduction à jQuery

1 Un peu de JavaScript

1.1 Bref historique

Pour plus de détails, voir la présentation en PDF.
JavaScript a été introduit dans Netscape Navigator en 1995. Malgré le nom,
JavaScript n’a rien à voir avec Java. Simplement, Java était très en vogue à
cette époque. Netscape a voulu exploiter la popularité de Java et a baptisé son
langage JavaScript pour des raisons de marketing.
L’apparition de JavaScript coïncide avec d’autres évolutions notables du web :
  • l’apparition de langages tels que Perl 5, Python, PHP, permettant de
    générer des pages web dynamiquement, par exemple à partir d’une base
    de données.
  • l’introduction d’élements de présentation dans le HTML (tables) et des
    feuilles de style.

1.2 À quoi sert JavaScript

JavaScript permet d’ajouter de l’interaction dans une page web. Par exemple, le
bouton HTML ci-dessous permet de revenir à la page précédente :
Précédent
Dans le navigateur web, JavaScript peut manipuler des éléments de la page en
cours, accéder à l’historique de navigation de la fenêtre courante, programmer
des actions à effectuer à l’issue d’un intervalle de temps défini (setTimeout())
ou à intervalles réguliers (setInterval()).
Il est important de distinguer :
  • d’une part, le langage lui-même: on peut très bien imaginer que JavaScript
    fonctionne ailleurs que dans un navigateur web. Ce n’était pas possible
    à l’origine, mais depuis quelques années Node.js permet d’exécuter du
    JavaScript en dehors d’un navigateur.
  • d’autre part, les “fonctions” accessibles par ce langage, dans un certain
    environnement. Par exemple, l’API DOM, intégrée par défaut dans les nav-
    igateurs, est un ensemble de fonctions JavaScript, permettant de manipuler
    le document HTML. Mais elle ne fait pas partie du langage proprement dit.
    Ainsi elle n’est pas disponible sous Node.js. Inversement Node.js dispose
    de fonctions pour manipuler des fichiers ou des bases de données comme

                                       1
MySQL, qu’on ne pourrait jamais avoir dans un navigateur. La raison
     pour ce dernier point est que le navigateur doit protéger l’utilisateur contre
     des programmes malicieux. Imaginez : vous visitez un site apparemment
     inoffensif. Celui-ci contient un script JavaScript, qui se télecharge de façon
     invisible pour vous. S’il pouvait accéder aux fichiers de votre ordinateur, il
     pourrait (au hasard) essayer de trouver votre RIB, votre carnet d’adresses,
     les mots de passe stockés dans votre navigateur, etc. C’est pourquoi c’est
     strictement impossible. On dit que le JavaScript dans le navigateur est
     “sandboxé” (en franglais dans le texte).

1.3 (In)compatibilité entre les navigateurs

Beaucoup de choses en informatique sont standardisées, normalisées, et c’est
heureux. Par exemple le protocole HTTP (permettant l’échange entre un serveur
web et un navigateur) est strictement décrit dans une spécification (à vos
risques et périls si vous vous attaquez à une lecture de ce calibre !).
De même les langages sont standardisés. HTML et CSS le sont, JavaScript aussi,
pour chacune de leurs versions (ici la spécification d’une des premières versions
de JavaScript).
Là où le bât blesse, c’est que certaines spécifications, faute d’être assez précises,
peuvent laisser une petite part d’interprétation à ceux qui s’en servent. JavaScript
a connu ce problème, ou plus précisément, les API associées. Cela s’est en
partie arrangé depuis, heureusement. Mais par exemple, certaines fonctions de
manipulation du DOM n’ont jamais été disponibles sous Internet Explorer. Ce
dernier avait aussi un système différent des autres pour effectuer des requêtes
AJAX vers un serveur.

1.4 Apparition de librairies pour “lisser” les incompatibilités

Les problèmes de compatibilité entre navigateurs ont encouragé des développeurs
indépendants à créer des librairies pour y pallier, et ainsi faciliter le travail des
programmeurs d’applications JavaScript. Parmi elles, jQuery, créée initialement
par un certain John Resig.
Outre le fait de lisser les différences entre les navigateurs, jQuery fournit des
fonctions permettant de facilement :
   • manipuler la page web : agir sur les élements HTML et leurs styles, ajouter
     ou retirer facilement des éléments, etc.
   • animer des éléments : par exemple pour construire un carousel d’images,
     avec différentes transitions possibles entre chaque (par fade in / fade out,
     par défilement, etc.)
   • effectuer des requêtes AJAX

                                         2
De plus jQuery est extensible : il permet facilement d’ajouter d’autres fonctions
à celles fournies en standard.
Enfin, suivant le leitmotiv affiché sur sa page d’accueil, jQuery permet d’écrire
moins, faire plus. Les programmes écrits avec jQuery que les équivalents écrits
avec l’API DOM native.

2 Bases de jQuery - Les sélecteurs

2.1 L’objet jQuery

Note pour les étudiants IPI/CGI : lors de notre 1ère session, j’ai commencé
par les sélecteurs sans employer explicitement le terme “objet jQuery”.
jQuery permet de manipuler des ensembles d’éléments HTML, via des fonctions
à la syntaxe simple telles que :
   • .html() pour lire ou modifier le contenu des éléments ciblés
   • .css() pour leur attribuer des styles ou les consulter
   • .show(), .hide(), .toggle() pour respectivement les rendre visibles,
     invisibles, ou inverser leur visibilité par rapport à l’état actuel (en modifiant
     leur propriété CSS display et non visibility).
Pour pouvoir appeler ces fonctions sur un élément ou un ensemble d’éléments,
jQuery les enveloppe (wrap) dans une structure de données qui lui est propre :
l’objet jQuery. Pour obtenir un objet jQuery, on fait appel à un sélecteur de
la forme $(...). L’objet jQuery contient des références aux éléments “natifs”
qu’on obtiendrait normalement avec l’API DOM.
La facilité et la puissance de jQuery pour manipuler le DOM viennent de sa
conception :
   • les sélecteurs ont une syntaxe largement calquée sur les sélecteurs CSS.
   • les fonctions appelées sur l’objet jQuery ont la même syntaxe, que celui-ci
     enveloppe un seul ou plusieurs éléments du DOM (contrairement à l’API
     DOM qui oblige à parcourir soi-même des ensembles d’éléments par des
     boucles).
   • on peut ajouter des éléments au document par différentes méthodes.
Un premier exemple de création d’un objet jQuery via un sélecteur. Le sélecteur
suivant enveloppe tous les liens de la page où s’exécute le script :
$('a')
Il est intéressant de se pencher sur ce que contient cet objet, ici dans l’onglet
“Console” des outils de développement de Google Chrome.
Vous pouvez le faire vous-même, en ouvrant n’importe quelle page comportant
des liens, et intégrant jQuery. . . comme celle-ci ! (pour ceux qui consultent le
cours en HTML). Cliquez avec le bouton droit dans cette page, et choisissez

                                          3
“Inspecter”, ou ouvrez simplement les outils développeur. Puis allez dans l’onglet
“console” et faites les manipulations ci-dessous.

                                    Figure 1:

On constate la présence de propriétés : 0, 1, 2, etc. qui ressemblent à des indices
dans un tableau (vous en aurez plus sur cette page, mon exemple en comportait
3). À chacune est associée un a qui est un objet puisqu’il est précédé d’une
flèche (ou de Object dans Firefox). On peut donc l’examiner en cliquant sur la
flèche (ci-dessous un extrait).
Sans forcément s’attarder sur toutes les propriétes de l’objet, on peut constater
la présence de propriétés qui nous indiquent que c’est un élément du DOM, telles
que :
   • attributes : la liste des attributs qui ont été mis sur la balise HTML.
   • childNodes: les éventuels noeuds enfants de l’élément (ici un noeud de
     type text, le contenu textuel du lien, situé entre les balises ouvrante et
     fermante).
   • id: l’id de l’élément, sous forme d’une chaîne de caractères qui peut être
     vide.
En plus des éléments, l’objet jQuery contient une propriété length qui contient
le nombre d’éléments.
Petite astuce, quand vous concevez un programme avec jQuery, et que
“bizarrement” rien ne marche comme vous voulez, vous pouvez faire un
console.log() de l’objet que vous avez créé avec un sélecteur. Si vous trouvez
length valant 0 et aucun élément, vous avez pu faire une erreur dans votre
sélecteur. . .
On peut comparer le contenu de l’objet jQuery avec l’équivalent renvoyé par le
DOM :
À première vue, cet objet (qui est une collection d’éléments) ressemble beaucoup
à l’objet jQuery, exception faite de la propriété prevObject présente dans l’objet
jQuery. Si on examine les contenus des éléments dans cette structure, ce sont les
mêmes que dans l’objet jQuery.
Mais attention, souvenez-vous qu’en JavaScript, comme dans de nombreux

                                        4
Figure 2:

    5
Figure 3:

langages dits “objet”, un objet possède des propriétés et des méthodes (fonctions).
Pour voir les fonctions disponibles sur l’objet jQuery et sur l’objet DOM, toujours
dans la console, vous pouvez cliquer sur la propriété __proto__ que chacun
d’eux possède. Cela affiche la liste des fonctions que vous pouvez appeler sur
l’objet, et on peut voir que ce ne sont pas les mêmes.
Dernier point pour conclure cette section relativement complexe : malgré leurs
propriétés numérotées 0, 1, 2, etc., ni l’objet jQuery, ni le résultat d’une
fonction DOM getElementsBy***Name, ne sont des tableaux à proprement
parler ! Ce sont des structures proches des tableaux, mais on ne peut pas utiliser
des méthodes de Array dessus. Par contre, dans les deux cas, il reste possible
de faire des boucles for ou while pour parcourir leurs éléments, comme on le
ferait avec un tableau.
Note pour les CGI : ce dernier point sera probablement plus clair quand vous
aurez étudié plus en détail le JavaScript et ses différents types de données, dont
les tableaux.

2.2 Les sélecteurs de base

jQuery fournit d’abord trois types de sélecteurs équivalents aux fonctions du
DOM permettant de récupérer un élément dans le document. Plus un autre
pour rendre accessibles à un élément DOM les fonctions de jQuery.
La documentation officielle de jQuery fournit une page dédiée aux sélecteurs.

2.2.1 Par ID
Le sélecteur commençant par # suivi d’un id permet de cibler l’élément avec
cet id. Il cible donc forcément un élément dans la page, l’id étant unique (sauf
erreur de l’auteur du HTML).
Voici un paragraphe HTML :
J'aime les pains au chocolat.

                                        6
Et ci-dessous, comment remplacer son contenu en JavaScript (DOM vs. jQuery).
// DOM
var element = document.getElementById('texte-polemique');
element.innerHTML = "Je n'aime pas les pains au chocolat.";

// jQuery
$('#texte-polemique').html("J'aime les chocolatines !");
À noter :
  • ce simple exemple (pour la partie DOM) suffit pour constater des différences
    entre les (vieux) navigateurs : les anciennes versions de Internet Explorer
    ne supportaient pas la modification directe du contenu d’un élément via
    innerHTML.
  • comme indiqué en fin de section 2.1 “l’objet jQuery”, si l’id indiqué dans
    le sélecteur ne correspond à rien d’existant dans la page, l’objet jQuery
    retourné sera vide. C’est évidemment valable aussi pour les sélecteurs que
    nous allons voir ensuite.
  • jQuery se sert, en interne, des fonctions du DOM pour aller chercher des
    éléments.

2.2.2 Par classe
Un sélecteur commençant par . suivi d’un nom de classe CSS permet de cibler
tous les éléments comportant cette classe.

     Apple iPhone X
     1329,00
     Enlever
  
     Samsung Galaxy S8
     799,00
     Enlever
  
Et comment remplacer le texte des liens (par exemple pour traduire les liens en
anglais):
// DOM: noter le pluriel
var links = document.getElementByClassName('link-remove');
for(var i = 0 ; i < links.length ; i++) {
  links[i].innerHTML = 'Remove';
}

                                      7
// jQuery
$('.link-remove').html('Remove');

2.2.3 Par nom de balise (tag)
Un sélecteur contenant un nom de balise HTML englobe tous les éléments de ce
type.
Apple iPhone X
Samsung Galaxy S8
Sony Xperia XZ
a.link-product {
  color: #55f;
}
// DOM
var links = document.getElementByTagName('a');
for(var i = 0 ; i < links.length ; i++) {
  links[i].classList = 'link-product';
}

$('a').addClass('link-product');

2.3 Autres façons de construire un objet jQuery

2.3.1 À partir d’un élement ou d’une collection d’élements
On peut passer en paramètre à $(...), au lieu d’un sélecteur CSS, un élément
ou une collection.
// Un élément
var pageTitleElem = document.getElementById('title');
var pageTitleJquery = $(pageTitleElem);

// Une collection
var sectionTitleElems = document.getElementsByClassName('section-title');
var sectionTitlesjQuery = $(sectionTitleElems);

À partir de code HTML
On peut passer une chaîne de caractères contenant du HTML en paramètre :
var numberedList = $('OneTwo');

                                     8
2.4 Les sélecteurs - suite

2.4.1 Sélecteur par attribut
Le sélecteur suivant sélectionne tous les input de type text (excluant donc les
autres types comme hidden, submit, etc.). Dans cet exemple on leur donne une
bordure grise avec des coins arrondis :
$('input[type="text"]').css({
  border: '1px solid none',
  'border-radius': '4px'
});
Note : vous pouvez vous demander pourquoi, dans l’objet passé à .css(), la
propriété border-radius est indiquée avec des guillemets, et pas border. C’est
lié au langage JavaScript : le tiret - n’est pas valide dans un nom de propriété
(contrairement au _ qui l’est). Sauf si on prend la précaution d’entourer la
propriété avec des guillemets (simples ou doubles).

2.4.2 Filtres ou pseudo-sélecteurs
Les filtres ou pseudo-sélecteurs, contrairement à tous ceux vus jusqu’ici (et à
ceux des deux sections suivantes), sont particuliers, dans le sens où ils diffèrent
de la syntaxe CSS.

2.4.2.1 Filtres par position
Ces filtres permettent de restreindre une sélection, en fonction de la position des
éléments de la sélection.
   • :first et :last permettent de sélectionner respectivement le premier et
     le dernier élément d’un ensemble
   • :even et :odd permettent de sélectionner respectivement les éléments
     d’indices pairs et impairs d’un emsemble. Attention, comme on compte à
     partir de 0, :even va matcher les éléments 0, 2, etc. (donc le premier, le
     troisième, etc.), ce qui n’est pas forcément intuitif.
   • :eq(n) permet de sélectionner l’élément se trouvant à la position n dans
     un ensemble (en comptant à partir de zéro comme très souvent en pro-
     grammation)
A revoir

        1ère ligne, 1ère cellule
        1ère ligne, 2ème cellule
    
                                        9
2ème     ligne, 1ère cellule
         2ème     ligne, 2ème cellule
    
         3ème     ligne, 1ère cellule
         3ème     ligne, 2ème cellule
    
         4ème     ligne, 1ère cellule
         4ème     ligne, 2ème cellule
    
2.4.2.2 Pseudo-sélecteurs par type
Ces pseudo-sélecteurs permettent de cibler des champs de saisie dans des for-
mulaires. Ce sont parfois de simples raccourcis par rapport aux sélecteurs par
attributs vus précédemment.
   • :checkbox sélectionne les input de type checkbox
   • :radio sélectionne les input de type radio
   • :text sélectionne les input de type text
Voir l’exemple et la documentation jQuery pour la liste complète

2.4.2.3 Pseudo-sélecteurs par état
Si les sélecteurs CSS permettent de cibler des éléments selon leur balise ou leurs
attributs, ils ne permettent pas de le faire suivant un certain état, tel que “coché”
(checked) pour un input[type="checkbox"] ou input[type="radio"], ou
encore “sélectionné” (selected) pour un select. D’où ces filtres dans jQuery :
   • :checked pour cibler des checkboxes ou boutons radio cochés.
   • :selected pour cibler la ou les option(s) sélectionnée(s) dans un select.

2.4.2.4 Filtres de contenu
Voir la référence
Le filtre :contains() permet de cibler des éléments contenant un certain texte.
Comme d’habitude on peut chaîner ce sélecteur avec d’autres. Dans cet exemple,
seuls les items de la liste de films de science-fiction sont ciblés par le sélecteur.

  Blade Runner
  Interstellar
  Star Trek
  Star Wars

                                         10
War of the Worlds

  Forrest Gump
  Lone Star
  The Star

$("#liste-films-sf li:contains('Star')")
.css('text-decoration', 'underline');
Le filtre :empty() permet de cibler des éléments vides (sans contenu d’aucune
sorte, que ce soit du texte ou des éléments enfants).

  Enfant non vide
  
$("div:empty").css('background', 'red');
Le filtre :has(selecteur) permet de cibler des éléments contenant un élément
matchant le sélecteur donné en paramètre. C’est bel et bien différent d’utiliser
seulement le sélecteur.

  Souligné
  Souligné + gras
  Italique + gras
  Italique + souligné

$("#demo-filtre-has div:has('.gras')").css('background', '#ccc');

2.4.3 Sélections “cumulées”

L’utilisation de la virgule dans les sélecteurs permet de sélectionner plusieurs
choses en même temps. On peut inclure des sélecteurs de types différents (par
balise, id, classe, attribut, pseudo-sélecteurs. . . ).
$('a,button')                   // tous les liens ET boutons
$('#titre-page,.titre-section') // l'élément avec id titre-page +
                                // ceux avec classe titre-section
$('input[type="email"],:text') // les input de type email ET texte

                                      11
2.4.4 Sélecteurs CSS composés

L’utilisation de sélecteurs séparés par des espaces permet de restreindre de plus
en plus la sélection
$('div h2')                //   les h2 se trouvant à l'intérieur
                           //   d'une div, pas les autres
$('#main .item')           //   les éléments avec la classe item,
                           //   à l'intérieur de #main
$('#main div.item')        //   proche du précédent, mais restreint
                           //   aux div uniquement
$('#main div .item')       //   DIFFERENT : éléments .item situés
                           //   DANS une div DANS #main
Note pour les CGI Les deux dernières lignes de l’exemple précédent me
permettent de reprendre une question posée pendant une de nos sessions :
l’espace est-il important ? La réponse est définitivement oui.
Quand vous voyez un sélecteur avec des espaces, lisez-le de droite à gauche: ici
pour la 4ème ligne, on prend les .item à l’intérieur d’une div à l’intérieur de
#main.
Pour préciser la différence entre les 3ème et 4ème ligne : dans la 3ème, on cible
les div avec classe item. Dans la 4ème, on cible les éléments avec classe item
dans une div.
Comme il est indiqué dans la documentation jQuery, il est préférable d’utiliser
“le filtre le plus court qui fasse le job” : par exemple préférez #myTable
th.special à #myTable thead tr th.special si le premier vous permet
d’obtenir l’ensemble d’éléments que vous ciblez.

2.4.5 Plus de précision : cibler un élément enfant

Il arrive qu’on ait besoin de plus de précision dans les sélecteurs. Par exemple,
les pages web comportent souvent un grand nombre de div imbriquées. Le
caractère > permet de choisir un élément qui est un enfant direct d’un autre.

  Paragraphe 1
  
    Paragraphe 2
    Paragraphe 3
    Div très imbriquée
  
    Paragraphe 4
    Paragraphe 5
  
                                       12
$('#main > div')    // div DIRECTEMENT sous #main
.addClass('gray')
$('.section > p')   // paragraphes 2 et 4 seulement
.addClass('blue')
$('.section > div') // div contenant les paragraphes 2 et 4
.addClass('red')

2.4.6 Plus de précision : cibler un élément adjacent

Un autre type de sélecteur permet de cibler un élément adjacent à un autre :

  Paragraphe 1
  Paragraphe 2
  Paragraphe 3
  Div
  Paragraphe 4

$('p + p') // paragraphes précédés directement par un autre
.addClass('red')

2.4.6 Conclusion sur les sélecteurs jQuery et CSS

La plupart des sélecteurs jQuery - exceptés les pseudo-sélecteurs - utilise la
syntaxe CSS. C’est le cas pour le suivant par exemple :
$('.tabs a.active,nav a.active').css('font-weight', 'bold');
Dans le cas précédent cela ne saute pas forcément aux yeux, probablement parce
qu’on n’y voit pas les accolades auxquelles on est habitué en CSS:
.tabs a.active,
nav a.active {
  color: #5db;
}
 Pourtant c’est bien la même syntaxe. Que ce soit le chaînage de sélecteurs
“inclusif” - en les séparant par des virgules, ou “restrictif” - en les séparant par
 des espaces, les deux syntaxes existent en jQuery comme en CSS. L’opérateur
‘>’ permettant de spécifier un enfant direct existe de même dans les deux cas.

                                        13
3 La manipulation du DOM

Pour rappel, le DOM ou Document Object Model, est l’arborescence de noeuds
(éléments) que le navigateur construit à partir du HTML qu’il a interprété.
jQuery permet de manipuler les éléments et leurs attributs avec une grande
facilité. Il permet d’en ajouter, d’en supprimer, d’en déplacer, etc. De nombreuses
fonctions sont fournies, certaines ayant des fonctionnalités similaires entre elles,
avec todut de même des différences subtiles.

3.1 Insertion et manipulation à l’intérieur d’un élément

La référence pour les fonctions décrites ci-dessous est disponible ici.
Une des premières fonctions que nous avons vues (exemple de la section 2.2.1
sélection par ID) est .html(), permettant de lire ou d’écrire le contenu HTML
d’un élément.
Très important car la façon d’utiliser cette fonction est assez représentative
d’une façon de faire omniprésente dans jQuery. Cette fonction fait partie des
nombreuses qui font office à la fois de “getter” (terme savant pour désigner une
fonction qui lit une propriété d’un objet) et de “setter” (fonction qui écrit une
propriété). L’usage dépend du nombre d’arguments :
// la variable contenuHtml récupère le contenu HTML de l'élément:
var contenuHtml = $('#un-element').html();
// le contenu de l'élément est complètement remplacé:
$('#un-element').html('Un titre de niveau 1');
Une fonction semblable est .text(), qui récupère seulement le contenu textuel
d’un élément, oubliant donc les balises.
// Suite de l'exemple précédent
// contenuTexte contiendra la chaîne "Un titre de niveau 1"
var contenuTexte = $('#un-element').text()
Les fonctions .append() et .appendTo permettent d’ajouter du contenu à la fin
de l’élément ciblé, soit après le dernier enfant actuel de cet élément. Si on prend
le HTML suivant :

  1er paragraphe

Et qu’on effectue les appels suivants :
$('#cible').append('2ème paragraphe');
$('3ème paragraphe').appendTo('#cible');
On aura après ces deux appels :

                                          14
1er paragraphe
  2ème paragraphe
  3ème paragraphe

Les fonctions ont quasiment la même fonctionnalité, mais notez que dans le
JavaScript, les deux syntaxes diffèrent par l’ordre de la cible et du contenu à
y ajouter. Personnellement la 1ère syntaxe me paraît plus intuitive, mais la
seconde à un gros avantage, du moins si on souhaite aussitôt manipuler l’élément
ajouté : on peut assigner son résultat à une variable, ou même directement
chaîner des appels de fonctions jQuery à sa suite :
var p = $('4ème paragraphe').appendTo('#cible');
p.css({ color: '#eae', backgroundColor: '#ddd' });
$('5ème paragraphe')
.appendTo('#cible').css('color', '#aee');
Les fonctions .prepend() et .prependTo permettent d’ajouter du contenu au
début de l’élément ciblé, soit avant le premier enfant actuel de cet élément.
Comme leur nom l’indique, elles ont une fonctionnalité semblable, avec la même
différence qu’entre .append() et .appendTo : .prependTo renvoie l’objet jQuery
enveloppant le(s) élément(s) HTML qu’on a ajouté.

3.2 Insertion autour d’un élément

Référence sur ce sujet ici
Plusieurs fonctions permettent d’envelopper un ou plusieurs élément(s) avec
du contenu HTML (attention, pas au sens d’envelopper où on l’entendait avec
l’objet jQuery qui “enveloppe” un ou plusieurs élément(s) du DOM).
La fonction .wrap() permet d’envelopper chaque élément d’un objet jQuery
avec du HTML. Avec le HTML suivant :

  Hello
  Goodbye

Et l’appel suivant :
$('.niveau-2').wrap('');
On obtiendra ceci :

    Hello
  
                                      15
Goodbye
  
La fonction .unwrap() fait l’inverse : elle supprime le parent de chaque élément
de l’objet jQuery sur lequel elle est appelée. Elle prend, en argument optionnel,
un sélecteur qui permet de ne supprimer le parent que s’il correspond (match)
au sélecteur. Voir l’exemple dans la “JS Sandbox” pour .wrap() et les deux
façons d’appeler .unwrap().
La fonction .wrapAll() permet d’envelopper, contrairement à .wrap(),
l’ensemble des éléments d’un objet jQuery, et non pas chaque élément
individuellement. Avec le HTML suivant :

  Hello
  Goodbye

Et l’appel suivant :
$('.niveau-2').wrapAll('');
On obtiendra ceci :

    Hello
    Goodbye
  
Enfin, .wrapInner() fonctionne d’une façon relativement similaire à ‘.wrap’,
mais au lieu d’envelopper chaque élément d’un objet jQuery, elle enveloppe le
contenu de chaque élément. Si on prend le même HTML que pour le 1er exemple,
celui de ‘.wrap()’, et qu’on effectue l’appel suivant :
$('.niveau-2').wrapInner('');
Alors il deviendra :

    Hello
  
    Goodbye
  
                                       16
3.3 Insertion avant ou après un élément

Référence sur cette section ici
Des fonctions permettent d’ajouter du contenu avant ou après un élément, en
dehors de celui-co contrairement aux fonctions vues en 3.1.
On a notamment .after() et .before(), ainsi que .insertAfter() et
.insertBefore(). Les différences entre .after() et .insertAfter(), ou
entre .before() et .insertBefore(), sont les mêmes qu’entre par exemple
.append() et .appendTo() vues précédemment.
Milieu
$('#milieu')
.before('Presque au début');
$('Tout au début')
.insertBefore('#presque-debut');
$('#milieu')
.after('Presque à la fin');
$('Tout à la fin')
.insertAfter('#presque-fin');

3.4 Suppression d’éléments

Référence sur cette section ici
On va s’intéresser à .empty() (à ne pas confondre avec le filtre :empty vu
précédemment) et à .remove(). .empty() supprime tous les noeuds enfants de
chaque élément de l’objet jQuery : donc tout le contenu. .empty() supprime
non pas le contenu des éléments matchés par le sélecteur, mais les éléments
eux-mêmes.

  Un titre
  Un paragraphe

  Un titre
  Un paragraphe

// enlève le h1 et le p de la div #des-trucs:
$('#des-trucs').empty();
// enlève la div #dautres-trucs elle-même:
$('#dautres-trucs').remove();

                                    17
À noter, car cela s’applique à jQuery, mais on trouve des notions similaires dans
les autres librairies et frameworks front-end : quand on supprime des éléments
auxquels on a attaché des listeners ou gestionnaires d’évènements (ou encore
handlers), que deviennent-ils ? Eh bien, jQuery s’occupe de les supprimer pour
nous, dès lors qu’on utilise ses fonctions de manipulation telles que .html(),
.remove(), ou encore .replaceWith(). Et heureusement : car chaque listener
prend des ressources (au moins de la mémoire).
Imaginons qu’on manipule une page avec beaucoup d’éléments (par exemple
une longue liste d’images à la Instagram), et que chacun de ces éléments ait
un listener. Dans le cadre d’une Single-Page App, où le navigateur ne recharge
jamais la page, si on est amené à quitter fréquemment cette page (entraînant la
destruction de ses éléments) et à y revenir, on pourrait se retrouver rapidement
avec des tas de listeners “fantômes”, qui ne sont plus rattachés à aucun élément.
Si on n’utilise pas jQuery mais l’API DOM native du navigateur, celui-ci s’occupe
normalement de supprimer les listeners devenus inutiles : à la condition toutefois
qu’il n’y ait plus aucune référence nulle part (par exemple dans une variable) à
l’élément auxquel ils sont attachés. C’est le cas des navigateurs modernes du
moins, mais pendant longtemps, des fuites de mémoire dûes notamment à des
gestionnaires d’évènements non supprimés, affectaient certains navigateurs.

3.5 Remplacement d’élément

La fonction .replaceWith() remplace non pas le contenu d’un élément, mais
l’élément lui-même. Pour reprendre l’exemple de la doc jQuery :

  Hello
  And
  Goodbye

$( "div.second" ).replaceWith( "New heading" );
Après l’appel à .replaceWith(), on obtient :

  Hello
  New heading
  Goodbye

3.6 Manipulation des attributs et propriétés classiques

On a vu pour l’instant la manipulation des tags eux-mêmes. jQuery offre aussi
des fonctions pour manipuler les attributs et propriétés d’un élément. Les

                                       18
fonctions principales pour cela sont .attr() et .prop(). Comme pour d’autres
fonctions, elles sont à la fois “getter” et “setter” :
  • elles renvoient la valeur de l’attribut ou propriété demandé, si appelées
    avec le seul nom de l’attribut en paramètre
  • elles remplacent la valeur de l’attribut ou propriété, si on leur passe le nom
    de l’attribut suivi de sa nouvelle valeur
Il y a d’autres façon de les appeler, et une nouvelle fois, pour plus de détails,
référez-vous à la section correspondante de la doc jQuery.
Ces fonctions sont assez similaires mais ont des différences notables. Les deux vont
faire la même chose si vous les utilisez, par exemple, pour récupérer un attribut id
ou href. Alors, quand utiliser l’un ou l’autre ? En gros, il faut utiliser .prop()
si on manipule des attributs d’état tels que checked, selected, disabled, etc.
Là où .attr('checked') sur une checkbox renverra "checked"`` si elle
est cochée, etundefinedsinon,.prop(‘checked’)‘ vous renverra un état clair et
précis sous forme d’un booléen. Un autre exemple que vous pouvez tester dans
la “Sandbox” :

var theChoice = $('#the-choice');
var the2ndChoice = $('#the-2nd-choice');

// Similaire
console.log(theChoice.attr('id')); // renvoie "the-choice"
console.log(theChoice.prop('id')); // renvoie "the-choice"

// Différent
console.log(theChoice.attr('checked')); // renvoie "checked"
console.log(theChoice.prop('checked')); // renvoie true

// Différent
console.log(the2ndChoice.attr('checked')); // renvoie undefined
console.log(the2ndChoice.prop('checked')); // renvoie false

var the3rdChoice = $('input[type="checkbox"]:eq(2)');
the3rdChoice.attr('id', 'the-3rd-choice');
the3rdChoice.prop('checked', true);
the3rdChoice.after(
   ' J\'aime les pâtes'
);
console.log(the3rdChoice.attr('id')); // renvoie "the-3rd-choice"
Une autre différence entre .attr() et .prop() peut s’observer en prenant le
href d’un lien. .attr() va renvoyer la valeur “brute” telle qu’indiquée dans

                                        19
l’attribut, alors que .prop() va renvoyer l’URL construite en combinant l’URL
de la page courante et la valeur de href. Si celle-ci est un lien relatif (sans / au
début), .prop() va construire l’URL absolue.
C’est un cas où on peut préférer utiliser .attr() : être sûr que ce qu’on récupère
est exactement ce qu’on avait indiqué.

3.7 Manipulation des attributs data

Outre les attributs “standard” et habituels tels que id, src, href, la norme
HTML5 permet d’associer aux balises des attributs nommés arbitrairement, en
étant toutefois précédés de data-. On peut y stocker tout ce qu’on veut, pourvu
que ce soit une string (si ce que vous souhaitez stocker dans un attribut data
est par exemple un objet, vous pouvez le “sérialiser” dans une chaîne JSON
grâce à JSON. stringify()).
jQuery offre la fonction .data() qui, comme précédemment, fait office de getter
(si appelée avec un argument) ou de setter (avec deux).
Questions essentielles

  Des questions que tout le monde se pose

// Cela pourrait être récupéré d'un fichier JSON externe.
var translations = {
    "fr": {
        "the_title": "Questions essentielles",
        "the_subtitle": "Des questions que tout le monde se pose"
    },
    "en": {
        "the_title": "Essential questions",
        "the_subtitle": "Questions everyone's asking oneself"
    }
};

$('#lang-selector a').click(function(e) {
    e.preventDefault();
    // Supprimer le # du début. Notez qu'ici on utise .attr(),
    // car on ne veut pas l'URL absolue qui aurait été
    // calculée avec .prop().
    var lang = $(this).attr('href').substr(1);
    // Démontre une autre fonction: .each()
    $('[data-translate]').each(function(index, elem) {
       var jqElem = $(this);
       var translateKey = jqElem.data('translate');
       jqElem.html( translations[lang][translateKey] );

                                        20
});
});
Quelques explications :
  • le sélecteur '[data-translate]' permet de choisir tous les éléments ayant
    un attribut data-translate (quelle que soit la valeur associée).
  • la fonction .each() fait une boucle : fonction passée en paramètre est ap-
    pelée pour chaque élément de l’objet jQuery, avec index et elem changeant
    à chaque itération
  • à noter, dans le corps de cette fonction, item et this ont la même valeur.
  • à partir de la valeur lang (en ou fr), et de la valeur de l’attribut
    data-translate, on sait quelle traduction aller chercher dans l’objet
    translations.

4 Propriétés de style

Voir la documentation sur cette partie.

4.1 Récupérer ou modifier les propriétés CSS

La fonction .css() est à nouveau un exemple de getter/setter. Cependant,
son fonctionnement n’est pas aussi systématique que pour les autres fonctions
getter/setter vues jusqu’ici.
  • Appelée avec un argument de type string, elle renvoie la propriété CSS
    correspondante
  • Appelée avec deux arguments de type string, elle remplace la propriété
    CSS dont le nom est passé comme premier argument, par la valeur passée
    comme deuxième argument.
  • Appelée avec un argument de type object, elle parcourt les paires “clé-
    valeur” de l’objet, et attribue à la propriété “clé” la “valeur” associée.
Comme getter : renvoie la valeur de la propriété CSS
Un paragraphe en bleu
Valeur de la propriété color: 

Comme setter : modifie la valeur de la propriété CSS
Un paragraphe sans style de base
Valeur de la propriété color après modif. :

Comme setter : modifie les valeurs
de plusieurs propriétés CSS
Un paragraphe sans style de base

                                      21
var colorFirst = $('p:first').css('color');
$('p:first + div > span').html(colorFirst);

$('p:eq(1)').css('color', 'green');
var colorSecond = $('p:eq(1)').css('color');
$('p:eq(1) + div > span').html(colorSecond);

var properties = {
    color: 'red',
    backgroundColor: '#bbb',
    fontSize: '130%',
    padding: '10px',
    'font-weight': 'bold'
};
var thirdParagraph = $('p:eq(2)');
thirdParagraph.css(properties);
for( var key in properties ) {
    var value = thirdParagraph.css(key);
    console.log( key, value );
    var texte = 'Valeur de la propriété ' +
        key + ' après modification: ';
    var div = $( texte ).insertAfter( thirdParagraph );
    div.find('span').html( value );
}
Remarquez qu’on peut utiliser indifféremment, pour les noms des propriétés, la
syntaxe CSS native (avec tirets -) ou la syntaxe “camelCase”. jQuery supporte
les deux.
L’intérêt d’utiliser la syntaxe camelCase se révèle pour la 3ème utilisation de la
fonction, où on passe un objet en argument. JavaScript génère une erreur si on
met un - dans une clé d’objet, sauf si on prend la précaution d’entourer la clé
par des quotes simples ' ou doubles ".
Cela peut alourdir un peu le code et le rendre moins lisible, ce qui est résolu par
l’utilisation de camelCase.

4.2 Propriétés CSS dynamiques

Par là, on entend des propriétés qui sont susceptibles d’être modifiées pendant la
durée d’exécution du programme. Et modifiées, pas seulement par le programme
lui-même, mais du fait de l’interaction de l’utilisateur. Par exemple, des éléments
dont les propriétés CSS width et height n’ont pas été indiquées “en dur” avec une
valeur en pixels, peuvent voir cette propriété varier si l’utilisateur redimensionne
la fenêtre en cours.
jQuery fournit des raccourcis pratiques pour lire ou modifier ces propriétés.

                                        22
.width() et .height() sont encore des getter/setter simples (pas d’argument :
lecture, un argument : modification), qui comme leur nom l’indique retournent
ou modifient la largeur et la hauteur du ou des élément(s) ciblé(s).
.innerWidth() et .innerHeight() sont des variantes, qui prennent en compte
non seulement la largeur ou hauteur intrinsèque de l’élément, mais aussi sa
propriété padding, en omettant border.
.outerWidth() et .outerHeight() incluent les propriétés padding et border
de l’élément, ainsi que margin si elle est spécifiée.

    Container
    Inner 1
    Inner 2

On va attribuer des styles différents aux deux div.inner, pour voir les différences
entre les résultats des différentes fonctions.
div {
    padding: 10px;
}
.wrapper {
    background: #999;
}
.inner {
    margin-bottom: 20px;
}
.wrapper div:nth-child(2) {
    background: #bef;
    margin-left: 40px;
}
.wrapper div:nth-child(3) {
    background: #efb;
    border: 10px solid #bbb;
}
Le JavaScript se corse un peu. . . Ici on utilise des constructions un peu complexes,
mais courantes. L’explication est juste après le code !
var divsInner = $('.inner');
divsInner.each(function() {
  var div = $(this);
  var functions = [
     'width', 'innerWidth', 'outerWidth',
     'height', 'innerHeight', 'outerHeight'
  ];

                                         23
// On va construire une liste précédée d'un titre
  var divTitle = div.html();
  // Tag d'ouverture de la liste
  var resultHtml = 'Div: ' + divTitle + '';
  functions.forEach( function( funcName ) {
    // A la 1ère itération, funcName vaut width,
    // puis innerWidth à la 2nde, etc.
    // On va se servir de ce funcName pour
    // savoir quelle fonction appeler !
    var result = div[funcName]();
    resultHtml += '.' + funcName +
      '() renvoie: '+ result + '';
  });
  // Ne pas oublier les tags de fermeture
  resultHtml += '';
  // On ajoute le tout à la div de résultats.
  $('#results').append(resultHtml);
});
Parfois on veut exécuter un certain nombre de fonctions (ou récupérer un certain
nombre de propriétés) sur des objets.
Plutôt que d’écrire individuellement chaque appel “en dur”, ici on itère sur les
noms des fonctions à appeler (tableau functions). Pour chaque nom de fonction
dans ce tableau, on va exécuter cette fonction sur l’objet jQuery div.
C’est cette ligne qui fait ce tour de magie :
var result = div[funcName]();
Ici on prend la propriété de div indiquée par funcName (qui vaut successivement
width, innerWidth, etc.). Cette propriété est ici une fonction, et pour l’appeler
il faut indiquer les parenthèses, comme on le ferait pour un appel de fonction
“normal”. Ensuite on sauve le résultat de l’appel dans la variable result.

                                        24
Vous pouvez aussi lire