Pit: onclick auf dynamisch hinzugefügte ID

Hallo,

geht so ein Kontrukt grundsätzlich nicht oder ist einfach ein Fehler drin?

    $('#myDel').on('click', function(){
        $('#myVan' + ' .myButton').html("<span id='TDel'>Wirklich löschen?<span>");
    });


    $('#TDel').on('click', function(){
		console.log(this.id);
        $("#formDel").submit();
    });

Pit

  1. Tach!

    geht so ein Kontrukt grundsätzlich nicht oder ist einfach ein Fehler drin?

        $('#myDel').on('click', function(){
            $('#myVan' + ' .myButton').html("<span id='TDel'>Wirklich löschen?<span>");
        });
    
    
        $('#TDel').on('click', function(){
    		console.log(this.id);
            $("#formDel").submit();
        });
    
    

    Du musst die zeitliche Reihenfolge beachten. Wenn das Element mit der ID TDel erst im Click-Eventhandler von myDel erstellt wird, kann auch erst danach eine Zuweisung eines Event-Handlers erfolgreich sein. In deinem Code gibt $('#TDel') eine leere Menge zurück, und das on() kann da nichts hinzufügen.

    dedlfix.

    1. Hi dedlfix,

      verstehe, danke. Aber wie löst man so einen gordischen Knoten denn auf? Kann ich den Eventhandler mit kin die $('#myDel').on('click', function(){ - Funktion aufnehmen?

      Pit

      1. Hallo Pit,

        du machst das bitte im konkreten Fall NICHT so. Statt eines span füge einen Button hinzu, mit type="submit".

        Wenn #myVan bereits im #formDel Form drin liegt, reicht das schon. Andernfalls musst Du dem Button mit dem form='formDel' Attribut noch sagen, welches Form er submitten soll.

        Auf einen Klick-Handler für den Button kannst Du dann verzichten, und wenn Du das Design eines Button nicht willst, dann style den Button so, wie Du das span gestyled hast.

        Und - wenn Du keinen bestimmten Grund für deine Schreibweise hast, der aus dem geposteten Code nicht ersichtlich ist - dann kannst Du statt '#myVan' + ' .mybutton' auch kurz '#myVan .mybutton' schreiben.


        Andererseits ist das Problem, das Du hier hattest, natürlich durchaus häufig. Die ansynchrone Natur von JavaScript hat schon viele in den Wahnsinn getrieben.

        Möglichkeit 1: der html() Setter liefert Dir ein Wrapped Set auf den hinzugefügten Span (glaub ich jedenfalls) und damit solltest Du problemlos ein .on('click', ...); hinten anhängen können.

        Der Code ist rot, damit jeder, der ihn ggf. kopieren will, sofort sieht dass das für das gewählte Szenario nicht best-practice ist.

        $('#myDel').on('click', function() {
              $('#myVan' + ' .myButton')
                 .html("<span id='TDel'>Wirklich löschen?<span>")
                 .on("click", function() {
                    console.log(this.id);
                    $("#formDel").submit();
                 });
        });
        

        Die andere Möglichkeit ist, einfach auf $('myVan') einen Klick-Handler zu legen und ihn dort zu lassen. Die .on() Methode kennt eine Variante mit 3 Parametern, in der der 2. Parameter als Filter dient. Damit kannst Du den Klick-Handler an passender Stelle im DOM verankern, aber nur die Klicks auf die Elemente verarbeiten, die auf deinen Selektor passen.

        $('#myDel').on('click', function() {
              $('#myVan .myButton')
                 .html("<span id='TDel'>Wirklich löschen?<span>")
        });
        $('#myVan .myButton').on('click', '#TDel', function() {
           $("#formDel").submit();
        });
        

        Rolf

        --
        sumpsi - posui - clusi
        1. Ich habe mal beide Varianten verfiddelt:

          https://jsfiddle.net/f9k6jged/

          Rolf

          --
          sumpsi - posui - clusi
          1. Ich habe mal beide Varianten verfiddelt:

            https://jsfiddle.net/f9k6jged/

            Sehr cool! Dank Dir,

            Pit

        2. Hallo Rolf,

          du machst das bitte im konkreten Fall NICHT so. Statt eines span füge einen Button hinzu, mit type="submit".

          Stimmt, das passt besser.

          Wenn #myVan bereits im #formDel Form drin liegt, reicht das schon. Andernfalls musst Du dem Button mit dem form='formDel' Attribut noch sagen, welches Form er submitten soll.

          Ja, muß ich dem Button mitteilen...

          Andererseits ist das Problem, das Du hier hattest, natürlich durchaus häufig. Die ansynchrone Natur von JavaScript hat schon viele in den Wahnsinn getrieben.

          Beruhig mich zwar nur sehr bedingt, aber ok... 😀

          Möglichkeit 1: der html() Setter liefert Dir ein Wrapped Set auf den hinzugefügten Span (glaub ich jedenfalls) und damit solltest Du problemlos ein .on('click', ...); hinten anhängen können.

          Der Code ist rot, damit jeder, der ihn ggf. kopieren will, sofort sieht dass das für das gewählte Szenario nicht best-practice ist.

          $('#myDel').on('click', function() {
                $('#myVan' + ' .myButton')
                   .html("<span id='TDel'>Wirklich löschen?<span>")
                   .on("click", function() {
                      console.log(this.id);
                      $("#formDel").submit();
                   });
          });
          

          Die andere Möglichkeit ist, einfach auf $('myVan') einen Klick-Handler zu legen und ihn dort zu lassen. Die .on() Methode kennt eine Variante mit 3 Parametern, in der der 2. Parameter als Filter dient. Damit kannst Du den Klick-Handler an passender Stelle im DOM verankern, aber nur die Klicks auf die Elemente verarbeiten, die auf deinen Selektor passen.

          $('#myDel').on('click', function() {
                $('#myVan .myButton')
                   .html("<span id='TDel'>Wirklich löschen?<span>")
          });
          $('#myVan .myButton').on('click', '#TDel', function() {
             $("#formDel").submit();
          });
          

          Mal schauen, ob das bei mir funktioniert. Ich werds mal umsetzen, vielen Dank für Deine Hilfe!

          Pit

          1. Hallo Rolf,

            $('#myDel').on('click', function() {
                  $('#myVan .myButton')
                     .html("<span id='TDel'>Wirklich löschen?<span>")
            });
            $('#myVan .myButton').on('click', '#TDel', function() {
               $("#formDel").submit();
            });
            

            Mal schauen, ob das bei mir funktioniert. Ich werds mal umsetzen, vielen Dank für Deine Hilfe!

            Jetzt hab ichs. Die erste Methode hat bei mir leider das Formular sofort abgeschockt, ich habs nicht herausgefunden, was da falsch lief.

            Die 2.Methode hingegen hat von vorneherein sauber funktioniert.

            Vielen Dank für Deine Mühe,

            Pit

  2. Hi,

    Wirklich löschen?

    sieht eher nach confirm() aus. Den return value kannst Du unmittelbar nutzen, false verhindert, true erlaubt bspw. ein submit. MfG

    1. Hi,

      Wirklich löschen?

      sieht eher nach confirm() aus. Den return value kannst Du unmittelbar nutzen, false verhindert, true erlaubt bspw. ein submit. MfG

      Ja, ist ein bischen so, wie confirm(), aber an dieser Stelle ist es bereits der confirmklick, insofern passt es dann wider.

      Pit

  3. Hi, es gibt auch noch eine andere Variante die hier noch nicht erwähnt wurde:

    $(document).on("click", "#myDel", function(e) {
      //code
    });
    

    Die on-Funktionsparameter sind hier Eventtyp, ein CSS-Selektor für gewollte Elemente und der eigentliche Eventhandler.

    Intern passiert folgendes: document bekommt einen Eventhandler von jQuery. Bei jedem Click auf der Seite wird irgendwann (falls nicht durch andere Eventhandler event.stopPropagation() aufgerufen wird) jener Eventhandler ausgeführt. Dieser Eventhandler guckt dann ob das Click-Event von einem Element kommt auf den der CSS-Selektor passt. Wenn ja, wird der obige Eventhandler ausgeführt.

    Das hat Vor- und Nachteile, hier mal 2 wichtige: Vorteil: der Eventhandler greift auch bei Elementen die erst später hinzugefügt werden. Nachteil: in diesem Fall wird der jQuery-interne Eventhandler bei jedem Click ausgeführt (es seiden oben erwähntes stopPropagation() wird ausgeführt)

    Natürlich gilt das nicht nur für $(document) sondern für alle Elemente. Mal angenommen du hast eine Liste bei der Einträge dynamisch hinzugefügt werden und da je Eintrag auch ein Löschbutton dabei ist:

    <ul id="dynamic-entries">
       <li>Eintrag <button class="delete">Löschen</li>
    </ul>
    

    Dann kann man an Stelle von document auch gleich auf #dynamic-entries gehen. Das bedeutet dann, dass der jQuery-interne Eventhandler nur aufgerufen wird, wenn auf dieses oder ein Element in #dynamic-entries geclickt und stopPropagation nicht aufgerufen wurde.

    Vollständigkeitshalber: Das Ganze ist nicht direkt an jQuery gebunden, das geht auch mit "reinem Javascript". Für mehr Informationen darüber sind gute Stichworte event bubbling und event delegation.

    MfG

  4. @@Pit

    geht so ein Kontrukt grundsätzlich nicht oder ist einfach ein Fehler drin?

        $('#myDel').on('click', function(){
            $('#myVan' + ' .myButton').html("<span id='TDel'>Wirklich löschen?<span>");
        });
    
    
        $('#TDel').on('click', function(){
    		console.log(this.id);
            $("#formDel").submit();
        });
    
    

    Es geht grundsätzlich nicht.

    $('#myVan .myButton')[1] ist das jQuery-Objekt zu einem button-Element, nehme ich an? Dann wird im Firefox der Eventhandler des inneren spans nie ausgeführt, sondern die Aktion, die auf dem button-Element liegt. ☞ Codepen
    Das ist auch bei jQuery so. ☞ Codepen
    Safari und Chrome führen beide Aktionen aus: die des spans und die des buttons.

    Ansonsten ist es grundsätzlich falsch, Eventhandler für nicht-interaktive Elemente (span, div, …) zu registrieren. (Event delegation mal außenvorgelassen.) Ein großer Teil der Nutzer kann das mit Tastatur überhaupt nicht bedienen.

    Merke: Niemals nicht-interaktive Elemente als Target für click-Events vorsehen! click-Events ausschließlich für interaktive Elemente wie a, button, input u.ä.

    LLAP 🖖

    --
    “When UX doesn’t consider all users, shouldn’t it be known as ‘Some User Experience’ or... SUX? #a11y” —Billy Gregory

    1. Warum verkettest du da zwei Stringkonstanten anstatt gleich eine Stringkonstante hinzuschreiben? ↩︎