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 :

Désactiver onclick sur les enfants de l'élément cliqué


Sujet :

JavaScript

  1. #1
    Membre chevronné
    Homme Profil pro
    Analyse système
    Inscrit en
    Mai 2014
    Messages
    393
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Arménie

    Informations professionnelles :
    Activité : Analyse système
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Mai 2014
    Messages : 393
    Par défaut Désactiver onclick sur les enfants de l'élément cliqué
    Bonsoir,

    Je cherche à créer des listes dépliantes avec un effet amusant. Je propose l'exemple ci-dessous.
    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
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    <!doctype html>
    <html>
      <head>
        <meta charset="utf-8">
          <style>
            .deplier { list-style-type: '- '; }
            .plier { list-style-type: '+ '; }
            .deplier ul {
              height: 100%;
              transition: 0.3s;
            }
            .plier ul {
              height: 1px;
              transform: scale(0.1,0.01);
              transition: 0.3s;
            }
          </style>
      </head>
      <body>
        <ul>
          <li class="plier">Les jours
            <ul>
              <li><a href="j1.html">Lundi</a>
              <li><a href="j2.html">Mardi</a>
              <li><a href="j3.html">Mercredi</a>
              <li><a href="j4.html">Jeudi</a>
            </ul>
     
          <li class="plier">Les années
            <ul>
              <li><a href="a1.html">2016</a>
              <li><a href="a2.html">2015</a>
            </ul>
          <li class="plier">Les mois
            <ul>
              <li><a href="m1.html">Janvier</a>
              <li><a href="m2.html">Février</a>
              <li><a href="m3.html">Mars</a>
            </ul>
        </ul>
        <script>
          plier=function() {
            for (var i=0;i<document.getElementsByClassName("plier").length;i++) {
              document.getElementsByClassName("plier")[i].addEventListener('click', function() {
                this.className="deplier";
                deplier();
              });
            }
          };
          deplier=function() {
            for (var i=0;i<document.getElementsByClassName("deplier").length;i++) {
              document.getElementsByClassName("deplier")[i].addEventListener('click', function() {
                this.className="plier";
                plier();
              });
            }
          };
          plier();
        </script>
      </body>
    </html>


    Dans cet exemple, si on clique sur un lien, par exemple sur "mardi", la liste se referme. Or, je voudrais qu'elle reste dépliée, qu'elle ne se replie que si on clique sur "Les jours". J'ai bien trouvé une solution, mais je me demande qu'elle est la bonne façon de procéder, selon vous.

    Merci par avance pour vos réponses.

  2. #2
    Expert confirmé
    Avatar de Watilin
    Homme Profil pro
    En recherche d'emploi
    Inscrit en
    Juin 2010
    Messages
    3 099
    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 099
    Par défaut
    La technique qui convient le mieux dans ton cas, c’est celle qu’on appelle la délégation d’évènement. En gros tu ne mets qu’un seul gestionnaire d’évènement, sur l’ancêtre commun à tous les éléments que tu veux gérer (en l’occurence la première <ul>), et tu agis en fonction de l’évènement passé en paramètre. Dans le code que tu as donné, tu ne gères pas ce paramètre.

    La propriété target de l’évènement t’indique quel élément a reçu le clic en premier. Voici un exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    document.querySelector('ul').addEventListener('click', function (ev) {
      console.log(ev.target);
    });
    La FAQ JavaScript – Les cours JavaScript
    Touche F12 = la console → l’outil indispensable pour développer en JavaScript !

  3. #3
    Modérateur

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

    Informations forums :
    Inscription : Janvier 2011
    Messages : 17 208
    Par défaut
    Bonjour,
    une petite remarque complémentaire, tu vas droit dans le mur car à chaque click sur un élément tu lui ajoutes un nouvel « listener », c'est sans fin...

    Tu aurais aussi avantage à utiliser un toggle de la classe via le CSS.

    [EDIT]
    Dans cet exemple, si on clique sur un lien, par exemple sur "mardi", la liste se referme.
    enlève moi d'un doute, après avoir cliqué sur le lien ta page est donc bien remplacée ?

  4. #4
    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 Watilin
    Salut,

    Sujet intéressant et je vois qu'il y a des effets... J'ai testé et au bout d'un moment ça ralenti énormément (ça bloque un certain temps...). Je pense que c'est lié à la remarque de NoSmoking...

    Sinon ne serait-ce pas une bonne idée d'ajouter un listener seulement au "+" et "-" ?

    Mais bon ce que propose Watilin doit être mieux je pense...

  5. #5
    Membre chevronné
    Homme Profil pro
    Analyse système
    Inscrit en
    Mai 2014
    Messages
    393
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Arménie

    Informations professionnelles :
    Activité : Analyse système
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Mai 2014
    Messages : 393
    Par défaut
    Bonsoir,

    C'est amusant, la solution que j'ai mis en oeuvre et que je vous présenterai bientôt est différente de celles que vous me proposez.

    @ NoSmoking :
    enlève moi d'un doute, après avoir cliqué sur le lien ta page est donc bien remplacée ?
    La page est bien remplacée, mais on peut y revenir en cliquant sur le bouton "Reculer d'une page" du navigateur.
    Tu aurais aussi avantage à utiliser un toggle de la classe via le CSS.
    Je vais me documenter et essayer cette solution.

    @ Watilin :
    Là, j'ai un peu plus de mal à comprendre...

  6. #6
    Membre chevronné
    Homme Profil pro
    Analyse système
    Inscrit en
    Mai 2014
    Messages
    393
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Arménie

    Informations professionnelles :
    Activité : Analyse système
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Mai 2014
    Messages : 393
    Par défaut
    Bonsoir,

    @ Beginner :
    Sinon ne serait-ce pas une bonne idée d'ajouter un listener seulement au "+" et "-" ?
    Là non plus, je ne comprends pas.

  7. #7
    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
    Tout d'abord n’oublie pas la remarque de NoSmoking, je pense qu'il a raison il y a un problème... Comme je disais : j'ai testé et au bout d'un moment ça ralenti énormément (ça bloque un certain temps...).

    Oui car là cela ajoute des listener chaque fois que les fonctions plier() et deplier() sont exécutées...

    Citation Envoyé par eleydet Voir le message
    Bonsoir,

    @ Beginner :

    Là non plus, je ne comprends pas.
    Ben actuellement tu ajoutes des listener aux éléments qui ont la class plier ou deplier (et cela se répercutent à leur enfants) alors je me demandais si ce serait une bonne idée d'ajouter un listener seulement aux caractères "+" et "-", d'ailleurs certains mettent des images à la place... Comme ça le pliage et dépliage ne se fait qu'aux cliques sur ces "+" et "-"...

    Mais bon, comme je disais, ce que propose Watilin doit être mieux je pense... Car c'est plus polyvalent...

  8. #8
    Expert confirmé
    Avatar de Watilin
    Homme Profil pro
    En recherche d'emploi
    Inscrit en
    Juin 2010
    Messages
    3 099
    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 099
    Par défaut
    Les « + » et « - » sont des ajouts CSS list-style-type, un peu comme les pseudo-éléments ::before et ::after. Ils ne sont pas directement manipulables par script.

    Pour apporter des précisions sur la technique de la délégation, tu as donc un unique listener qui reçoit un évènement en paramètre, et tu utilises la propriété target de ce dernier. Cette target, tu dois examiner sa classe. Si c’est "plier" tu la changes en "deplier", et réciproquement.

    C’est plus clair ?
    La FAQ JavaScript – Les cours JavaScript
    Touche F12 = la console → l’outil indispensable pour développer en JavaScript !

  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 Watilin Voir le message
    Les « + » et « - » sont des ajouts CSS list-style-type, un peu comme les pseudo-éléments ::before et ::after. Ils ne sont pas directement manipulables par script.
    Ok mais on pourrait mettre ces carartères dans des span par exemple mais bon pas la peine c'est moins bien de toute façon que la solution que tu proposes...

    Citation Envoyé par Watilin Voir le message
    Pour apporter des précisions sur la technique de la délégation, tu as donc un unique listener qui reçoit un évènement en paramètre, et tu utilises la propriété target de ce dernier. Cette target, tu dois examiner sa classe. Si c’est "plier" tu la changes en "deplier", et réciproquement.

    C’est plus clair ?
    Personnellement, c'est comme ça que je l'avais compris d'ailleurs j'ai testé ici (ça sera peut-être plus clair avec un exemple...) : http://jsbin.com/xibulijobi/1/edit?js,console,output...

    C'est plus court et plus simple en plus...

  10. #10
    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

  11. #11
    Membre chevronné
    Homme Profil pro
    Analyse système
    Inscrit en
    Mai 2014
    Messages
    393
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Arménie

    Informations professionnelles :
    Activité : Analyse système
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Mai 2014
    Messages : 393
    Par défaut
    Bonsoir,

    Merci beaucoup pour vos commentaires. Pour ma part, je n'ai pas fini d'étudier ce sujet. J'avais écrit :
    C'est amusant, la solution que j'ai mis en oeuvre et que je vous présenterai bientôt est différente de celles que vous me proposez.
    Il est temps que je vous montre cette autre solution.
    Code : 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
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    <!doctype html>
    <html>
      <head>
        <meta charset="utf-8">
          <style>
            .deplier { list-style-type: '- '; }
            .plier { list-style-type: '+ '; }
            .deplier ul {
              height: 100%;
              transition: 0.3s;
            }
            .plier ul {
              height: 1px;
              transform: scale(0.1,0.01);
              transition: 0.3s;
            }
          </style>
      </head>
      <body>
        <ul>
          <li class="plier">Les jours
            <ul>
              <li><a href="j1.html">Lundi</a>
              <li><a href="j2.html">Mardi</a>
              <li><a href="j3.html">Mercredi</a>
              <li><a href="j4.html">Jeudi</a>
            </ul>
     
          <li class="plier">Les années
            <ul>
              <li><a href="a1.html">2016</a>
              <li><a href="a2.html">2015</a>
            </ul>
          <li class="plier">Les mois
            <ul>
              <li><a href="m1.html">Janvier</a>
              <li><a href="m2.html">Février</a>
              <li><a href="m3.html">Mars</a>
            </ul>
        </ul>
        <script>
          for (var i=0;i<document.getElementsByClassName("plier").length;i++) {
            document.getElementsByClassName("plier")[i].addEventListener('click', function(e) {    
              if (this.className=="deplier") { if(e.target===this) this.className="plier"; }
              else this.className="deplier"
            });
          }
        </script>
      </body>
    </html>

  12. #12
    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
    Moi aussi ce sujet m'intéresse, je devais m'y mettre...

    J'ai testé ta solution ici : http://jsbin.com/favusaqawu/edit?html,output

    Cela rejoint un peu ce que j'ai posté sauf que je n'utilise qu'un seul listener et pour le test j'avais aussi pensé utiliser className au début mais j'ai changé d'avis et j'ai utilisé classList pour faire un truc plus général (qui permet d'utiliser d'autres class en plus de plier et deplier).

  13. #13
    Membre chevronné
    Homme Profil pro
    Analyse système
    Inscrit en
    Mai 2014
    Messages
    393
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Arménie

    Informations professionnelles :
    Activité : Analyse système
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Mai 2014
    Messages : 393
    Par défaut
    Bonsoir,

    Beginner a écrit :
    Ces solutions utilisent quelque chose du genre input type="checkbox", c'est à dire, selon mon avis, ce que je nomme une "pirouette classique" pour parvenir à ses fins. Puisqu'on se passe de JavaScript, le site fonctionne même si l'option JavaScript du navigateur est désactivée. Soit on se passe de JavaScript et on met en oeuvre cette pirouette, soit on opte pour Javascript...

  14. #14
    Expert confirmé
    Avatar de Watilin
    Homme Profil pro
    En recherche d'emploi
    Inscrit en
    Juin 2010
    Messages
    3 099
    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 099
    Par défaut
    Personnellement je trouve ça plutôt élégant. En tant qu’utilisateur de NoScript, je ne peux que valider une fonctionnalité dynamique qui fonctionne sans JavaScript.
    La FAQ JavaScript – Les cours JavaScript
    Touche F12 = la console → l’outil indispensable pour développer en JavaScript !

  15. #15
    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
    Oui j'ai aussi remarqué qu'il y avait des input type="checkbox", il fallait y penser... C'est plus difficile de se passer du JS et peut-être impossible dans certains cas où on voudrait aller plus loin dans les fonctionnalités...

  16. #16
    Modérateur

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

    Informations forums :
    Inscription : Janvier 2011
    Messages : 17 208
    Par défaut
    @eleydet : concernant ton code
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    for (var i = 0; i < document.getElementsByClassName('plier').length; i++) {
        document.getElementsByClassName('plier') [i].addEventListener('click', function (e) {
            if (this.className == 'deplier') {
                if (e.target === this) this.className = 'plier';
            } 
            else this.className = 'deplier'
        });
    }
    • tu aurais tout intérêt à mettre en cache les éléments plutôt que de rappeler la méthode à chaque itération ;
    • lorsque tu ajoutes un « listerner » à un élément il est inutile de tester e.target === this ;
    • cela ne marchera pas si tu décides d'avoir un ou des éléments dépliés au départ ;
    • optionnel : si plusieures classes doivent être appliqués aux éléments il serait préférable de passeer par les classList, comme réalisé par Beginner..

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    var elements = document.querySelectorAll('.plier , .deplier');
    var i,
    nb = elements.length;
    for (i = 0; i < nb; i += 1) {
        elements[i].addEventListener('click', function (e) {
            if (this.className === 'deplier') {
                this.className = 'plier';
            } 
            else {
                this.className = 'deplier'
            }
        });
    }
    @Beginner. , Watilin :
    Que pensez-vous des solutions uniquement en CSS ?
    je n'y vois qu'un inconvénient, c'est l'ajout d'élément au HTML sémantiquement pas forcément les bienvenus, et j'ai d'ailleurs proposé cette approche dans Galerie au clic sans JavaScript en utilisant des <input type="radio"> qui ouvrent également pas mal de solutions.

  17. #17
    Membre chevronné
    Homme Profil pro
    Analyse système
    Inscrit en
    Mai 2014
    Messages
    393
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Arménie

    Informations professionnelles :
    Activité : Analyse système
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Mai 2014
    Messages : 393
    Par défaut
    Bonjour,

    Envoyé par NoSmoking :
    tu aurais tout intérêt à mettre en cache les éléments plutôt que de rappeler la méthode à chaque itération ;
    Bien vu, cela simplifie le code.

    lorsque tu ajoutes un « listerner » à un élément il est inutile de tester e.target === this ;
    Là, je conteste. Il s'agit d'une solution à mon problème de départ : Désactiver le clic sur les éléments enfants.

    cela ne marchera pas si tu décides d'avoir un ou des éléments dépliés au départ ;
    Bien vu! En fait, la liste devrait être toujours dépliée si le JavaScript est désactivé. Dans le cas contraire, elle pourrait être pliée ou dépliée au départ, selon ce que l'auteur décide.

    optionnel : si plusieurs classes doivent être appliqués aux éléments il serait préférable de passer par les classList, comme réalisé par Beginner...
    Il serait préférable... A mon avis, tout dépend du contexte.

    je n'y vois qu'un inconvénient, c'est l'ajout d'élément au HTML sémantiquement pas forcément les bienvenus,
    J'ajoute que s'il est possible de créer un tableau sans balise <table>, ce n'est pas le cas avec un <input type="radio"> ou avec un <input type="checkbox">.
    Code css : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    #div_transformee_en_tableau {
      display: table;
    }

  18. #18
    Modérateur

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

    Informations forums :
    Inscription : Janvier 2011
    Messages : 17 208
    Par défaut
    Là, je conteste. Il s'agit d'une solution à mon problème de départ : Désactiver le clic sur les éléments enfants.
    effectivement j'avais perdu de vue ce point !

    Il serait préférable... A mon avis, tout dépend du contexte.
    Au final j'aurais, sans utiliser les classList sur ce coup rendant un code plus verbeux
    Code : 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
    var elements = document.querySelectorAll('.plier , .deplier');
    var i, nb = elements.length;
    for (i = 0; i < nb; i += 1) {
        elements[i].addEventListener('click', function (e) {
            if (e.target === this) {
                var cn = this.className;
                if (cn.indexOf('deplier') >- 1) {
                    cn = cn.replace('deplier', 'plier')
                } 
                else {
                    cn = cn.replace('plier', 'deplier')
                }
                this.className = cn;
            }
        });
    }
    J'ajoute que s'il est possible de créer un tableau sans balise <table>,...
    ne confondons pas présentation et contenu et c'est ce que l'on pourrait reprocher à cette méthode c'est l'ajout d'élément non « réellement » concernés mais la machine est en route pour les effets simples et rapides à mettre en oeuvre, on n'a pas toujours besoin de javascript dans les pages.

  19. #19
    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 NoSmoking Voir le message
    @Beginner. , Watilin :
    je n'y vois qu'un inconvénient, c'est l'ajout d'élément au HTML sémantiquement pas forcément les bienvenus, et j'ai d'ailleurs proposé cette approche dans Galerie au clic sans JavaScript en utilisant des <input type="radio"> qui ouvrent également pas mal de solutions.
    Ok et merci pour l'article.

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

Discussions similaires

  1. Réponses: 12
    Dernier message: 01/02/2015, 15h34
  2. [JDOM] Parsage : comment boucler sur les enfants d'un noeud ?
    Par Nelieru dans le forum Format d'échange (XML, JSON...)
    Réponses: 9
    Dernier message: 12/02/2009, 16h28
  3. Réponses: 2
    Dernier message: 27/01/2009, 13h47
  4. [XPath] test d'existence de noeud avec conditions sur les enfants
    Par MasterOfChakhaL dans le forum XSL/XSLT/XPATH
    Réponses: 6
    Dernier message: 11/04/2007, 10h42
  5. Méthode pour supprimer tous les enfants d'un élément
    Par Pymm dans le forum Général JavaScript
    Réponses: 6
    Dernier message: 10/05/2005, 12h10

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