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

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

JavaScript Discussion :

Création d'une treeview


Sujet :

JavaScript

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Homme Profil pro
    Enseignant
    Inscrit en
    Mars 2013
    Messages
    38
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Service public

    Informations forums :
    Inscription : Mars 2013
    Messages : 38
    Par défaut Création d'une treeview
    Bonjour,

    Je ne suis pas novice en programmation mais je suis novice en javascript. je suis en train de mettre en place un "treeview" pour m'exercer et pour mon site ( site de cours de maths en ligne pour la période de confinement)
    Voici l'extrait de mon code qui pose souci:
    Code Javascript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    function addListeners(){
        let carets= tree.getElementsByClassName("caret");
        for (let i=0;i<carets.length;i++){
            carets[i].addEventListener("click", function(){
                this.classList.toggle("caret-down")          
                let nestedElements =this.querySelectorAll("ul > li")
                console.log(nestedElements)            
                for (let i=0;i<nestedElements.length;i++){
                nestedElements[i].classList.toggle("active")
     
                }
            });
        }
    }

    La ligne qui pose souci est celle-ci: let nestedElements =this.querySelectorAll("ul > li") .

    Avec mon console.log, je vois que tous les éléments enfants "li" sont ciblés alors que je ne veux cibler que ceux qui sont les enfants directs. Il me semblait que le sélecteur CSS "ul>li" permettait de faire cela mais je ne trouve pas de solution à mon problème. Merci d'avance pour vos éventuelles aides.

    Raphaël, enseignant.

  2. #2
    Modérateur

    Avatar de NoSmoking
    Homme Profil pro
    Inscrit en
    Janvier 2011
    Messages
    17 207
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Janvier 2011
    Messages : 17 207
    Par défaut
    Bonjour,
    ton sélecteur fait ce qu'il faut, il cible les <li> enfants directs d'un élément <ul> ce qui est (devrait être) toujours le cas mais il semblerait que cela soit le premier <ul> que tu cherches à cibler, mais il nous manque donc ta structure HTML pour te montrer.

  3. #3
    Membre averti
    Homme Profil pro
    Enseignant
    Inscrit en
    Mars 2013
    Messages
    38
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Service public

    Informations forums :
    Inscription : Mars 2013
    Messages : 38
    Par défaut suite avec code HTML
    merci tout d'abord d'avoir pris du temps pour cette première réponse.
    Ce sont bien les li directs sous le ul que je cherche à cibler. Voici le code HTML qui va avec:
    Code HTML : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    <nav id="navTree">
            <ul>
                <li> Classe de seconde
                    <ul>
                        <li><a href="#">Chapitre 1</a>
                            <ul>
                                <li>doc 1</li>
                                <li>doc 2</li>
                            </ul>
                        </li>
                        <li><a href="#">Chapitre 2</a>
                            <ul>
                                <li>doc 1</li>
                                <li>doc 2</li>
                            </ul>
                        </li>
     
                    </ul>
                </li>
                <li> Classe de premiere
                    <ul>
                        <li><a href="#">Chapitre 1</a>
                            <ul>
                                <li>doc 1</li>
                                <li>doc 2</li>
                            </ul>
                        </li>
                        <li><a href="#">Chapitre 2</a>
                            <ul>
                                <li>doc 1</li>
                                <li>doc 2</li>
                            </ul>
                        </li>
     
                    </ul>
                </li>
            </ul>

    À noter que les classes n'apparaissent pas dans le code HTML: la première partie de mon script js se charge de les ajouter et cela, ça marche ( vérification faite avec l'inspecteur d'élément)

    Merci d'avance pour une éventuelle réponse

  4. #4
    Expert confirmé
    Avatar de Watilin
    Homme Profil pro
    En recherche d'emploi
    Inscrit en
    Juin 2010
    Messages
    3 094
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : En recherche d'emploi

    Informations forums :
    Inscription : Juin 2010
    Messages : 3 094
    Par défaut
    Citation Envoyé par rafoim Voir le message
    À noter que les classes n'apparaissent pas dans le code HTML: la première partie de mon script js se charge de les ajouter et cela, ça marche ( vérification faite avec l'inspecteur d'élément)

    Merci d'avance pour une éventuelle réponse
    Question un peu hors sujet mais, si tu as un script capable de cibler les bons éléments pour leur ajouter une classe, alors à quoi sert la classe ?

    Pour répondre à ta question, techniquement le sélecteur ul > li est équivalent à li tout court car un élément <li> est toujours un descendant direct de <ul>.
    Le détail qui nous manque encore, dans ton code, c’est à quel endroit sont ajoutées les classes "caret". En fonction de l’élément de départ (this) sur lequel est appliqué querySelectorAll, le résultat ne sera pas le même.
    Si ça peut t’aider, sache que tu peux naviguer vers le haut dans l’arbre DOM avec la propriété .parentElement ou la méthode .closest().

    Une autre piste de solution : tu peux essayer de ne mettre que l’instruction this.classList.toggle("caret-down") dans ta fonction, et t’arranger pour que les éléments voulus apparaissent en utilisant uniquement du code CSS
    La FAQ JavaScript – Les cours JavaScript
    Touche F12 = la console → l’outil indispensable pour développer en JavaScript !

  5. #5
    Membre averti
    Homme Profil pro
    Enseignant
    Inscrit en
    Mars 2013
    Messages
    38
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Service public

    Informations forums :
    Inscription : Mars 2013
    Messages : 38
    Par défaut
    Je te cite:
    " Question un peu hors sujet mais, si tu as un script capable de cibler les bons éléments pour leur ajouter une classe, alors à quoi sert la classe ? "
    Je m 'inspire en fait de la méthode ici:https://www.w3schools.com/howto/howto_js_treeview.asp

    j'ai voulu modifier un peu. je n'ai pas encore testé mais je crois que leur méthode ne fonctionne que si on est dans une totale imbrication des répertoires et des sous-répertoires, pas pour un arbre plus général ( deux entrées de niveau supérieures par exemple).

    je tente aussi de modifier une chose: je ne veux pas avoir à écrire les classes dans mon html d'où l'insertion par js. Voici le script complet avec la fonction qui insère les classes:
    Code javascript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
     
    function prepareTree(){
     
        let treeElements = tree.getElementsByTagName("li")
     
        for (let i=0;i<treeElements.length;i++){
            let l = treeElements[i].children.length
            if (l>0){
                treeElements[i].classList.add("caret")
            }
     
            if (treeElements[i].parentElement.parentElement.tagName != "NAV" ){
                treeElements[i].classList.add("nested")
            }
        }
    }
     
    function addListeners(){
        let carets= tree.getElementsByClassName("caret");
        for (let i=0;i<carets.length;i++){
            carets[i].addEventListener("click", function(){
                this.classList.toggle("caret-down")          
                let nestedElements =this.querySelectorAll("ul > li")
                console.log(nestedElements)            
                for (let i=0;i<nestedElements.length;i++){
                nestedElements[i].classList.toggle("active")
     
                }
            });
        }
    }
    let tree = document.getElementById("navTree");
    prepareTree();
    addListeners();


    Mon code insère les classes puis les classes doivent s'ajouter ou se soustraire selon les événements. je n'ai pas compris pourquoi tu trouvais cela inutile ( j'ai senti une pointe d'ironie par contre, mais il n'y a pas de souci).
    pour la navigation avec parentElement, je vais y penser. Le souci, c'est que quand je remonte au parent, ensuite, je risque de sélectionner trop de monde ( je sais, ce n'est pas très clair).

    merci pour ta participation à ma recherche.

    Raphaël

  6. #6
    Expert confirmé
    Avatar de Watilin
    Homme Profil pro
    En recherche d'emploi
    Inscrit en
    Juin 2010
    Messages
    3 094
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : En recherche d'emploi

    Informations forums :
    Inscription : Juin 2010
    Messages : 3 094
    Par défaut
    Citation Envoyé par rafoim Voir le message
    je n'ai pas compris pourquoi tu trouvais cela inutile ( j'ai senti une pointe d'ironie par contre, mais il n'y a pas de souci).
    C’était une vraie question, désolé si ça sonnait ironique, ce n’était pas mon intention. L’information que je n’avais pas était celle-ci :
    je ne veux pas avoir à écrire les classes dans mon html
    … Ce qui est une raison parfaitement valable.

    Je souligne juste un point délicat dans ton code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
            if (treeElements[i].parentElement.parentElement.tagName != "NAV" ){
    Ici, tu as un enchaînement .parentElement.parentElement qui est « rigide » et cassera dès la première modification de la structure HTML. Ok, tu n’as sans doute pas prévu de modifier le HTML, et je comprends l’intention de remonter exactement 2 niveaux. Mais en l’occurence, je pense qu’on peut se passer complètement de la classe "nested" en la remplaçant, à la fois dans le code CSS et dans le code JS, par un simple sélecteur ul ul. Je sais que je contredis W3Schools (ça ne sera pas la première fois )

    pour la navigation avec parentElement, je vais y penser. Le souci, c'est que quand je remonte au parent, ensuite, je risque de sélectionner trop de monde ( je sais, ce n'est pas très clair).
    Si si ça me semble clair Bien sûr, rien ne t’empêche de combiner des trucs comme .parentElement.querySelectorAll( ... ).

    Ah, une précision peut-être utile : quand tu écris this.querySelectorAll("ul > li"), le sélecteur CSS n’est pas limité au sous-arbre de this. Je m’explique : pour résoudre un querySelectorAll, le moteur JS fait deux choses :
    1. il établit la liste des enfants de l’élément ciblé ;
    2. il invoque le moteur de filtrage CSS pour tester le sélecteur "ul > li" sur chacun des enfants.

    Le moteur CSS n’a pas connaissance de « l’élément de base » de querySelectorAll, et il peut remonter plus haut si besoin quand il y a une relation de descendance à tester.
    Par exemple, this.querySelectorAll("nav li") fonctionne parce qu’il y a un élément <nav> plus haut dans l’arbre, même si c’est au-dessus de l’élément this.

    Citation Envoyé par jreaux62 Voir le message
    (au cas où je supprime - plus tard - mon Codepen)
    Je te remercie d’avoir pensé au “link rot”
    La FAQ JavaScript – Les cours JavaScript
    Touche F12 = la console → l’outil indispensable pour développer en JavaScript !

  7. #7
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par Watilin Voir le message
    ...techniquement le sélecteur ul > li est équivalent à li
    Oui et non, soyons précis :
    • ul > li signifie : les li "descendants directs" de ce ul.
    • li cible "tous les li", où et quels qu'ils soient.

    Certes, ul > li (sans plus de précision) est équivalent à li.

    Mais, selon cette configuration :
    Code html : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    <ul id="menu">
      <li>..... menu 1
        <ul>
          <li>..... sous-menu 1.1</li>
          <li>..... sous-menu 1.2</li>
        </ul>
      </li>
      <li>..... menu 2</li>
    </ul>

    Pour cibler les "bons" <li>, on doit indiquer de quel <ul> on parle :
    • ul#menu > li ne cible QUE les menus (car "descendants directs"), mais PAS les sous-menus.
    • Pour cibler les sous-menus, on peut utiliser ul#menu > li > ul > li (sous-menus de niveau 1), ul#menu ul > li (tous les sous-menu, quel que soit leur niveau, sous-sous-menu,...)
    Dernière modification par Invité ; 06/04/2020 à 14h52.

  8. #8
    Invité
    Invité(e)
    Par défaut
    Cela dit... pour corriger ton code :

    Code JavaScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    "use strict";
    const tree = document.getElementById("navTree");
     
    prepareTree(tree); // remarque : au cas où on peut avoir plusieurs "trees", on passe le "tree" en paramètre des fonctions.
    addListeners(tree);
     
    function prepareTree(tree)
    {
      let tree_elts = tree.querySelectorAll("li");
      tree_elts.forEach( elt => {
        if( elt.querySelector("ul") ) // si on a un sous-menu (présence de ul dans le li)
        {
          elt.classList.add("caret"); // ajoute "caret" au li
          elt.querySelector("ul").classList.add("nested"); // ajoute "nested" au ul enfant du li
        }
      });
    }
     
    function addListeners(tree)
    {
      var togglers = tree.querySelectorAll(".caret");
      togglers.forEach( elt => {
        elt.addEventListener("click", function(event) {
          event.stopPropagation(); // IMPORTANT (stoppe la propagation de l évènement)
          this.querySelector("ul.nested").classList.toggle("active");
          this.classList.toggle("caret-down");
        });
      }); 
    }

  9. #9
    Membre Expert
    Homme Profil pro
    Inscrit en
    Octobre 2011
    Messages
    2 910
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2011
    Messages : 2 910
    Par défaut
    Citation Envoyé par rafoim Voir le message

    Avec mon console.log, je vois que tous les éléments enfants "li" sont ciblés alors que je ne veux cibler que ceux qui sont les enfants directs.
    C'est ce qui est fait, tu as bien les enfants directs mais de tous les ul...

  10. #10
    Membre averti
    Homme Profil pro
    Enseignant
    Inscrit en
    Mars 2013
    Messages
    38
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Service public

    Informations forums :
    Inscription : Mars 2013
    Messages : 38
    Par défaut merci
    Merci bien, je vais chercher comment cibler les "li" du premier niveau de mon arborescence. Je reviendrai chercher votre précieuse aide si je coince trop. En attendant, j'ai mis le sujet sur "résolu" car mon erreur d'interprétation a bien été corrigée.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [Débutant] Création et utilisation d'une treeView
    Par Gonzague54 dans le forum Développement Windows
    Réponses: 1
    Dernier message: 06/09/2019, 17h34
  2. [Plugin][View][TreeView] Création d'une vue.
    Par bitou dans le forum Eclipse Platform
    Réponses: 6
    Dernier message: 20/11/2007, 12h57
  3. Création d'une base avec IbConsole
    Par Lucien dans le forum Outils
    Réponses: 3
    Dernier message: 02/03/2004, 18h34
  4. création d'une batabse .gdb
    Par jejestyle dans le forum Bases de données
    Réponses: 3
    Dernier message: 23/02/2004, 00h29
  5. [BES] Création d'une variable d'environnement
    Par NGI80 dans le forum Autres
    Réponses: 2
    Dernier message: 17/10/2002, 07h31

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo