Matthias Apsel: Vanilla – best practice gesucht

Hallo alle,

ich möchte mich für ein Projekt von JQuery trennen.

Ich habe ein Formular, für das bei jeder Änderung die Aktion "A" ausgelöst werden soll, bei Betätigung eines Buttons einer bestimmten Klasse (von denen es mehrere geben kann) soll jedoch erst die Aktion "B" ausgelöst werden. Meine JQuery-Lösung funktioniert.

do_B = function() {
  // do something;
  do_A();
} 

do_A = function() {
  // do something;
}

$('form').on('click', '.foo', do_B);
// JQuerys 'click' lauscht auch auf Tastatur und Touch
$('form').change(do_A);

Wie würde man dies idealerweise umsetzen? A und B in eine Funktion und beim Aufruf nach event.target schauen? A und B in getrennte Funktionen? Wovon wäre diese Entscheidung abhängig?

Die Seite kann ich leider nicht zeigen.

Bis demnächst
Matthias

--
Du kannst das Projekt SELFHTML unterstützen,
indem du bei Amazon-Einkäufen Amazon smile (Was ist das?) nutzt.

akzeptierte Antworten

  1. @@Matthias Apsel

    $('form').on('click', '.foo', do_B);
    // JQuerys 'click' lauscht auch auf Tastatur und Touch
    $('form').change(do_A);
    

    Wie würde man dies idealerweise umsetzen? A und B in eine Funktion und beim Aufruf nach event.target schauen?

    Das sollte dasselbe tun (mit do_A() und do_B() wie gehabt):

    document.forms[0].addEventListener('click', event => {
      if (event.target.classList.contains('foo') {
        do_B();
      }
    });
    document.forms[0].addEventListener('change', do_A);
    

    A und B in getrennte Funktionen? Wovon wäre diese Entscheidung abhängig?

    Davon, ob B ohne A Sinn hat. Dann:

    do_B = function() {
      // do something;
    } 
    
    do_A = function() {
      // do something;
    }
    
    document.forms[0].addEventListener('click', event => {
      if (event.target.classList.contains('foo') {
        do_B();
        do_A();
      }
    });
    document.forms[0].addEventListener('change', do_A);
    

    🖖 Stay hard! Stay hungry! Stay alive! Stay home!

    --
    Home Office ist so frustierend, weil man jetzt noch viel stärker bemerkt mit wievielen Menschen man zu tun hat, die nicht sinnerfassend lesen können. (@Grantscheam)
    1. Lieber Gunnar,

      document.forms[0].addEventListener('change', do_A);
      

      bist Du sicher, dass es nur das erste Element in document.forms braucht? Ich meine mich zu erinnern, dass $("form") alle <form>-Elemente findet. Dazu müsste man daher über alle Elemente in document.forms iterieren.

      Liebe Grüße

      Felix Riesterer

      1. Hallo Felix Riesterer,

        bist Du sicher, dass es nur das erste Element in document.forms braucht?

        Hab ich nicht deutlich hinzugeschrieben: Es gibt nur ein Form auf der Seite.

        Bis demnächst
        Matthias

        --
        Du kannst das Projekt SELFHTML unterstützen,
        indem du bei Amazon-Einkäufen Amazon smile (Was ist das?) nutzt.
      2. @@Felix Riesterer

        document.forms[0].addEventListener('change', do_A);
        

        bist Du sicher, dass es nur das erste Element in document.forms braucht?

        Wie Matthias sich ausdrückte, ja. („Ich habe ein Formular, für das …“)

        Ich hätte aber korrekter schreiben sollen: Das sollte in deinem Fall dasselbe tun.

        🖖 Stay hard! Stay hungry! Stay alive! Stay home!

        --
        Home Office ist so frustierend, weil man jetzt noch viel stärker bemerkt mit wievielen Menschen man zu tun hat, die nicht sinnerfassend lesen können. (@Grantscheam)
    2. Hallo Gunnar Bittersmann,

      document.forms[0].addEventListener('click', event => {
        if (event.target.classList.contains('foo') {
          do_B();
        }
      });
      document.forms[0].addEventListener('change', do_A);
      

      IE11 kann leider kein =>.

      Bis demnächst
      Matthias

      --
      Du kannst das Projekt SELFHTML unterstützen,
      indem du bei Amazon-Einkäufen Amazon smile (Was ist das?) nutzt.
      1. @@Matthias Apsel

        IE11 kann leider kein =>.

        Na dann mach

        document.forms[0].addEventListener('click', function (event) {
        

        draus (wenn du keinen Transpiler einsetzt).

        🖖 Stay hard! Stay hungry! Stay alive! Stay home!

        --
        Home Office ist so frustierend, weil man jetzt noch viel stärker bemerkt mit wievielen Menschen man zu tun hat, die nicht sinnerfassend lesen können. (@Grantscheam)
        1. Hallo Gunnar Bittersmann,

          Na dann mach

          document.forms[0].addEventListener('click', function (event) {
          

          draus

          Hab ich schon 😉

          Bis demnächst
          Matthias

          --
          Du kannst das Projekt SELFHTML unterstützen,
          indem du bei Amazon-Einkäufen Amazon smile (Was ist das?) nutzt.
  2. Lieber Matthias,

    inzwischen unterstützen alle aktuellen Browser event.target, so dass Du nicht mehr für den IE nach event.srcElement suchen musst.

    let do_A = function (event) {
      let target = event.target; // event.target || event.srcElement für legacy IE
      // ...
    }
    
    let do_b = function (event) {
      let target = event.target;
      // ...
      do_A(event);
    }
    

    Den Eventhandler kann man in Vanilla wie üblich mit addEventListener binden:

    $('form').on('click', '.foo', do_B);
    // JQuerys 'click' lauscht auch auf Tastatur und Touch
    $('form').change(do_A);
    

    Quick & dirty:

    document.querySelectorAll("form").forEach(function (f) {
    
      f.querySelectorAll(".foo").forEach(function (n) {
        n.addEventListener("click", do_B);
      });
    
      f.addEventListener("change", do_A);
    });
    

    Je nach Alter des Browsers kann es sein, dass die von querySelectorAll zurückgegebene Liste kein forEach unterstützt. Da musst Du das Ergebnis erst in ein echtes Array umwandeln, bevor Du mit forEach iterierst.

    Liebe Grüße

    Felix Riesterer

    1. Hallo Felix Riesterer,

      erstmal vielen Dank. Weil du das Alter ansprichst: Ich muss IE11 unterstützen.

      Würden dynamisch hinzukommende Buttons der Klasse foo auch die Funktion B auslösen?

      Bis demnächst
      Matthias

      --
      Du kannst das Projekt SELFHTML unterstützen,
      indem du bei Amazon-Einkäufen Amazon smile (Was ist das?) nutzt.
      1. Lieber Matthias,

        Würden dynamisch hinzukommende Buttons der Klasse foo auch die Funktion B auslösen?

        nein. Die Verteilung der Eventlistener geschieht ja nur einmal. Wenn du aber dynamisch erzeugte später hinzugefügte Buttons unterstützen musst, dann musst Du das Event am <body> verankern:

        document.body.addEventListener("click", function (event) {
        
          let target = event.target || event.srcElement;
        
          if (target.className.match(/\.foo\b/)) {
            do_B(event);
          }
        });
        
        document.body.addEventListener("change", function (event) {
        
          let target = event.target || event.srcElement;
        
          if (target.className.match(/\.foo\b/)) {
            do_A(event);
          }
        });
        

        Ich habe keine Ahnung, ob IE11 classList unterstützt, daher habe ich eine RegExp verwendet.

        Liebe Grüße

        Felix Riesterer

        1. Hi,

            if (target.className.match(/\.foo\b/)) {
          

          Der Punkt im Regex möchte gerne ein b sein (also vor und nach foo eine Wortgrenze). Punkt kommt im Klassennamen nicht vor. Du gehst ja direkt auf's class-Attribut, im Gegensatz zu Matthias, der im Originalposting jQuery benutzt, wo der Punkt dazu da ist, jQuery klarzumachen, daß es ein Klassen-Selektor sein soll.

          cu,
          Andreas a/k/a MudGuard

          1. @@MudGuard

            Der Punkt im Regex möchte gerne ein b sein

            Nö, der RegExp möchte gar nicht da sein. Eine String-Funktion würde es auch tun – wenn man mit classList nicht schon eine Liste hätte.

            🖖 Stay hard! Stay hungry! Stay alive! Stay home!

            --
            Home Office ist so frustierend, weil man jetzt noch viel stärker bemerkt mit wievielen Menschen man zu tun hat, die nicht sinnerfassend lesen können. (@Grantscheam)
            1. Hi,

              Nö, der RegExp möchte gar nicht da sein. Eine String-Funktion würde es auch tun

              Nein, includes ist nicht geeignet, im class-Attribut auf das Vorhandensein der Klasse foo zu prüfen. Nur ein Narr 😉 (pun intended) würde das tun:

              alert("fool".includes("foo"));
              

              cu,
              Andreas a/k/a MudGuard

              1. @@MudGuard

                Nein, includes ist nicht geeignet, im class-Attribut auf das Vorhandensein der Klasse foo zu prüfen. Nur ein Narr 😉 (pun intended) würde das tun:

                alert("fool".includes("foo"));
                

                Foolish me.

                Und der RegExp ist genausowenig geeignet:

                alert("foo-bar".match(/\bfoo\b/));
                

                🖖 Stay hard! Stay hungry! Stay alive! Stay home!

                --
                Home Office ist so frustierend, weil man jetzt noch viel stärker bemerkt mit wievielen Menschen man zu tun hat, die nicht sinnerfassend lesen können. (@Grantscheam)
                1. Hi,

                  Und der RegExp ist genausowenig geeignet:

                  alert("foo-bar".match(/\bfoo\b/));
                  

                  Da bin ich nicht firm genug in Javascript - da es unterschiedliche Implementierungen gibt, was ein word-character ist …

                  cu,
                  Andreas a/k/a MudGuard

                  1. @@MudGuard

                    da es unterschiedliche Implementierungen gibt, was ein word-character ist …

                    Echt? Auch das noch!

                    Ich dachte, word-characters wären [A-Za-z] – was an sich auch schon Unsinn ist; damit ist \b für menschliche Sprachen ungeeignet, die diakritische Zeichen verwenden (von zusätzlichen Buchstaben wie ß und þ ganz abgesehen) – also für alle(?) Sprachen.[1]

                    Das ist doch Müll:

                    console.log('Müll'.match(/\bM\b/)); // Array [ "M" ]
                    console.log('Mull'.match(/\bM\b/)); // null
                    

                    🖖 Stay hard! Stay hungry! Stay alive! Stay home!

                    --
                    Home Office ist so frustierend, weil man jetzt noch viel stärker bemerkt mit wievielen Menschen man zu tun hat, die nicht sinnerfassend lesen können. (@Grantscheam)

                    1. Gibt es irgendeine natürliche Sprache, die das lateinische Alphabet ohne jegliche diakritische Zeichen verwendet? (Selbst im Latein werden doch lange Vokale mit Makron gekennzeichnet.) ↩︎

                    1. Hi,

                      da es unterschiedliche Implementierungen gibt, was ein word-character ist …

                      Echt? Auch das noch!

                      ja. In manchen Sprachen sind word-characters alle Buchstaben, in manchen nur die aus dem ASCII-Bereich, mal gehören die Ziffern (mal nur ASCII, mal alle) dazu, weitere Varianten nicht ausgeschlossen.

                      Ich dachte, word-characters wären [A-Za-z]

                      M.W. gehören die Ziffern 0-9 auch noch mit rein.

                      Englisch?

                      (ok, über die Natürlichkeit könnte man streiten 😉)

                      cu,
                      Andreas a/k/a MudGuard

                      1. @@MudGuard

                        Ich dachte, word-characters wären [A-Za-z]

                        M.W. gehören die Ziffern 0-9 auch noch mit rein.

                        Klar, wegen Wörtern wie H1N1.

                        Gibt es irgendeine natürliche Sprache, die das lateinische Alphabet ohne jegliche diakritische Zeichen verwendet? (Selbst im Latein werden doch lange Vokale mit Makron gekennzeichnet.)

                        Englisch?

                        Das zu glauben wäre naïve. Zoë nickt zustimmend.

                        🖖 Stay hard! Stay hungry! Stay alive! Stay home!

                        --
                        Home Office ist so frustierend, weil man jetzt noch viel stärker bemerkt mit wievielen Menschen man zu tun hat, die nicht sinnerfassend lesen können. (@Grantscheam)
                    2. Hallo Gunnar,

                      Selbst im Latein werden doch lange Vokale mit Makron gekennzeichnet.

                      Aber nur in Latein-Lehrbüchern.

                      (Ich frag mich ja, ob's dem Monsieur Le President recht ist, ein Flatliner zu sein...)

                      Rolf

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

                        Selbst im Latein werden doch lange Vokale mit Makron gekennzeichnet.

                        Aber nur in Latein-Lehrbüchern.

                        Wenn man Latein so schreiben wollen würde wie es damals geschrieben wurde, als es noch geschrieben wurde … damals gab’s noch keine Kleinbuchstaben! 😉

                        🖖 Stay hard! Stay hungry! Stay alive! Stay home!

                        --
                        Home Office ist so frustierend, weil man jetzt noch viel stärker bemerkt mit wievielen Menschen man zu tun hat, die nicht sinnerfassend lesen können. (@Grantscheam)
                        1. Hallo Gunnar,

                          ICHWEISSVNDLEERSTELLENAVCHNICHT

                          Rolf

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

                            ICHWEISSVNDLEERSTELLENAVCHNICHT

                            ICHVVEISSVNDVVVVARNOCHKEINEIGENERBVCHSTABE

                            🖖 Stay hard! Stay hungry! Stay alive! Stay home!

                            --
                            Home Office ist so frustierend, weil man jetzt noch viel stärker bemerkt mit wievielen Menschen man zu tun hat, die nicht sinnerfassend lesen können. (@Grantscheam)
                      2. @@Rolf B

                        Selbst im Latein werden doch lange Vokale mit Makron gekennzeichnet.

                        Aber nur in Latein-Lehrbüchern.

                        Sieht man auch hin und wieder, wenn jemand Russisch zusammen-kopiert-und-kleistert:

                        Ма́льчики, чита́ть уме́ете?[1]

                        Äh, nö, Betonungszeichen gibt’s nur in Russisch-Lehrbüchern.

                        🖖 Stay hard! Stay hungry! Stay alive! Stay home!

                        --
                        Home Office ist so frustierend, weil man jetzt noch viel stärker bemerkt mit wievielen Menschen man zu tun hat, die nicht sinnerfassend lesen können. (@Grantscheam)

                        1. Mascha und der Bär, Folge 55 ab 2:44 ↩︎

                        1. Hallo Gunnar Bittersmann,

                          Äh, nö, Betonungszeichen gibt’s nur in Russisch-Lehrbüchern.

                          die es durchaus auch online geben kann.

                          Bis demnächst
                          Matthias

                          --
                          Du kannst das Projekt SELFHTML unterstützen,
                          indem du bei Amazon-Einkäufen Amazon smile (Was ist das?) nutzt.
                2. @@Gunnar Bittersmann

                  Und der RegExp ist genausowenig geeignet:

                  Wenn man wirklich mit RegExp nach „foo“ in einer whitespace-separierten Liste suchen will (was man in diesem Fall nicht will), müsste man da wohl mit (?:^|\s)foo(?:$|\s) ran.

                  🖖 Stay hard! Stay hungry! Stay alive! Stay home!

                  --
                  Home Office ist so frustierend, weil man jetzt noch viel stärker bemerkt mit wievielen Menschen man zu tun hat, die nicht sinnerfassend lesen können. (@Grantscheam)
        2. @@Felix Riesterer

          Wenn du aber dynamisch erzeugte später hinzugefügte Buttons unterstützen musst, dann musst Du das Event am <body> verankern:

          Nö, musst du nicht. Ich würde das zugehörige form-Element nehmen, nicht wahllos irgendein Element zwischen dem Formular und der Wurzel.

            if (target.className.match(/\.foo\b/)) {
          

          Ich habe keine Ahnung, ob IE11 classList unterstützt, daher habe ich eine RegExp verwendet.

          Es ist einfacher, sich die Ahnung zu verschaffen, als einen RegExp zu verwenden. Das macht nur Probleme. Besonders, wenn der Ausdruck – wie bei dir – falsch ist.

          🖖 Stay hard! Stay hungry! Stay alive! Stay home!

          --
          Home Office ist so frustierend, weil man jetzt noch viel stärker bemerkt mit wievielen Menschen man zu tun hat, die nicht sinnerfassend lesen können. (@Grantscheam)
    2. @@Felix Riesterer

      document.querySelectorAll("form").forEach(function (f) {
      

      Nein, so nicht. Das macht keinen Sinn.Immer noch nicht.

        f.querySelectorAll(".foo").forEach(function (n) {
          n.addEventListener("click", do_B);
        });
      

      Warum das denn und nicht wie gehabt event delegation?

      🖖 Stay hard! Stay hungry! Stay alive! Stay home!

      --
      Home Office ist so frustierend, weil man jetzt noch viel stärker bemerkt mit wievielen Menschen man zu tun hat, die nicht sinnerfassend lesen können. (@Grantscheam)
  3. Hallo Matthias Apsel,

    ich möchte mich für ein Projekt von JQuery trennen.

    Ich glaube, ich möchte mich doch nicht damit umherärgern.

    <button type="button" class="del" title="diese Zeile löschen">
      <svg class="svg-inline--fa fa-minus-square fa-w-14" ></svg>
      <!-- <i class="far fa-minus-square"></i> -->
    </button>
    

    Bei Klick auf den Button ist Firefox der Meinung, event.target sei das svg, IE11 meint event.target sei button.

    Mit JQuery funktioniert es deutlich intuitiver. -meh

    Bis demnächst
    Matthias

    --
    Du kannst das Projekt SELFHTML unterstützen,
    indem du bei Amazon-Einkäufen Amazon smile (Was ist das?) nutzt.
    1. Hallo,

      <button type="button" class="del" title="diese Zeile löschen">
        <svg class="svg-inline--fa fa-minus-square fa-w-14" ></svg>
        <!-- <i class="far fa-minus-square"></i> -->
      </button>
      

      Bei Klick auf den Button ist Firefox der Meinung, event.target sei das svg

      was aber nur dann richtig ist, wenn du direkt auf das Bild klickst. Was ist aber beim Klick neben das Bild, aber immer noch auf den Button? Den Fall müsstest du doch sowieso mit berücksichtigen (es sei denn, das SVG-Bild deckt den Button zu 100% ab).

      IE11 meint event.target sei button.

      Ja, den hättest du dann quasi nebenbei auch noch bedient.

      Mit JQuery funktioniert es deutlich intuitiver. -meh

      Hmm. Die einen sagen so, die anderen so.

      Live long and pros healthy,
       Martin

      --
      Ich stamme aus Ironien, einem Land am sarkastischen Ozean.
    2. @@Matthias Apsel

      Bei Klick auf den Button ist Firefox der Meinung, event.target sei das svg, IE11 meint event.target sei button.

      Du willst also nicht event.target, sondern event.target.closest('button').

      ☞ MDN – Den Polyfill gibt’s da auch gleich mit.

      🖖 Stay hard! Stay hungry! Stay alive! Stay home!

      --
      Home Office ist so frustierend, weil man jetzt noch viel stärker bemerkt mit wievielen Menschen man zu tun hat, die nicht sinnerfassend lesen können. (@Grantscheam)
      1. Hallo Gunnar Bittersmann,

        ☞ MDN – Den Polyfill gibt’s da auch gleich mit.

        Den Polyfill brauche ich auch schon für do_B. Im Moment habe ich so ein Mischmasch zwischen JQuery und Vanilla. Das ist nicht schön.

        Bis demnächst
        Matthias

        --
        Du kannst das Projekt SELFHTML unterstützen,
        indem du bei Amazon-Einkäufen Amazon smile (Was ist das?) nutzt.
    3. Hallo Matthias,

      Ich glaube, ich möchte mich doch nicht damit umherärgern.

      <button type="button" class="del" title="diese Zeile löschen">
        <svg class="svg-inline--fa fa-minus-square fa-w-14" ></svg>
        <!-- <i class="far fa-minus-square"></i> -->
      </button>
      

      Bei Klick auf den Button ist Firefox der Meinung, event.target sei das svg, IE11 meint event.target sei button.

      mit so etwas durfte ich mich auch beschäftigen. Such mal in https://wiki.selfhtml.org/wiki/Benutzer:JürgenB/Drag_and_Drop#Die_drei_Phasen_des_Drag_and_Drop nach der Funktion parent

      Gruß
      Jürgen

    4. Hallo Matthias,

      das ist ein Grundproblem bei den Buttons. Ob Elemente im Inneren eines Buttons als Event Target angesehen werden oder nicht, wird von den Browsern unterschiedlich gehandhabt.

      Einige Browser sehen HTML im Inneren eines Buttons nicht als Event Target und zeigen den Button als Target, andere schon. Da sind sich die Hersteller nicht einig.

      Daher der Bedarf für das .closest('button').

      Hm, Update. Es scheint sich vereinheitlicht zu haben. Ich meine, der Chrome hätte früher immer den Button als event.target gesetzt. Jetzt nicht mehr.

      Rolf

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

        Hm, Update. Es scheint sich vereinheitlicht zu haben. Ich meine, der Chrome hätte früher immer den Button als event.target gesetzt. Jetzt nicht mehr.

        Beide. Firefox und Chrome. Hat sich vor gar nicht so langer Zeit geändert; ich weiss noch, dass ich JS-Code deshalb anpassen musste.

        Freundliche Grüße,
        Christian Kruse

  4. Hallo alle,

    danke für die Motivation.

    Screenshot github commit

    ca. 600 Zeilen schlechtes JQuery entsorgt (u.a. schlecht, weil ich DRY nicht beachtet hatte bzw. nicht einhalten konnte). Jetzt ist es nur noch eine Stelle, an der JQuery verwendet wird.

    Bis demnächst
    Matthias

    --
    Du kannst das Projekt SELFHTML unterstützen,
    indem du bei Amazon-Einkäufen Amazon smile (Was ist das?) nutzt.