Javascript: Select-All Funktion in einer html Tabelle

  • Hallo zusammen,

    ich habe eine HTML-Seite mit einer generierten Tabelle, d.h. der Inhalt bzw. die Zeilen werden durch eine Funktion (Daten aus einer DB auslesen)

    gefüllt.

    Jede Zeile beinhaltet u.a. Checkboxes.

    Die letzte Spalte in einer Zeile ist ein "Select-All"-Checkbox.

    Ich möchte, wenn ich ein Hacken in den "Select-All"-Checkbox setzte, dann werden alle Checkboxes in dieser Zeile selektiert.

    Momentan werden eher alle Checkboxes selektiert, weil ich mit der ID suche. die identisch für alle Zeile ist.


    Ich suche eine Lösung um die RowIndex des selektierten Checkbox zu ermitteln und zu prüfen, nur wenn Checkbox in dieser Zeile ist dann einchecken.

    Ich habe lange rumprobiert, aber vergeblich...

    z.B.

    var table = $('#xxxxtable').DataTable();

    ..

    const row = document.getElementById('select_all');

    var rowID = row.tabIndex ;

    ...

    this.parentNode.parentNode.rowIndex



    ...

    var colValue= this.dataItem($(e.currentTarget).closest("tr"));



    Ich wäre dankbar wenn jemand hier weiterhelfen kann.


    Danke

  • Hast du vieleicht mal ein Link zur Seirte ? Oder kannst du eine Beispiel Tabelle erstellen ?

    Konsole öffnen , auf elements klicken , dann ganz oben auf den <html> klicken , rechts klick und outerHTML anklicken.

    Dann Codepen öffnen und in den html Fenster reinkopieren.


    Dann können wir deinen erstellten html Code sehen und wahrscheinlich besser helfen, aber einen Link zur Seite wäre am besten.

  • closest() ist schon mal ein guter Ansatz.

    Zunächst aber definierst Du ein Array mit allen CheckAll-Boxen der Tabelle:

    JavaScript
    1. var _checkAll = document.querySelectorAll('table td .checkall');

    Dann definierst Du für jede gefundene CheckAll-Box einen Listener auf das Click-Event:

    JavaScript
    1. _checkAll.forEach( i => {
    2. i.addEventListener( 'click', function(e) {
    3.     // here comes the magic...
    4. });
    5. });

    Darin sammelst Du dann alle Standard-Checkboxes:

    JavaScript
    1. _all = this.closest('tr').querySelectorAll('input[type="checkbox"]:not(.checkall)')

    Jetzt verpasst Du denen den Checked-Status, den auch die entsprechende CheckAll-Box der Zeile hat:

    JavaScript
    1. _all.forEach( c => { c.checked = this.checked; });

    thats all...



    Hinweis:

    Da querySelectorAll() eine NodeList und kein Array zurückgibt, benötigt man für die M$ Browser eine kleine Anpassung, da diese kein forEach() für eine NideList kennen. Es gibt verschiedene Ansätze, für mich funktioniert folgendes Prinzip ganz gut:

    JavaScript
    1. // returns NodeList
    2. var _checkAll = document.querySelectorAll('table td .checkall');
    3. // returns array
    4. var _checkAll = Array.prototype.slice.call( document.querySelectorAll('table td .checkall') );

    und schon kann forEach() auch bei M$ Produkten angewendet werden. Produktiv mache ich das natürlich über eine externe Methode, hier nur als Veranschaulichung.


    Zusammengefasst kannst Du das hier testen: https://codepen.io/PHProcks/pen/MWWEvKV

  • Hallo zusammen,

    vielen Dank für Eure Tipps und Hinweise.

    Diese haben mir geholfen!

    Folgende Implementierung funktioniert:

    Es werden nur die Checkboxes, die zur Class=dunkel gehören und die sich in der aktuellen Zeile befinden, selektiert.

    Danke!

  • Nutze besser addEventListener, anstatt onclick. Mit onclick überschreibst Du das Standardverhalten, was nicht immer gewünscht ist. addEventListener erweitert das Event um Deine Funktion, wie der Name bereits suggeriert. Das Standardverhalten kann man dort auch unterbinden, wenn man es denn muss/will.


    Außerdem hast Du in jeder <tr> ein <td> mit einem <input> der gleichen id, das ist nicht konform. Die meisten Browser verzeihen Dir das, aber es tut nicht weh, es richtig zu machen.


    Mich wundert auch, dass das hier sauber funktionieren soll:

    JavaScript
    1. var checkboxes = source.closest('tr').querySelectorAll('table td .dunkel');

    Das dürfte so gar nicht funktionieren, weil der querySelectorAll() meiner Info nach relativ zum Objekt startet, d.h. in Deinem Fall bei dem übergeordneten <tr> der Checkbox. Dann ist aber table in dem Pfad nicht korrekt und er dürfte keine Elemente finden.

  • Das hat so wirklich funktioniert.

    Ich kann zwar nicht genau erklären aber so habe ich das interpretiert:

    querySelectorAll('table td .dunkel') heisst es alle Spalten die, die class=dunkel haben.

    Da es vorher  source.closest(tr) steht, dann wird eher nur in der Zeile gesucht, wo sich die checkbox befindet.

    Also genau was ich gesucht habe.

  • Das ist prima und das Verhalten von querySelectorAll hast Du soweit auch richtig verstanden, aber der angegebene Pfad passt nicht zu dem von Dir geposteten HTML. Deshalb wundert es mich, dass das funktioniert. Tut es aber, habe es eben selber getestet. :/


    Was ich meinte, nur zur Information:

    JavaScript
    1. source.closest('tr').querySelectorAll('table td .dunkel');

    Du suchst ab dem übergeordneten <tr> nach dem Pfad table td .dunkel, demnach müsste es unterhalb von <tr> eine <table> geben, gibt es aber nicht. Deshalb wundere ich mich, dass das funktioniert.

    ;)

  • Du suchst ab dem übergeordneten <tr> nach dem Pfad table td .dunkel, demnach müsste es unterhalb von <tr> eine <table> geben, gibt es aber nicht. Deshalb wundere ich mich, dass das funktioniert.

    Hier eine Erklärung dafür: mdn: Element.querySelectorAll()

    Das standard Verhalten von Element.querySelectorAll() ist es, dass, nur der letzte Teil des Selektors überprüft wird.


    source.closest('tr').querySelectorAll('table td .dunkel'); ist als das gleiche wie: source.closest('tr').querySelectorAll('.dunkel');


    Wenn man den Kompletten Selektor berücksichtigt haben möchte gibt es die Pseudoklasse :scope.
    source.closest('tr').querySelectorAll(':scope table td .dunkel');
    würde kein Element selektieren.

  • Ok, ganz so tragisch ist das scheinbar nicht, denn er bleibt zumindest auch ohne :scope im aktuellen Knoten:

    HTML
    1. <div class="wrapper">
    2. <div class="test">
    3. <span>test</span>
    4. </div>
    5. <span>foobar</span>
    6. </div>
    JavaScript
    1. var _test = document.querySelector( '.test' );
    2. console.log( _test.querySelectorAll('.wrapper span').length ); // Ausgabe: 1

    d.h. er ignoriert in diesem Falle zwar den .wrapper, aber er sammelt zumindest schon mal keine <span> außerhalb des Scope.

    Ein Problem tritt erst dann auf, wenn ich weitere Elemente unterhalb des Knoten an beliebiger Stelle habe, die auf das Matching passen:

    HTML
    1. <div class="wrapper">
    2. <div class="test">
    3. <span>test</span>
    4. <div><span>test+</span></div>
    5. </div>
    6. <span>foobar</span>
    7. </div>
    JavaScript
    1. var _test = document.querySelector( '.test' );
    2. console.log( _test.querySelectorAll('.wrapper span').length ); // Ausgabe: 2

    Wenn ich nun den Selector entsprechend anpasse, zeigt sich das Verhalten, wie beschrieben:

    JavaScript
    1. console.log( _test.querySelectorAll('.wrapper .test > span').length ); // Ausgabe: 0
    2. console.log( _test.querySelectorAll(':scope wrapper > .test > span').length ); // Ausgabe: 0
    3. console.log( _test.querySelectorAll(':scope .test > span').length ); // Ausgabe: 0
    4. console.log( _test.querySelectorAll(':scope > span').length ); // Ausgabe: 1
    5. console.log( _test.querySelectorAll(':scope span').length ); // Ausgabe: 2

    Was bedeutet, dass :scope tatsächlich eine Referenz auf die Node ist, über die querySelectorAll() angewendet wird.


    Die Fälle, wo das jetzt wirklich zur Stolperfalle wird, sind dadurch zwar etwas geringer, aber man sollte sie dennoch nicht außer Acht lassen.

    Da es keinen sinnigen Grund gibt, querySelectorAll() auf eine Node anzuwenden, wenn man diese nicht als Basis des Selector annimmt, sollte man sich angewöhnen in so einem Falle immer :scope zu verwenden.


    Alternative

    Man baut sich seinen eigene Selector auf Basis von querySelectorAll().