Linuchs: classList.remove

Moin,

ich habe eine Liste mit 120 Firmen, deren Branchen als Class hinterlegt sind:

<p class="eisenwaren geraeteverleih reparaturen">Müller & Co</p>

Dazu eine Reihe radio-buttons, mit denen ich eine Branche hervorheben kann:

function toggleClass ( klasse ) {
  alert ( "toggleClass ( " +klasse +")" );
  // Markierungen zuruecksetzen
  arr = document.getElementsByClassName("border_color_red");
  for ( i=0; i<arr.length; i++ ) {
    arr[i].classList.remove("border_color_red");
  }
  // neue Markierungen setzen
  arr = document.getElementsByClassName( klasse );  // alle Firmen, die (auch) diese klasse haben
  for ( i=0; i<arr.length; i++ ) {
    arr[i].classList.add("border_color_red");
  }
}
<p>Branche(n) hervorheben: &nbsp;
<label for="radio_keine">
<input
type      = "radio"
id        = "radio_keine"
name      = "klasse"
value     = "keine"
onchange  = "toggleClass( '_keine_' )"
checked

> keine</label> &nbsp;

Problem: Bei Klick auf "keine" behalten einige Firmen ihre Markierung. Bei Klick auf eine andere Branche bleiben auch Firmen markiert, die nicht dazugehören.

Von 25 markierten und klick auf "keine" bleiben 11 markiert. Ein anderes Mal bleiben von 16 8 übrig. Habe keine Erklärung. Was kann das sein?

Gruß, Linuchs

  1. Verständnisfrage:

    Wenn ich einen radio buttton klicke, müsste das onchange event doch auch bei dem button feuern, dem der focus entzogen wird, es werden ja zwei radio buttons geändert.

    Offenbar feuert aber nur der neu geklickte. Das heisst - anders als bei Checkboxen - kann ich nicht feststellen, wem der focus entzogen wurde.

    Ist das so richtig?

    Linuchs

  2. @@Linuchs

    Habe keine Erklärung.

    Ich habe Fragen:

    Warum Radiobuttons, keine Checkboxen, mit denen man auch mehrere Kategorien gleichzeitig auswählen kann?

    Warum JavaScript, wo das doch mit CSS allein (:checked und +) geht?

    Wo kann man sich denn dein Problem ansehen?

    LLAP 🖖

    --
    „Wir haben deinen numidischen Schreiber aufgegriffen, o Syndicus.“
    „Hat auf dem Forum herumgelungert …“
    (Wachen in Asterix 36: Der Papyrus des Cäsar)
    1. Moin Gunnar,

      Warum Radiobuttons, keine Checkboxen, mit denen man auch mehrere Kategorien gleichzeitig auswählen kann?

      So hatte ich das zunächst. Aber aufgrund des Schleifenfehlers beim Rücksetzen hatte ich da einen Fehler im Konzept vermutet.

      Und tatsächlich ist unklar, ob ich mit einer Checkbox die Treffer erweitere (wie zunächst erwünscht) oder verringere. Also nur die markiere, die alle geforderten Branchen gleichzeitig haben. Dagegen ist der radio button eindeutig.

      Warum JavaScript, wo das doch mit CSS allein (:checked und +) geht?

      Beispiel?

      Wo kann man sich denn dein Problem ansehen?

      http://bfp-forum.de/?code=mus-7b6960

      Gruß, Linuchs

    2. Warum JavaScript, wo das doch mit CSS allein (:checked und +) geht?

      Du meinst sicher mit :checked und ~. Aber auch das funktioniert nur unter der Voraussetzung, dass die hervozuhebenden Elemente im selben Teilbaum wie die Radiobuttons liegen und das in-order. Das ist keine sehr robuste Aussicht, deswegen kann ich den Einsatz von JavaScript hier verteidigen.

      1. @@1unitedpower

        Warum JavaScript, wo das doch mit CSS allein (:checked und +) geht?

        Du meinst sicher mit :checked und ~.

        Ja, klar.

        Aber auch das funktioniert nur unter der Voraussetzung, dass die hervozuhebenden Elemente im selben Teilbaum wie die Radiobuttons liegen und das in-order. Das ist keine sehr robuste Aussicht

        Das wäre nicht das Problem, IMHO.

        deswegen kann ich den Einsatz von JavaScript hier verteidigen.

        Was für JavaScript spricht: Barrierefreiheit. Wenn man die entsprechenden Elemente nicht nur visuell keinzeichnen möchte, sondern auch für Screenreader, muss man dafür Attribute vergeben. (aria-selected für hervorgehobene? aria-hidden für die anderen?)

        Und außerdem ist da ja noch der WebKit Adjacent/General Sibling & Pseudo Class Bug.

        LLAP 🖖

        --
        „Wir haben deinen numidischen Schreiber aufgegriffen, o Syndicus.“
        „Hat auf dem Forum herumgelungert …“
        (Wachen in Asterix 36: Der Papyrus des Cäsar)
        1. Was für JavaScript spricht: Barrierefreiheit. Wenn man die entsprechenden Elemente nicht nur visuell keinzeichnen möchte, sondern auch für Screenreader, muss man dafür Attribute vergeben. (aria-selected für hervorgehobene? aria-hidden für die anderen?)

          Das ist problematisch, denn mit der Hervorhebung einer Branche fügt der Nutzer die Aussteller noch nicht zu seiner persönlichen Auswahlliste hinzu.

          Um WAI-ARIA hier sinnvoll einzusetzen zu können müssten imho. erst die richtigen Voraussetzungen geschaffen werden. Aktuell besteht die Auswahlliste leider noch nicht einmal aus semantischen HTML-Elementen. Zum Beispiel sind die Auswahlmöglichkeiten an Ausstellern nicht als Checkboxen ausgezeichnet.

          1. @@1unitedpower

            Aktuell besteht die Auswahlliste leider noch nicht einmal aus semantischen HTML-Elementen. Zum Beispiel sind die Auswahlmöglichkeiten an Ausstellern nicht als Checkboxen ausgezeichnet.

            Ja. Man kann Linuchs nicht nachsagen, dass er hier gegebene Hinweise beachten würde. Da kann man sich das Antworten auch gleich sparen. Dann kann er sich aber auch das Fragen sparen.

            LLAP 🖖

            --
            „Wir haben deinen numidischen Schreiber aufgegriffen, o Syndicus.“
            „Hat auf dem Forum herumgelungert …“
            (Wachen in Asterix 36: Der Papyrus des Cäsar)
            1. Hallo Gunnar,

              Aktuell besteht die Auswahlliste leider noch nicht einmal aus semantischen HTML-Elementen. Zum Beispiel sind die Auswahlmöglichkeiten an Ausstellern nicht als Checkboxen ausgezeichnet.

              Ja. Man kann Linuchs nicht nachsagen, dass er hier gegebene Hinweise beachten würde. Da kann man sich das Antworten auch gleich sparen. Dann kann er sich aber auch das Fragen sparen.

              Ich denke, 120 Positionen mit der TAB-Taste durchzuhecheln macht keinen Sinn. Die Idee stammt ja noch aus der DOS-Zeit, als es noch keine Mäuse gab.

              Diese Seite ist gedacht für Messebesucher. Dort habe ich noch nie einen blinden, tauben Rollstuhlfahrer gesehen. Also in diesem Fall darf die Webseite barriere-behaftet sein.

              Wenn ich die Seite für unsere Diskussionsrunde verlinke, bedeutet das nicht, dass die Seite für die Öffentlichkeit bestimmt ist.

              Linuchs

              1. @@Linuchs

                Diese Seite ist gedacht für Messebesucher. Dort habe ich noch nie einen blinden, tauben Rollstuhlfahrer gesehen. Also in diesem Fall darf die Webseite barriere-behaftet sein.

                Henne-Ei-Problem?

                „Auf unserer SPA hab ich noch nie einen Nutzer gesehen, der JavaScript deaktiviert hat.“

                LLAP 🖖

                --
                „Wir haben deinen numidischen Schreiber aufgegriffen, o Syndicus.“
                „Hat auf dem Forum herumgelungert …“
                (Wachen in Asterix 36: Der Papyrus des Cäsar)
  3.   arr = document.getElementsByClassName("border_color_red");
      for ( i=0; i<arr.length; i++ ) {
        arr[i].classList.remove("border_color_red");
      }
    

    getElementsByClassName() gibt dir eine "live" HTMLCollection zurück. Das heißt, wenn du die entsprechende Klasse von einem Element löschst, dann ist dieses Element auch sofort nicht mehr Teil der HTMLCollection. Dadurch verringert sich dann auch die Länge der Liste und die Elemente hinter dem gelöschten Element rücken auf. Mit anderen Worten: Deine Schleife zählt falsch. Alternativ könntest du in einer Schleife immer so lange das erste Element löschen bis die Liste letztendlich leer ist:

    while (arr.length > 0) {
        arr[0].classList.remove("border_color_red");
    }
    

    Oder du könntest die HTMLCollection in ein "richtiges" Array konvertieren:

    var elements = [].slice.call(arr);
    

    Mit modernem JavaScript geht das wesentlich kürzer und schöner:

    var elements = [...arr];
    
    1.   arr = document.getElementsByClassName("border_color_red");
        for ( i=0; i<arr.length; i++ ) {
          arr[i].classList.remove("border_color_red");
        }
      

      Mit anderen Worten: Deine Schleife zählt falsch.

      Ja, ich habe mir das i zeigen lassen, das läuft nicht bis zum Ende. Also wird arr.length nicht nur beim Start der Schleife einmal festgelegt, sondern bei jedem Durchlauf neu. Das wusste ich nicht.

      Rückwärts geht's aber:

        i = arr.length;
        while ( i > 0 ) {
          i--;
          arr[i].classList.remove("border_color_red");
        }
      

      Linuchs