ebody: jQuery - klick auf dynamisch erstellte Elemente funktioniert nicht

Hallo,

https://codepen.io/anon/pen/QVrWBV

Bei Klick auf #element, soll ein neues Element eingefügt werden anstelle von #element. "Element erstellen" verschwindet und "Äpfel" wird angezeigt. Jetzt soll bei einem Klick auf "Äpfel" das Element #birnen eingefügt werden. Das passiert aber nicht.

1. Weil das DOM das Element #aepfel nicht kennt?

2. Muss man für so etwas wirklich etwas wie MutationObserver verwenden?

Gruß ebody

<div id="elementBox">
  <div id="element">Element erstellen</div>
</div>
$(document).ready(function() {
  
  $("#element").click(function(){
    $( "#elementBox" ).html( "<div id=\"aepfel\">Äpfel</div>");
  });

  $("#aepfel").click(function(){
    $( "#elementBox" ).html( "<div id=\"birnen\">Birnen</div>");
  });

  $("#birnen").click(function(){
    $( "#elementBox" ).html( "<div id=\"aepfel\">Äpfel</div>");
  });

});
  1. hallo

    1. Weil das DOM das Element #aepfel nicht kennt?

    Du speicherst ja kein Objekt, das deinen Klickevent enthält.

    2. Muss man für so etwas wirklich etwas wie MutationObserver verwenden?

    Event-Delegation wäre hier angebracht.

  2. Tach!

    https://codepen.io/anon/pen/QVrWBV

    Bei Klick auf #element, soll ein neues Element eingefügt werden anstelle von #element.

    Dann musst du das aber auch so tun. Der Code fügt stattdessen ein Kind-Element in #element ein.

    "Element erstellen" verschwindet und "Äpfel" wird angezeigt.

    Der Textnode in #element wird ausgetauscht durch das #aepfel-Element.

    Jetzt soll bei einem Klick auf "Äpfel" das Element #birnen eingefügt werden. Das passiert aber nicht.

    Das kann nicht passieren, weil #aepfel keinen Eventhandler hat. Die Eventhandler-Zuweisung fand statt, als #aepfel noch gar nicht existierte. $('#aepfel') hat eine leere Menge geliefert, da können keine Events angehängt werden. Das Event-Anhängen blieb ohne Auswirkung und still, aufgrund der jQuery-Arbeitsweise, beim Nichtsfinden still und leise nichts zu machen. Mit Vanilla-JS hätte der Zugriff auf das nicht vorhandene Element einen Fehler ausgelöst.

    Das Click-Event gelangt deshalb aufgrund des Bubbling weiter nach oben zum #element und das ersetzt seinen Inhalt mit dem #aepfel.

    1. Weil das DOM das Element #aepfel nicht kennt?

    Das kannst du selbst prüfen, wenn du die Entwicklertools des Browsers verwendest. Da sieht man aber auch, dass kein Event registriert ist.

    2. Muss man für so etwas wirklich etwas wie MutationObserver verwenden?

    Nö, man muss es nur richtig machen. Besonders die zeitliche Reihenfolge, wann man was zur Verfügung hat und auch erst dann bearbeiten kann.

    dedlfix.

  3. Hallo

    Bei Klick auf #element, soll ein neues Element eingefügt werden anstelle von #element. "Element erstellen" verschwindet und "Äpfel" wird angezeigt. Jetzt soll bei einem Klick auf "Äpfel" das Element #birnen eingefügt werden.

    1. Weil das DOM das Element #aepfel nicht kennt?

    In der Tat. Zu dem Zeitpunkt, an dem ready feuert, existieren die Elemente #aepfel und #birnen nicht.

    $(document).ready(function() {
      
      $("#element").click(function(){
        $( "#elementBox" ).html( "<div id=\"aepfel\">Äpfel</div>");
        $("#aepfel").click(function(){
          $( "#elementBox" ).html( "<div id=\"birnen\">Birnen</div>");
          $("#birnen").click(function(){
            $( "#elementBox" ).html( "<div id=\"aepfel\">Äpfel</div>");
          });
        });
      });
    });
    

    Ich würde erwarten, dass die Registrierung der Eventhandler nach der Erstellung des jeweiligen DOM-Elements zum gewünschten Ergebnis führt. Ich habe das aber selbst nicht getestet.

    Tschö, Auge

    --
    Eine Kerze stand [auf dem Abort] bereit, und der Almanach des vergangenen Jahres hing an einer Schnur. Die Herausgeber kannten ihre Leser und druckten den Almanach auf weiches, dünnes Papier.
    Kleine freie Männer von Terry Pratchett
  4. @@ebody

      <div id="element">Element erstellen</div>
    
      $("#element").click(function(){
    

    Das kann so nicht funktionieren. Bei manchen Nutzer passiert da beim Click was; aber andere können da überhaupt nicht clicken. Ein div-Element kann per se nicht mit der Tastatur angewählt werden.

    Merke: Niemals nicht-interaktive Elemente als Target von Click-Events verwenden!

    Wo immer eine Aktion auf einer Seite ausgeführt wird, muss das Element ein button sein. Wenn es ein Link zu einer anderen Stelle ist, ist a-Element mit href-Attribut richtig.

    In diesem Fall also:

      <button id="element">Element erstellen</button>
    

    Den Button kannst du mit CSS wie gewünscht stylen.

    LLAP 🖖

    PS: Es ist ärgerlich, dass niemand der drei bereits gekommenen Antworten auf diesen Fehler hingewiesen hat.

    --
    „Wer durch Wissen und Erfahrung der Klügere ist, der sollte nicht nachgeben. Und nicht aufgeben.“ —Kurt Weidemann
  5. Hallo,

    vielen Dank an alle. So hat es bei mir jetzt funktioniert:

    $(document).ready(function() {
    
    		$( "#elementBox" ).append( "<div id=\"aepfel\">Äpfel</div>");
    		$( "#elementBox" ).append( "<div id=\"birnen\">Birnen</div>");
    		$("#aepfel").css("display","none");
    		$("#birnen").css("display","none");
    
    		  $("#element").click(function(){
    			$("#element").remove();
    			$("#aepfel").css("display","block");
    		  });
    
    		  $("#aepfel").click(function(){
    			$("#aepfel").css("display","none");
    			$("#birnen").css("display","block");
    		  });
    
    		  $("#birnen").click(function(){
    			$("#birnen").css("display","none");
    			$("#aepfel").css("display","block");
    		  });
    		  
    		});
    
    });
    
    	<div id="elementBox">
    		<div id="element">Element erstellen</div>
    	</div>
    

    Gruß ebody

    1. Hallo ebody,

      man weiß nicht, auf welchen Einsatzzweck dieses Codefragment hinausläuft. Es ist ja offenbar eine Demo noch ohne praktischen Wert. Aber die genutzte Technik ist für eine offene Webseite untauglich. Gunnar hat hinreichend erklärt, wieso.

      Das Escapen der Anführungszeichen kannst Du Dir sparen wenn Du " und ' nutzt. Das kann HTML-Fragmente im Code lesbarer machen.

      	$("#elementBox").append("<div id='aepfel'>Äpfel</div>");
      

      Und deine Einrückstrategie müsstest Du ggf. überarbeiten oder strenger beachten. Deine Eventhandler für Äpfel und Birnen sind als solche nicht zu erkennen.

      Deswegen mein Minus. Nimms's nicht persönlich. Aber der Code ist nicht empfehlenswert. Um eine bessere Strategie empfehlen zu können, müsste man mehr darüber wissen, was eigentlich beabsichtigt ist.

      Rolf

      --
      sumpsi - posui - clusi
      1. Hallo Rolf,

        konstruktives Feedback ist immer hilfreich, daher danke und kein Problem.

        Den "Einsatzzweck" oder eher die Frage und was ich wissen möchte, habe ich in meinem 1. Beitrag beschrieben. Da es nur ein Beispielcode ist, habe ich auch nicht so auf das Einrücken u.a. geachtet. Es ging mir eher darum zu zeigen, dass das...

        Bei Klick auf #element, soll ein neues Element eingefügt werden anstelle von #element. "Element erstellen" verschwindet und "Äpfel" wird angezeigt. Jetzt soll bei einem Klick auf "Äpfel" das Element #birnen eingefügt werden.

        ...jetzt funktioniert.

        Deine Eventhandler für Äpfel und Birnen sind als solche nicht zu erkennen.

        Hier bin ich mir nicht ganz sicher was du meinst. Die Eventhandler sind doch im Code: Eventhandler

        Gruß ebody

        1. Hallo ebody,

          dass das...jetzt funktioniert.

          Ja klar. Technisch tut es das, was Du in diesem Experiment erreichen wolltest. Aber worauf wir hinauswollten, ist dies: Es ist in dieser Form nicht für das Web und seine diversen Geräte und Benutzer geeignet. Um empfehlen zu können, was besser geeignet ist, wäre die Kenntnis nützlich, auf welches Ziel Du mit deinem Experiment hinarbeitest.

          Mit der Nichterkennbarkeit meinte ich

                $("#element").click(function(){
          			$("#element").remove();
          			$("#aepfel").css("display","block");
          		  });
          
          		  $("#aepfel").click(function(){
          			$("#aepfel").css("display","none");
          			$("#birnen").css("display","block");
          		  });
          
          		  $("#birnen").click(function(){
          			$("#birnen").css("display","none");
          			$("#aepfel").css("display","block");
          		  });
          

          versus

                $("#element").click(function(){
             			 $("#element").remove();
                   $("#aepfel").css("display","block");
          		  });
          
          		  $("#aepfel").click(function(){
             			$("#aepfel").css("display","none");
          		   	$("#birnen").css("display","block");
          		  });
          
          		  $("#birnen").click(function(){
             			$("#birnen").css("display","none");
             			$("#aepfel").css("display","block");
          		  });
          

          Rolf

          --
          sumpsi - posui - clusi
          1. Hi,

            ich bin mir jetzt nicht ganz sicher, was Du damit meinst:

            Es ist in dieser Form nicht für das Web und seine diversen Geräte und Benutzer geeignet.

            Es geht einfach nur um diese Funktion. HTML Elemente hinzuzufügen und diese per Klick ein und ausblenden zu können. Ich habe es in verschiedenen Browsern und auf dem Smartphone, netbook u.a. getestet und es funktioniert.

            Da ich keinen Mac, kein Iphone u.a. habe, kann ich es hier leider nicht testen. Oder spielst du auch auf das Thema button an und das es noch nicht ausgereift ist und man noch am Script einiges optimieren kann?

            Ich bin wirklich dankbar für die Hilfe und Hinweise hier, ich lerne sehr viel dazu und Du antwortest auch bisher immer sachlich, normal, sogar eher freundlich.

            Nicht geeignet...

            sagt aber aus, dass es nicht funktioniert, dass man befürchten muss, dass das alles Quatsch ist, was man macht und kein Nutzer meine Anwendung nutzen und bedienen könnte. Man bekommt das Gefühl und den Eindruck vermittelt, man sollte es am besten lassen.

            So viele Webseiten und auch erfolgreiche Webseiten enthalten mit Sicherheit auch Fehler, Opimierungspotential etc. und dennoch laufen und funktionieren sie. Diese Webprogrammierer machen es einfach und wo es wäre auch schade, wenn sie es nicht machen, weil Sie Fehler machen.

            Ich möchte einfach mal meine Meinung hier gerade sagen, weil mir das hier im Forum und im Internet generell auffällt, dass durch Antworten, deren Formulierungen, Aussagen u.a. viele abgeschreckt werden. Dabei sollte doch das Ziel sein zu helfen, zu motivieren etc.

            Gruß ebody

            1. Hallo ebody,

              ja, es ging um das click auf einem nicht interaktiven Element. Das ist und bleibt ungeeignet. Weil es NUR Maus-/Touchbedienbar ist. Es gibt aber noch andere Bedientechniken. SelfHtml hat Bedienbarkeit relativ hoch auf der Prioritätenliste, eben WEIL viele nicht wissen oder nicht glauben wollen, wie wichtig das ist. Darum reiben wir das mit der Drahtbürste ein, wenn es nötig ist. Aber wenn die Bedienung für den eigentlichen Anwendungszweck ohnehin anders läuft, dann ignoriere meinen Einwand.

              Das Minus am Beitrag bleibt trotzdem, als Etikett für unvorbereitete Leser aus den Weiten des Web. Da Du anonym hier bist, tut's ja nicht weh 😂

              Gunnars Bug-Hinweis bezieht sich auf den Umstand, dass jQuery show/hide das relativ neue hidden-Attribut von HTML nicht beachtet. Wenn Du dieses Attribut nicht nutzt, ist dieser Hinweis ebenfalls nicht relevant.

              Aber, einfach um mal einen anderen Ansatz zu zeigen, das direkte Manipulieren von Sichtbarkeiten ist nicht immer die beste Lösung. Es ist auch unklar, weshalb Du die Elemente für Äpfel und Birnen erst im JS hinzufügst und nicht direkt im HTML vorsiehst. Solange es nur zwei Elemente sind, geht es auch so, plus Bedienbarkeit, und mit mehr CSS als JS Magic:

              <h1>Klickeritis-Test</h1>
              <div id="elementBox">
                 <button type="button" id="element">Element erstellen</button>
                 <button type="button" id="äpfel">Äpfel</button>
                 <button type="button" id="birnen">Birnen</button>
              </div>
              
              #elementBox:not(.clicked) :not(#element),
              #elementBox.clicked #element,
              #elementBox.clicked.äpfel :not(#äpfel),
              #elementBox.clicked:not(.äpfel) #äpfel {
                display:none;
              }
              
              #elementBox button {
                border: none;
                background-color: transparent;
                font: inherit;
              }
              
              $(function() {
                 focusVisibleElementInBox();
              
                 $("#elementBox").click(function() {
                    $(this).addClass("clicked").toggleClass("äpfel");
                    focusVisibleElementInBox();
                 });
              });
              
              function focusVisibleElementInBox() {
                 $("#elementBox button").filter(":visible").focus();
              }
              

              Das JS setzt nach eine Klasse clicked auf die elementBox (nur einmal, dafür sorgt jQuery bzw. die classList des DOM), und schaltet die Klasse äpfel hin und her (Ja, äpfel. Die Jahre des geschienten Alphabets sind auch in CSS vorüber. Nur der CSS Highlighter im Forum weiß das nicht).

              Das CSS prüft die 4 Fälle, in denen ein Element auszublenden ist, und setzt dafür display:none. Das ist besser als es andersrum mit display:block zu machen, weil es eine MENGE Varianten geben, welchen display-Wert ein sichtbares Element hat.

              • Elementbox nicht geklickt, alles darin außer #element
              • Elementbox geklickt, darin das #element Element
              • Geklickt plus äpfel-Klasse, darin alles was nicht #äpfel ist
              • Geklickt ohne äpfel-Klasse, darin alles was #äpfel ist

              Und es sind jetzt Buttons. Sie sehen nur nicht wie Buttons aus. Das einzig verräterische ist der Outline-Rahmen drumherum, der das Element mit dem Fokus anzeigt. Das KÖNNTE man mit der outline-Eigenschaft im CSS abschalten, aber das stört die Bedienbarkeit. Dieser visuelle Bug ist ein FEATURE!

              Ob dieses Konstrukt für deinen realen Anwendungsfall taugt ist natürlich eine andere Frage. Den kennen wir ja nicht 😀

              Rolf

              --
              sumpsi - posui - clusi
              1. @@Rolf B

                Und es sind jetzt Buttons.

                Und wenn denn die Buttons noch aria-expanded-Attribute trügen …

                ☞ Inclusive Components: Collapsible Sections

                LLAP 🖖

                --
                „Wer durch Wissen und Erfahrung der Klügere ist, der sollte nicht nachgeben. Und nicht aufgeben.“ —Kurt Weidemann
              2. Tach!

                SelfHtml hat Bedienbarkeit relativ hoch auf der Prioritätenliste, eben WEIL viele nicht wissen oder nicht glauben wollen, wie wichtig das ist. Darum reiben wir das mit der Drahtbürste ein, wenn es nötig ist.

                Das Problem daran ist, dass die Drahtbürste wehtut. Da wir aber keine Vorgesetzten der Probleminhaber sind, können wir nur Vorschläge geben und keine Anweisungen. Vorschläge sollten aber nicht wehtun, damit sie bereitwillig angenommen werden. Deswegen sähe ich lieber eine hautverträgliche Emulsion zur Anwendung kommen als eine Drahtbürste.

                dedlfix.

                1. @@dedlfix

                  Deswegen sähe ich lieber eine hautverträgliche Emulsion zur Anwendung kommen als eine Drahtbürste.

                  Wäre schön, wenn du diese nicht nur gern zur Anwendung kommen sähest, sondern sie auch zu diesem Zwecke selbst austeiltest, damit das nicht immer an mir hängenbleibt.

                  LLAP 🖖

                  --
                  „Wer durch Wissen und Erfahrung der Klügere ist, der sollte nicht nachgeben. Und nicht aufgeben.“ —Kurt Weidemann
                  1. Tach!

                    Deswegen sähe ich lieber eine hautverträgliche Emulsion zur Anwendung kommen als eine Drahtbürste.

                    Wäre schön, wenn du diese nicht nur gern zur Anwendung kommen sähest, sondern sie auch zu diesem Zwecke selbst austeiltest, damit das nicht immer an mir hängenbleibt.

                    Tja, manchmal schaue ich da nicht so genau hin. Aber da fällt mir einen deiner Grundsätze ein, dass man das Frontend den Frontendexperten überlassen sollte. Also Arbeitsteilung oder All-in-one-Einzelkämpfer? 🤔

                    dedlfix.

        2. @@ebody

          ...jetzt funktioniert.

          Nein. Solange etwas nicht mit Tastatur funktioniert, kann man nicht sagen, dass es funktioniert.

          Die Eventhandler sind doch im Code: Eventhandler

          Nicht, dass das übersehen wird: <div id="aepfel">Äpfel</div> und <div id="aepfel">Birnen</div> dürfen auch keine divs sein.

          LLAP 🖖

          --
          „Wer durch Wissen und Erfahrung der Klügere ist, der sollte nicht nachgeben. Und nicht aufgeben.“ —Kurt Weidemann
    2. @@ebody

      vielen Dank an alle.

      Wenn du die dir gegebenen Hinweise auch umsetzen würdest – das wäre ein Dank!

      So hat es bei mir jetzt funktioniert:

      		<div id="element">Element erstellen</div>
      

      Bei dir hat das (vielleicht) funktioniert. Bei anderen funktioniert das nicht!

      Baust du die Seite für dich oder für andere, die sie nutzen sollen? Vermutlich letzteres; also so bauen, dass andere sie nutzen können.

      		$( "#elementBox" ).append( "<div id=\"aepfel\">Äpfel</div>");
      		$( "#elementBox" ).append( "<div id=\"birnen\">Birnen</div>");
      

      Es gibt einfache und doppelte Anführungszeichen. Wenn man beide einsetzt, lassen sich Escape-Orgien vermeiden.

      			$("#aepfel").css("display","none");
      			$("#birnen").css("display","block");
      

      Gibt es einen Grund, warum du jQuery einsetzt, aber es nicht verwendest? Hier speziell die Methoden hide(), show() und toggle()?

      Mal abgesehen davon, dass show() und toggle() einen ziemlich üblen Bug haben und die jQuery-Entwickler keine Anstalten machen, diesen zu fixen. 😡

      LLAP 🖖

      --
      „Wer durch Wissen und Erfahrung der Klügere ist, der sollte nicht nachgeben. Und nicht aufgeben.“ —Kurt Weidemann
      1. Hi,

        das ist nur ein kleiner Beispielcode. Es ist meist so, dass ich einen größeren Code habe und sich dann Probleme/Fragen ergeben und es deutlich einfacher und übersichtlicher ist, dann ein möglichst schlankes Beispiel zu zeigen, welches das Problem/die Frage deutlich macht.

        Ich habe Deinen Hinweis bzgl. der Verwendung von Button schon mitgenommen und so etwas ist auch hilfreich, aber ich fand es jetzt nicht notwendig den Beispielcode deswegen zu ändern.

        Ist das kein jQuery?

        $("#aepfel").css("display","none");
        $("#birnen").css("display","block");
        

        Und wenn show() und toggle() einen üblen Bug haben, ist es doch sogar besser, dass ich diesen Code verwendet habe (auch wenn ich nichts vom Bug wusste) ;-) hide(), show(), toggle() sind mir bekannt, aber für meinen gesamten Code hat css() besser gepasst.

        Gruß ebody

        1. @@ebody

          Ich habe Deinen Hinweis bzgl. der Verwendung von Button schon mitgenommen und so etwas ist auch hilfreich, aber ich fand es jetzt nicht notwendig den Beispielcode deswegen zu ändern.

          Naja, es wäre schön zu wissen, dass gegebene Hinweise bei dir auch ankommen.

          Beispielcode sollte möglichst korrekt sein, weil auch andere Mitleser sich daran ein Beispiel nehmen.

          Ist das kein jQuery?

          $("#aepfel").css("display","none");
          $("#birnen").css("display","block");
          

          Kein gutes.

          Du willst Elemente anzeigen bzw. verstecken. hide(), show(), toggle() sind sprechende Namen dafür.

          Und wenn show() und toggle() einen üblen Bug haben, ist es doch sogar besser, dass ich diesen Code verwendet habe

          Nein. Dein Code hat denselben Bug.

          LLAP 🖖

          --
          „Wer durch Wissen und Erfahrung der Klügere ist, der sollte nicht nachgeben. Und nicht aufgeben.“ —Kurt Weidemann
          1. Hallo Gunnar Bittersmann,

            Nein. Dein Code hat denselben Bug.

            Lass ihn doch nicht raten …

            Bis demnächst
            Matthias

            --
            Rosen sind rot.
            1. @@Matthias Apsel

              Nein. Dein Code hat denselben Bug.

              Lass ihn doch nicht raten …

              Welches Rätsel hinterlässt meine Bug-Beschreibung?

              Ein Element, das sichtbar gemacht werden soll, darf nicht mehr das Attribut hidden haben.

              Sonst wird es auch u.U. gar nicht sichbar, wenn man .show() (oder .css("display","block")) darauf anwendet.

              LLAP 🖖

              --
              „Wer durch Wissen und Erfahrung der Klügere ist, der sollte nicht nachgeben. Und nicht aufgeben.“ —Kurt Weidemann
              1. Hallo Gunnar,

                Ich hab's ihm ja schon gesteckt...

                Und wenn Matthias schon keine Lust hatte, deinem Link zu folgen - dann hatte ebody die bestimmt auch nicht 😜

                Rolf

                --
                sumpsi - posui - clusi
                1. Hallo Rolf B,

                  Und wenn Matthias schon keine Lust hatte, deinem Link zu folgen - dann hatte ebody die bestimmt auch nicht 😜

                  Vor allem hatte ich keine Veranlassung. Ich wusste ja, was Gunnar meint.

                  Bis demnächst
                  Matthias

                  --
                  Rosen sind rot.