Topic outline

  • go !

  • Le BOM : Browser Object Model

    Quand vous programmez en JavaScript, vous avez accès à de nombreuses données contenues dans votre navigateur. Il y a évidemment les éléments de votre page web (texte, image, etc...), mais avant, il y a quelques éléments qui sont plutôt rattachés au navigateur qu'a la page elle même.


    Le gros des projets que vous réaliserez se passe dans le DOM (Document Object Model), la partie "document" de l'image ci-dessus. Mais de temps en temps, vous serez emmenés à utiliser des fonctions qui sont "au-dessus" du DOM.

    Voici quelques fonctions accessibles via l'objet window :

    Interaction avec l'utilisateur (méthodes fonctionnelles, mais dépréciées dans les usages) :

    • alert : affiche une fenêtre modale avec un texte informatif
    • prompt : affiche une fenêtre modale avec une zone de saisie
    • confirm :  affiche une fenêtre modale qui demande la confirmation ou l'annulation d'une action


    Stockage d'information dans le navigateur :

    • localStorage : permet de stocker des informations sous forme de clé valeur, de manière persistante
    • sessionStorage : permet de stocker des informations sous forme de clé valeur, le temps de la navigation

    https://developer.mozilla.org/fr/docs/Web/API/Storage


    Liens et navigation :

    • location : permet de changer l'URL de la page en cours (un peu comme un lien hypertexte)
    • history : permet d'avoir accès à l'historique de navigation


    Événement dans la fenêtre :

    • tout ce qui concerne les scroll (scrollX, scrollY,...)
    • open / close (ouvrir un nouvel onglet, ou bien fermer l’onglet en cours)
    • addEventListener / removeEventListener : gestion des évenements (très important)


    Programmation asynchrone :

    • fetch : récupérer des données sur un serveur distant (très important)
    • setInterval / setTimeout (+ clearInterval et clearTimeout) : timers (très important pour les animations)


    Divers :

    • récupéré la largeur et la hauteur (outerHeight et outerWidth + innerHeigth et innerWidth)
    • console : afficher des informations dans la console du navigateur
    • et enfin : document (le DOM), sur lequel vous travaillerai énormément


    Peu utilisé, voir déconseillé :

    • tout ce qui concerne les frames
    Note sur les frameset : les frames sont une vieille pratique du web, mais qui est restée fonctionnelle malgré tout. Plus aucun site sérieux technologiquement ne les utilisent à fond. Elles permettaient d'ouvrir plusieurs URL dans une même page, via la mise en place d'un système de cadre (frame), dans une seule et même page. On pouvait donc "découper" un site en plusieurs zones. Cette pratique est à proscrire aujourd'hui. Il reste la balise <iframe> qui reste utilisé, mais seulement dans des cas très précis : intégration de vidéo/son/fonctionnalités offertes par un autre service (YouTube, platefome de son, etc...).


    Donc pour conclure, l'objet window correspond à des choses qui sont propre au navigateur, tandis que l'objet document (qui est compris dans window) correspond à l'ensemble des éléments qui composent une page web.


    On peut rajouter le CSS aussi, qui est manipulable via le DOM


    Et voici une dernière image détaillant un peu plus le DOM, et qui fait surtout le lien avec la notion de scope :


    En programmation, tout est souvent imbriqué


  • Le DOM : Document Object Model


    Comme nous l'avons vu sur les cours précédents, quand un navigateur reçoit une page HTML - qui est reçue sous forme de simple chaîne de caractère, pour que les choses soient claires - il ne l'affiche pas "telle quelle". Il décortique la chaîne HTML reçue, et construit ce que l'on appelle le DOM (pour Document Object Model). Et c'est le DOM qui sert de référence pour créer le rendu de votre page, via le moteur de rendu qui va se charger de "dessiner" votre page dans le navigateur.

    Le DOM est ce que nous appelons un objet, c’est-à-dire qu'il est créé selon une logique particulière, qui fait que les éléments qui le composent peuvent être créés, lus, modifiés ou supprimés si on sait lui parler et qu'on utilise la bonne méthode. Et JavaScript sait faire ça. C’est-à-dire que JavaScript dispose des éléments de langages pour venir discuter avec votre DOM, et faire des modifications dessus.


    => Inspecter la page du cours pour voir le DOM dans votre console. Rien de neuf, nous avons vu ça ensemble.


    Pour l'aspect POO (programmation orientée objet), nous verrons ça dans un des chapitres suivant. Ce que vous devez comprendre c'est que le DOM est entièrement modifiable via un langage de programmation tel que JavaScript. Vous pouvez par exemple changer des couleurs, changer le contenu d'un texte, ajouter des lignes à un tableau, etc...


    Décomposition des trois aspects :

    • rendu graphique dans le navigateur
    • code HTML
    • DOM


    Tous les éléments d'une page web correspondent à un objet du DOM. Dans l'image ci-dessus, nous voyons que certains objets possèdent du texte, d'autres contiennent simplement d'autres objets (c'est dû à l'imbrication du code HTML). On parle alors de récursivité : des objets contiennent des objets, qui contiennent d'autres objets... sans vraiment de limite.

    Je ne vous ferai pas la liste de toutes les méthodes et attributs accessibles via le DOM car elle serait immensément longue. Et elle existe déjà sur le MDN, et tous les sites spécialisés. Mais sachez que TOUTE votre page web se trouve quelque part dans ces objets, à vous de rechercher les différentes méthodes selon vos besoins.

    Voici une page intéressante en français sur le DOM que j'ai trouvé par hasard.

    Voici la page de référence du DOM sur le MDN, et quelques exemples simples.

  • Sélectionner des éléments

    Afin de pouvoir manipuler les éléments du DOM, il faut d'abord pouvoir les sélectionner. Un peu comme en CSS, on va écrire des règles de sélections pour cibler des éléments par classe, id, etc... puis on va pouvoir les traiter dans notre programme Javascript. 

    Important : vous allez remarquer que les méthodes de sélections des éléments de votre DOM utilisent la même approche que le CSS. Vous allez pouvoir sélectionner des éléments par balises, classes, id, attributs, etc...  Il vous faut donc bien avoir compris la logique des règles de sélections CSS, et le tour est quasiment joué !

    Il existe différentes méthodes pour sélectionner un ensemble d'élément dans le DOM, certaines sont rapides, d'autres sont pratiques. Voici un benchmark des quelques méthodes que nous allons voir dans les sections suivantes :

  • Sélecteurs standards

    Ces trois méthodes sont les plus optimisées pour accéder au DOM. En revanche elles ne sont pas très pratiques car elles manquent de souplesse en ce qui concerne la méthode de sélection. Nous verrons d'autres méthodes, plus pratiques, juste après.


    Sélectionner un élément par son id

    Avec la méthode .getElementById() de l'objet document, vous allez pouvoir sélectionner un élément par son id. Cette méthode vous renvoi un seul élément, accessible directement.

    <meta charset="UTF-8" />
    <h1 id="titre1">Ceci est un titre de ma page web</h1>
    <script>
    let monTitre = document.getElementById('titre1'); /*Renvoi l'élément HTML ayant l'id 'titre1'*/

    console.log('Mon élément, dans son ensemble : ',monTitre);
    console.log('Le contenu "texte" de mon élément : ',monTitre.innerHTML);
    </script>



    Sélectionner des éléments par leur type de balise

    Avec la méthode .getElementsByTagName() de l'objet document, vous allez pouvoir sélectionner des éléments via leur type de balise HTML (balise = tag, en anglais). Contrairement à .getElementById(), cette méthode vous renvoie un tableau d'éléments.

    Important : retenez bien que cette méthode vous renvoie un tableau. Il vous faudra donc utiliser des boucles pour accéder à tous les éléments de votre DOM retournés par cette méthode. Notez le "s" dans le nom de la méthode. Même si aucun élément ne matchent avec votre requête, ou bien juste un seul, vous obtiendrez quand même un tableau.
    <ul>
    <li>Abricot</li>
    <li>Pomme</li>
    <li>Banane</li>
    </ul>
    <script>
    let fruits = document.getElementsByTagName('li'); /* Renvoi les éléments HTML de type <li> */

    for(let fruit of fruits){
    console.log(fruit); /*La balise*/
    console.log(fruit.innerHTML); /*Le contenu*/
    }
    </script>


    Sélectionner des éléments par leurs classes CSS

    Avec la méthode .getElementsByClassName() de l'objet document, vous allez pouvoir sélectionner des éléments via leur classe CSS. Cette méthode vous renvoi plusieurs éléments, accessibles via un tableau.

    <meta charset="UTF-8" />
    <p>
    Voici un texte qui contient beaucoup de <span class="important">mots</span>,
    certains sont <span class="important">importants</span>, et d'autres non.
    Voici comment je peux <span class="important">extraire</span> les mots importants via une <span class="important">règle de sélection par classe CSS</span>.
    </p>
    <script>
    let expressionsImportantes = document.getElementsByClassName('important'); /* Renvoi les éléments HTML de la classe 'important' */

    for(let texte of expressionsImportantes){
    console.log(texte.innerHTML);
    }
    </script>
    Attention : comme vous pouvez le constater, il n'y pas l'identifiant ., habituellement utilisé pour identifier les classes en CSS. Cette méthode ne recherchant que des classes, vous n'avez pas besoin d'écrire .important.
  • querySelector : sélectionner via la logique CSS

    Ces deux méthodes sont bien pratiques, car vous n'avez plus à dire si vous souhaitez sélectionner un élément par son id, sa classe, ou son type de balise. Vous allez utiliser les règles de sélection CSS pour cela. 

    Revoir le cours sur les sélecteurs CSS si nécessaire. 

    Pour rappel, on peut sélectionner un élément en CSS par :

    • sa balise HTML
    • sa classe, avec l'opérateur .
    • son id, avec l'opérateur #
    • etc...


    querySelector() : sélectionner un seul élément

    La méthode querySelector() vous renvoie un seul élément, selon la logique des sélecteurs CSS.

    <input type="text" name="prenom" id="prenom" value="julien" />
    <script>
    let prenomId = document.querySelector('#prenom'); /* Sélection par id */
    console.log(prenomId.value);

    let prenomInput = document.querySelector('input'); /* Sélection par tag */
    console.log(prenomInput.value);

    let prenomAttr = document.querySelector('input[name=prenom]'); /* Sélection par attributs */
    console.log(prenomAttr.value);
    </script>

    Ces instructions vous renverrons toujours le input qui a dans l'extrait de code, via son id, sa balise, ou des attributs divers...

    Attention : si votre règle matche avec plusieurs éléments, la méthode querySelector() ne vous renverra que le premier qu'elle rencontre dans le DOM.


    querySelectorAll() : sélectionner un ensemble d'éléments

    La méthode querySelectorAll() fonctionne de la même manière que querySelector(), mais sur plusieurs éléments. Elle vous renvoi donc un tableau de NodeList dans tous les cas.

    <meta charset="UTF-8" />
    <h1>Mes fruits</h1>
    <ul id="fruits">
    <li>Abricot</li>
    <li>Pomme</li>
    <li>Fraise</li>
    <li>Frambois</li>
    </ul>
    <h1>Mes légumes</h1>
    <ul id="legumes">
    <li>Tomate</li>
    <li>Poivrons</li>
    <li>Oignons</li>
    <li>Patate</li>
    </ul>
    <script>
    let mesFruits = document.querySelectorAll('ul#fruits li'); /*Je sélectionne tous les li de ul ayant l'id fruits*/
    let mesLegumes = document.querySelectorAll('ul#legumes li'); /*Je sélectionne tous les li de ul ayant l'id legumes*/

    console.warn("Le retour de mes sélecteurs : un tableau d'éléments")
    console.log('mesFruits', mesFruits);
    console.log('mesLegumes', mesLegumes);

    /* Si on souhaite parcourir les éléments, on boucle !*/

    console.warn('Mes fruits :');
    for(let fruit of mesFruits){
    console.log(fruit.innerHTML);
    }

    console.warn('Mes légumes :');
    for(let legume of mesLegumes){
    console.log(legume.innerHTML);
    }
    </script>


    Et voila, la magie opère ! Maintenant que vous pouvez traiter votre DOM de manière programmatique, les possibilités sont très vastes.
  • Faire un helper de sélection

    L'écriture des méthodes de sélection peut parfois être fastidieuse et répétitives, vous pouvez donc écrire vos propres fonctions utilitaires pour rendre l'usage de ces fonctionnalités plus aisé. 

    Ceci est à titre d'exemple, juste pour vous montrer des possibilités...


    function select(selector) {
    let element = document.querySelectorAll(selector);
    if (element.length > 1) {
    return element;
    } else if (element.length == 1) {
    return element[0];
    } else {
    return false;
    }
    }
    select('li'); /* Si plusieurs li, renverra une liste */
    select('#titre1'); /* Renverra un seul élément */
    select('.titre'); /* Si plusieurs balise ont la classe titre, renverra une liste */
    select('iframe'); /* Si pas d'iframe dans la page : renverra false */


    Il y a de nombreuse façon de faire ses propres "helpers", à vous de le coder comme bon vous semble, selon vos besoins. Attention toutefois, si quelqu'un d'autre travail avec vous, il faudra qu'il comprenne ce que vous avez voulu faire, car ça n'est pas totalement standard...

  • Lire les propriétés

    Comme nous l'avons vu dans les exemples précédents, on peut accéder aux différentes propriétés d'une balise. Et il y en a de nombreuses... Par exemple, sur une balise simple, la propriété .innerHTML permet de lire le contenu "brut" d'un élément. Ce sera soit du texte, soit d'autres balises HTML.

    Et bien pour chaque balise, vous avez tout un tas de propriétés accessibles. Quasiment tout ce qui est faisable en HTML/CSS, peut être lu par JavaScript.


    Exemples


    Sur un ensemble de champs de formulaire, dont certains sont checkés et d'autres pas :

    <meta charset="UTF-8" />
    <h1>Les langages que je connais :</h1>
    <input type="checkbox" name="HTML" checked />HTML<br/>
    <input type="checkbox" name="JS" checked />Javascript<br/>
    <input type="checkbox" name="JAVA" />Java<br/>
    <input type="checkbox" name="C" />C<br/>
    <input type="checkbox" name="PHP" checked />PHP<br/>
    <input type="checkbox" name="PYTHON" />Python<br/>
    <input type="checkbox" name="CSS" checked />CSS<br/>

    <script>
    let skills = document.querySelectorAll('input'); /*Je sélectionne tous les input*/

    console.log('skills', skills);
    console.warn('Mais langages préférés :');

    for(let skill of skills){
    if(skill.checked === true){ /* Je peux lire la propriété checked, présente dans le DOM */
    console.log(skill.name); /* Je peux lire la propriété name de mon élément */
    }
    }
    </script>

  • Modifier les propriétés

    De la même manière on peut modifier les propriétés des éléments. Dans l'exemple ci-dessous, on va modifier la couleur du texte via la propriété style et la sous-propriété color, comme en CSS.


    Modifier les propriétés CSS inline
    <meta charset="UTF-8" />
    <h1>Les langages que je connais :</h1>
    <input type="checkbox" name="HTML" checked />
    <label id="HTML">HTML</label>
    <br/>
    <input type="checkbox" name="JS" checked />
    <label id="JS">Javascript</label>
    <br/>
    <input type="checkbox" name="JAVA" />
    <label id="JAVA">Java</label>
    <br/>
    <input type="checkbox" name="C" />
    <label id="C">C</label>
    <br/>
    <input type="checkbox" name="PHP" checked />
    <label id="PHP">PHP</label>
    <br/>
    <input type="checkbox" name="PYTHON" />
    <label id="PYTHON">Python</label>
    <br/>
    <input type="checkbox" name="CSS" checked />
    <label id="CSS">CSS</label>

    <script>
    let skills = document.querySelectorAll('input'); /*Je sélectionne tous les input*/
    let name = '';
    let label;

    for(let skill of skills){
    name = skill.name; /* On récupère la valeur présente dans la propriété name */
    label = document.querySelector(`label#${name}`); /*On sélectionne le label qui a l'id name */
    if(skill.checked === true){
    label.style.color = 'green'; /*On change la couleur du label en vert*/
    } else {
    label.style.color = 'red'; /*On change la couleur du label en rouge*/
    }
    }
    </script>



    Ajouter une classe CSS

    On peut aussi modifier certaines propriétés en utilisant des méthodes spécialisées. Si par exemple on souhaite ajouter une classe CSS à un élément, on peut utiliser la propriété classList, qui offre la méthode add()

    Voici un lien vers la doc de classList dans le MDN.

    <meta charset="UTF-8" />
    <h1>Les langages que je connais :</h1>
    <input type="checkbox" name="HTML" checked />
    <label id="HTML">HTML</label>
    <br/>
    <input type="checkbox" name="JS" checked />
    <label id="JS">Javascript</label>
    <br/>
    <input type="checkbox" name="JAVA" />
    <label id="JAVA">Java</label>
    <br/>
    <input type="checkbox" name="C" />
    <label id="C">C</label>
    <br/>
    <input type="checkbox" name="PHP" checked />
    <label id="PHP">PHP</label>
    <br/>
    <input type="checkbox" name="PYTHON" />
    <label id="PYTHON">Python</label>
    <br/>
    <input type="checkbox" name="CSS" checked />
    <label id="CSS">CSS</label>
    <style>
    /* Je défini des classes CSS normalement */
    .langageOk{
    color:green
    }
    .langagePasOk{
    color:red;
    }
    </style>
    <script>
    let skills = document.querySelectorAll('input'); /*Je sélectionne tous les input*/
    let name = '';
    let label;

    for(let skill of skills){
    name = skill.name; /* On récupère la valeur présente dans la propriété name */
    label = document.querySelector(`label#${name}`); /*On sélectionne le label qui l'id name */
    if(skill.checked === true){
    label.classList.add("langageOk"); /* J'ajoute la classe CSS de façon programmatique */
    } else {
    label.classList.add("langagePasOk"); /* J'ajoute la classe CSS de façon programmatique */
    }
    }
    </script>


    Après avoir exécuté cet extrait de code, regarder votre DOM dans votre inspecteur : les classes ont bel et bien été ajoutées ! Comme si vous les aviez écrit vous même. Et vu que vos classes sont définies dans votre code - entre les balises <style> - et font partie intégrante de votre DOM, le nouveau style s'applique au <label>


  • Créer de nouveaux éléments

    Vous pouvez créer des balises HTML de toute pièces à l'aide de JavaScript. En utilisant les méthodes adaptées, vous allez pouvoir ajouter des éléments à votre DOM, qui ne sont initialement pas présents dans le HTML.

    Voici quelques méthodes :

    • .createElement(x) : retourne un nouvel élément de type x. Exemple : cretaElement('h1') va créer un nouvel élément H1 dans le JS.
    • .appendChild() : ajoute un élément au DOM, à un élément parent. Exemple document.body.appendChild(xxx); -> ajoutera l'élément xxx au body.
    • etc...


    Il existe de très nombreuses méthodes rattachées à l'objet document. Comme toujours, ne vous amusez pas à tout retenir de tête, mais plutôt à prendre l'habitude d'aller fouiller dans la doc dès que vous souhaitez faire quelque chose. Voici le lien vers la doc du MDN pour l'objet document.


    Voici un exemple avec notre liste de langages :

    <meta charset="UTF-8" />
    <body>
    <h1>Les langages que je connais :</h1>
    <!-- MON BODY EST VIDE -->
    </body>

    <script>
    let languages = ['HTML', 'JAVASCRIPT', 'JAVA', 'C', 'PHP', 'PYTHON', 'CSS']; /* Un tableau JS, tout ce qu'il y a de plus classique */
    let input; /* Mes futurs éléments, que je prends soin de déclarer à l'avance */
    let label;
    let br;

    for(let language of languages){

    /*Je créé la balise input en JS */
    input = document.createElement('input'); /* Je créé la balise */
    input.type = 'checkbox'; /* Je modifie ses propriétés */
    input.name = language; /* Je modifie ses propriétés */
    document.body.appendChild(input); /* Je l'intègre dans le body */
    /*Je créé la balise label en JS */
    label = document.createElement('label');
    label.innerHTML = language;
    document.body.appendChild(label);

    /*Je créé la balise br en JS */
    br = document.createElement('br');
    document.body.appendChild(br);
    }
    </script>

    Résultat en image :


  • Ajouter des éléments dans d'autres éléments

    Nous venons de voir comment ajouter des éléments au <body>, mais vous pouvez ajouter des éléments à n'importe quel autre élément en réalité.

    Exemple sur une liste non-oronnée :

    <meta charset="UTF-8" />
    <body>
    <h1>Les langages que je connais :</h1>
    <ul id="listeDeLangages">
    <!-- VIDE -->
    </ul>
    </body>
    <script>
    let languages = ['HTML', 'JAVASCRIPT', 'JAVA', 'C', 'PHP', 'PYTHON', 'CSS'];
    let maListeHTML = document.getElementById('listeDeLangages');
    let li;

    for(let language of languages){
    /*Je créé la balise li en JS */
    li = document.createElement('li'); /* Je créé la balise */
    li.innerHTML = language; /* Je modifie ses propriétés */
    maListeHTML.appendChild(li); /* J'intègre le nouveau point à ma liste' */
    }
    </script>

    Et voilà, vous avez généré une liste <ul> <li> de manière programmatique !


  • Supprimer des éléments

    remove, removeChild(), etc...

  • En plus

    setAttribute / getAttribute etc...

    Parler de quelques méthodes supplémentaires...

    Comment sélectionner une valeur dans un select ?

    
    <select id="maListe">
      <option value="0">Poire</option>
      <option value="1">banane</option>
      <option value="2">Pomme</option>
      <option value="3">Fraise</option>
    </select>
    <button id="test">TEST</button>
    <script>
    
    
      document.getElementById('test').addEventListener('click', function () {
        console.log('ok ! ');
    
        let maListe = document.getElementById("maListe");    
        let optionSelected = maListe.options[maListe.selectedIndex].text;
    
        let test = maListe.value
    
        //console.log(optionSelected)
        console.log(test)
    
      })
    
    </script>
    


    Validation de formulaire : API validation

    https://developer.mozilla.org/fr/docs/Learn/Forms/Form_validation


    cloneNode : à voir

  • Exercices