Ingo: Tabellensortierung - wo ist der Fehler....?

problematische Seite

Hallo ihr Lieben!

Ich verzweifle gerade an einer simplen Tabellensortierung...

Wenn man auf HERSTELLER klickt, klappt alles wunderbar - man kann die Tabelle auf / Absteigens sortieren.... Wenn man aber TITEL anklickt, sortiert es einmal die Daten aufsteigend - danach passiert nichts mehr - klickt man davor wieder auf HERSTELLER, funktioniert die aufsteigende Sortierung erneut, absteigend ist jedoch scheinbar unmöglich umzusetzen...

Hier der Code meines Files - ich bin für jede Hilfe wirklich sehr dankbar...

<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>DSP Liste 2024</title>
<style>#myInput {
  background-image: url('/css/searchicon.png'); /* Add a search icon to input */
  background-position: 10px 12px; /* Position the search icon */
  background-repeat: no-repeat; /* Do not repeat the icon image */
  width: 100%; /* Full-width */
  font-size: 16px; /* Increase font-size */
  padding: 12px 20px 12px 40px; /* Add some padding */
  border: 1px solid #ddd; /* Add a grey border */
  margin-bottom: 12px; /* Add some space below the input */
}

#myTable {
  border-collapse: collapse; /* Collapse borders */
  width: 100%; /* Full-width */
  border: 1px solid #ddd; /* Add a grey border */
  font-size: 18px; /* Increase font-size */
}

#myTable th, #myTable td {
  text-align: left; /* Left-align text */
  padding: 12px; /* Add padding */
}

#myTable tr {
  /* Add a bottom border to all table rows */
  border-bottom: 1px solid #ddd; 
}

#myTable tr.header, #myTable tr:hover {
  /* Add a grey background color to the table header and on hover */
  background-color: #f1f1f1;
	
	/* Tabellenkopf festsetzen */ 
table#myTable thead { 
 position: sticky; 
 inset-block-start: 0; 
 user-select: none; 
} 

/* Hintergrund Tabellenkopf */ 
table#myTable > thead > tr { 
 background-color: rgba(255, 174, 94, 0.8); 
} 

table#myTable > thead > tr > th:hover { 
 background-color: #FFAE5E; 
 cursor: pointer; 
} 

/* Die Spalten der Tabelle anpassen */ 
table#myTable, 
table#myTable > thead > tr > th, 
table#myTable > tbody > tr > td { 
 border: Solid 1px #888888; 
 padding: 5px 8px 5px 8px; 
 color: #000000; 
} 

/* Spalte in der Tabelle von der Sortierung ausschließen */ 
table#myTable > thead > tr > td { 
 border: Solid 1px #888888; 
 padding: 5px 8px 5px 8px; 
 color: #000000; 
 font-weight: bold; 
 text-align: center; 
} 

/* Den Hintergrund zeilenweise einfärben */ 
table#myTable > tbody > tr:nth-child(even) { 
 background-color: #FFFFFF; 
} 

table#myTable > tbody > tr:nth-child(odd) { 
 background-color: #FFD2A6; 
} 

/* Pfeil nach oben */ 
.upArrow::after { 
 content: "\2191"; 
 color: #FFFFFF; 
 text-shadow: 1px 1px 0px #000000; 
 position: absolute; 
} 

/* Pfeil nach unten */ 
.dnArrow::after { 
 content: "\2193"; 
 color: #FFFFFF; 
 text-shadow: 1px 1px 0px #000000; 
 position: absolute; 
} 
}</style>
	<script>
function myFunction() {
  // Declare variables 
  var input, filter, table, tr, td, i, txtValue;
  input = document.getElementById("myInput");
  filter = input.value.toUpperCase();
  table = document.getElementById("myTable");
  tr = table.getElementsByTagName("tr");

  // Loop through all table rows, and hide those who don't match the search query
  for (i = 0; i < tr.length; i++) {
    td = tr[i].getElementsByTagName("td")[0];
    if (td) {
      txtValue = td.textContent || td.innerText;
      if (txtValue.toUpperCase().indexOf(filter) > -1) {
        tr[i].style.display = "";
      } else {
        tr[i].style.display = "none";
      }
    } 
  }
}
</script>
	</head>

<body>
	<input type="text" id="myInput" onkeyup="myFunction()" placeholder="Suche">

<table id="myTable">
	<thead> 

 <tr> 
  <th data-type="number" title="Nach Nummer sortieren">Titel</th> 
  <th data-type="string" title="Nach Vorname sortieren">Hersteller</th> 
 </tr> 

</thead> 
 
  <tr>
  <td>Arkeis</td>
  <td>Board Game Box</td>
 </tr>
 <tr>
  <td>ARSCHMALLOWS®</td>
  <td>D&amp;R DENKRIESEN GmbH</td>
 </tr>
 <tr>
  <td>Astra</td>
  <td>Skellig Games</td>
 </tr>
 <tr>
  <td>Bamboo</td>
  <td>Skellig Games</td>
 </tr>
 <tr>
  <td>Black Friday</td>
  <td>2F-Spiele</td>
 </tr>
 <tr>
  <td>Block and Key DE</td>
  <td>Skellig Games</td>
 </tr>
 <tr>
  <td>Cabanga!</td>
  <td>Amigo</td>
 </tr>
 <tr>
  <td>Chrono Fall: At the End of Space and Time</td>
  <td>Ornament Games</td>
 </tr>
 <tr>
  <td>Colour Lines</td>
  <td>SPIEL DAS! Verlag</td>
 </tr>
 <tr>
  <td>Come Together</td>
  <td>Skellig Games</td>
 </tr>
 <tr>
  <td>Corduba</td>
  <td>Skellig Games</td>
 </tr>
 <tr>
  <td>Darwin's Journey</td>
  <td>Skellig Games</td>
 </tr>
 <tr>
  <td>Décorum</td>
  <td>Skellig Games</td>
 </tr>
 <tr>
  <td>Die Kathedrale von Orléans</td>
  <td>dlp games</td>
 </tr>
 <tr>
  <td>Die Patin</td>
  <td>Zoch</td>
 </tr>
 <tr>
  <td>Die Perlen des Poseidon</td>
  <td>Zoch</td>
 </tr>
 <tr>
  <td>Die Wölfe</td>
  <td>Skellig Games</td>
 </tr>
 <tr>
  <td>Djinn</td>
  <td>Hall Games</td>
 </tr>
 <tr>
  <td>Evenfall</td>
  <td>Nanox Games, dlp games</td>
 </tr>
 <tr>
  <td>Expeditions</td>
  <td>Feuerland</td>
 </tr>
 <tr>
  <td>Feiges Huhn!</td>
  <td>Amigo</td>
 </tr>
 <tr>
  <td>Figurata</td>
  <td>10 Traders</td>
 </tr>
 <tr>
  <td>Flip4</td>
  <td>Noris-Spiele</td>
 </tr>
 <tr>
  <td>For Sale</td>
  <td>SPIEL DAS! Verlag</td>
 </tr>
 <tr>
  <td>Freaky Frogs from Outaspace</td>
  <td>2F-Spiele</td>
 </tr>
 <tr>
  <td>Frosthaven</td>
  <td>Feuerland</td>
 </tr>
 <tr>
  <td>FTW?!</td>
  <td>2F-Spiele</td>
 </tr>
 <tr>
  <td>Gigi Gacker</td>
  <td>Zoch</td>
 </tr>
 <tr>
  <td>Grease Monkey Garage</td>
  <td>Board Game Circus</td>
 </tr>
 <tr>
  <td>Haifischen</td>
  <td>D&amp;R DENKRIESEN GmbH</td>
 </tr>
 <tr>
  <td>Harry Potter - Dumbledores Armee</td>
  <td>Noris-Spiele</td>
 </tr>
 <tr>
  <td>Harry Potter - Quidditch </td>
  <td>Noris-Spiele</td>
 </tr>
 <tr>
  <td>Hitster - Summer Party</td>
  <td>Jumbo</td>
 </tr>
 <tr>
  <td>Insel-Express: Der kleine große Engine Builder</td>
  <td>Board Game Circus</td>
 </tr>
 <tr>
  <td>Kingscraft</td>
  <td>Skellig Games</td>
 </tr>
 <tr>
  <td>Kyū</td>
  <td>10 Traders</td>
 </tr>
 <tr>
  <td>LAMA Kadabra</td>
  <td>Amigo</td>
 </tr>
 <tr>
  <td>Levels Classic Edition</td>
  <td>D&amp;R DENKRIESEN GmbH</td>
 </tr>
 <tr>
  <td>Lost Lights</td>
  <td>Board Game Circus</td>
 </tr>
 <tr>
  <td>Lunar Laser Frogs</td>
  <td>Loosey Goosey Games</td>
 </tr>
 <tr>
  <td>Maldivia</td>
  <td>Zoch</td>
 </tr>
 <tr>
  <td>maunz.</td>
  <td>Skellig Games</td>
 </tr>
 <tr>
  <td>Mein grüner Fußabdruck - Spiel</td>
  <td>Noris-Spiele</td>
 </tr>
 <tr>
  <td>Mein lieber Scholli</td>
  <td>Zoch</td>
 </tr>
 <tr>
  <td>Mirakel Mix</td>
  <td>Zoch</td>
 </tr>
 <tr>
  <td>Mission Control</td>
  <td>Skellig Games</td>
 </tr>
 <tr>
  <td>Mythwind</td>
  <td>Board Game Circus</td>
 </tr>
 <tr>
  <td>Northgard - Uncharted Lands</td>
  <td>Board Game Box</td>
 </tr>
 <tr>
  <td>Pick a Pen</td>
  <td>Amigo</td>
 </tr>
 <tr>
  <td>Pirate Tales</td>
  <td>Skellig Games</td>
 </tr>
 <tr>
  <td>Pirates of Maracaibo</td>
  <td>Game's Up, dlp games</td>
 </tr>
 <tr>
  <td>Planet Ocean</td>
  <td>D&amp;R DENKRIESEN GmbH</td>
 </tr>
 <tr>
  <td>Planta Nubo</td>
  <td class=xl68>The Game Builders</td>
 </tr>
 <tr>
  <td>Punktestadt</td>
  <td>Skellig Games</td>
 </tr>
 <tr>
  <td>Rauf und Runter</td>
  <td>Zoch</td>
 </tr>
 <tr>
  <td>Rauha</td>
  <td>Skellig Games</td>
 </tr>
 <tr>
  <td>Reif für die Insel</td>
  <td>Zoch</td>
 </tr>
 <tr>
  <td>SAFE!®</td>
  <td>D&amp;R DENKRIESEN GmbH</td>
 </tr>
 <tr>
  <td>Schrödingers Katzen</td>
  <td>Amigo</td>
 </tr>
 <tr>
  <td>Schwingenschlag</td>
  <td>Feuerland</td>
 </tr>
 <tr>
  <td>Septima</td>
  <td>Skellig Games</td>
 </tr>
 <tr>
  <td>Shake that City</td>
  <td>Board Game Circus</td>
 </tr>
 <tr>
  <td>Snack Rabbits</td>
  <td>Amigo</td>
 </tr>
 <tr>
  <td>Spiel des Wissens - Rund um di<span
  style='display:none'>e Welt</span></td>
  <td>Jumbo</td>
 </tr>
 <tr>
  <td>Spiel des Wissens - Rund um di<span
  style='display:none'>e Welt Kartenspiel</span></td>
  <td>Jumbo</td>
 </tr>
 <tr>
  <td>Sssnake - Flip&amp;Write</td>
  <td>Suncoregames</td>
 </tr>
 <tr>
  <td>Stadt Land Vollpfosten® Das Ka<span
  style='display:none'>rtenspiel Urlaubs Edition</span></td>
  <td>D&amp;R DENKRIESEN GmbH</td>
 </tr>
 <tr>
  <td>Stich für Stich</td>
  <td>Zoch</td>
 </tr>
 <tr>
  <td>Supermallows®</td>
  <td>D&amp;R DENKRIESEN GmbH</td>
 </tr>
 <tr>
  <td>Surfosaurus MAX</td>
  <td>Loosey Goosey Games</td>
 </tr>
 <tr>
  <td>Sweet Mess: Der Backwettbe<span
  style='display:none'>werb</span></td>
  <td>Skellig Games</td>
 </tr>
 <tr>
  <td>The Academy</td>
  <td>Amigo</td>
 </tr>
 <tr>
  <td>Tinderblox</td>
  <td class=xl68>The Game Builders</td>
 </tr>
 <tr>
  <td>Tüftelmonster</td>
  <td>Board Game Circus</td>
 </tr>
 <tr>
  <td>Unfinished Business</td>
  <td>MPLPRN</td>
 </tr>
 <tr>
  <td>Unsolved - Tod auf der Jacht</td>
  <td>Amigo</td>
 </tr>
 <tr>
  <td>Voidfall</td>
  <td>Skellig Games</td>
 </tr>
 <tr>
  <td>Volles Fass voraus</td>
  <td>Zoch</td>
 </tr>
 <tr>
  <td>Weimar</td>
  <td>Skellig Games</td>
 </tr>
 <tr>
  <td>What the Rule?!</td>
  <td>Perdix Spiele</td>
 </tr>
 <tr>
  <td>With a Smile &amp; a Gun</td>
  <td>SPIEL DAS! Verlag</td>
 </tr>
 <tr>
  <td>Woozle Goozle - Quizzeria 300<span
  style='display:none'>1</span></td>
  <td>Noris-Spiele</td>
 </tr>
 <tr>
  <td>Woozle Goozle - Schlaukopf 30<span
  style='display:none'>01</span></td>
  <td>Noris-Spiele</td>
 </tr>
 <tr>
  <td>Woozle Goozle - Um die Welt <span
  style='display:none'>woozlen!</span></td>
  <td>Noris-Spiele</td>
 </tr>
 <tr>
  <td>Z3BRA</td>
  <td>Amigo</td>
 </tr>
 <tr>
  <td>ZUNGENBRECHER©</td>
  <td>D&amp;R DENKRIESEN GmbH</td>
 </tr>
</table>
	<script> 
// HTML-Tabelle sortieren 

const table = document.getElementById("myTable"); 
const headers = table.querySelectorAll("th"); 
const tableBody = table.querySelector("tbody"); 
const rows = tableBody.querySelectorAll("tr"); 
const directions = Array.from(headers).map(function(header) { 
 return ""; 
}); 

const transform = function(index, content) { 
 const type = headers[index].getAttribute("data-type"); 
 switch (type) { 
     case "number": 
  return parseFloat(content); 
     case "string": 
     default: 
  return content; 
 } 
}; 

const sortColumn = function(index, headers) { 

 const cls = ["upArrow", "dnArrow"]; 
 headers.forEach((header) => { 
  document.getElementById(header.id).classList.remove(...cls); 
 }); 

  const direction = directions[index] || "asc"; 
  const multiplier = (direction === "asc") ? 1 : -1; 
  const cssSort = (direction === "asc") ? cls[0] : cls[1]; 
  document.getElementById(index).classList.add(cssSort); 

  const newRows = Array.from(rows); 
  newRows.sort((rowA, rowB) => { 
     const cellA = encodeURIComponent(rowA.querySelectorAll("td")[index].textContent.toLowerCase()); 
     const cellB = encodeURIComponent(rowB.querySelectorAll("td")[index].textContent.toLowerCase()); 

     const a = transform(index, cellA); 
     const b = transform(index, cellB); 

     switch (true) { 
      case a > b: return 1 * multiplier; 
      case a < b: return -1 * multiplier; 
      case a === b: return 0; 
       } 
   }); 

   [].forEach.call(rows, function(row) { 
       tableBody.removeChild(row); 
   }); 

   directions[index] = direction === "asc" ? "desc" : "asc"; 
   newRows.forEach(function(newRow) { 
       tableBody.appendChild(newRow); 
   }); 
 }; 

[].forEach.call(headers, function(header, index) { 
   header.setAttribute("id", index); 
   header.addEventListener("click", () => { 
       sortColumn(index, headers); 
   }); 
}); 
</script>
</body>
</html>

  1. problematische Seite

    Hallo Ingo,

    deine unter Problematische Seite verlinkte Seite steckt voller Fehler: https://validator.w3.org/nu/?doc=https%3A%2F%2Fwww.spiel-essen.de%2Fde%2Fprogramm%2Fdsp%2Fteilnehmerliste-2024

    Übrigens, kennst du schon unseren Tabellensortierer?

    Gruß
    Jürgen

  2. problematische Seite

    @@Ingo

    Wenn man auf HERSTELLER klickt, klappt alles wunderbar

    Nein, leider nicht. Man kann nicht auf „Hersteller“ clicken.

    Einige können das (Mausnutzer bspw.). Andere können das nicht (Tastaturnutzer bspw.).

    Damit man (also alle) clicken können, müssen in den th-Elementen Buttons sein:

    <thead>
      <th><button>Titel</button></th>
      <th><button>Hersteller</button></th>
    </thead>
    

    Den Buttons kannst du mit CSS Rahmen und Hintergrundfarbe wegnehmen.

    Die Beschriftung lässt sich sicher mit visuell versteckten „sortieren nach“ verbessern.

    Und die th sollten bei der Sortierung entsprechende aria-sort-Attribute gesetzt bekommen.

    Siehe Abschnitt Sortable tables in Inclusive Components: Data tables.

    Kwakoni Yiquan

    --
    Ad astra per aspera
  3. problematische Seite

    (Uff - da bastelt man rum und währenddessen posten zwei andere 😉)

    Hallo Ingo,

    Ich verzweifle gerade an einer simplen Tabellensortierung...

    Ich verzweifle an deinem HTML.

    (1) Solche Monster bitte nicht posten, sondern ein Onlinebeispiel bereitstellen. Das schreiben wir fast täglich 😟. Ich werde deinen Code jetzt nicht selbst online stellen. Es hätte ja schon geholfen, die Row-Flut auf 3 oder 4 zu reduzieren; ich habe das mal gemacht.

    (2a) Placeholder sind keine Labels, dein Suchfeld braucht ein label Element zur Beschriftung, und type="search" obendrein.

    (2b) addEventListener kennst Du doch; warum beschmutzt Du Dein HTML mit einem onkeyup im Suchfeld? Und wieso keyup? Was machst Du, wenn jemand mit der Maus einen Inhalt hineinkopiert? Deine Seite ist nicht mausbedienbar.

    (3) Wenn ich es online stellen täte - dann gelänge es mir nicht, eine Sortierung herbeizuführen. Ich würde TAB und ENTER und TAB TAB drücken - alles ohne Effekt. Oder anders gesagt: click-Handler auf einem nicht-interaktiven Element wie th sind ein no-go. Die Sortierfunktion gehört auf Buttons. Im Wiki hätten wir ein Implementierungsbeispiel. Deine Seite ist nicht tastaturbedienbar.

    (4) Du speicherst Dir einmalig zu Beginn die Tabellenzeilen im Array rows. Dann sortierst Du und legst das Ergebnis nach newRows, woraus Du dann die Tabelle neu aufbaust. Im rows Array bleiben damit die Rows der Ursprungstabelle in ihrer Ursprungsreihenfolge erhalten.

    Für die Spalte 1 hast Du "number" als Datentyp angegeben. Da stehen aber keine Zahlen, deswegen liefert parseFloat immer NaN und dein Sort-Callback sagt immer: Alles gut, nicht tauschen. Deswegen ergibt sich nach dem sort-Aufruf die aus dem rows-Array übernommene Ursprungsreihenfolge.

    Das kommt davon, wenn man Code zusammenkopiert, ohne ihn zu verstehen!

    Rolf

    --
    sumpsi - posui - obstruxi
    1. problematische Seite

      Servus!

      (Uff - da bastelt man rum und währenddessen posten zwei andere 😉)

      Hallo Ingo,

      Ich verzweifle gerade an einer simplen Tabellensortierung...

      Ich verzweifle an deinem HTML.

      (1) Solche Monster bitte nicht posten, sondern ein Onlinebeispiel bereitstellen. Das schreiben wir fast täglich 😟.

      Hat er ja - unter "problematische Seite" - siehe @JürgenB s Antwort.

      Wenn selbst wir das oft nicht finden, sollten wir uns mal über ein Redesign Gedanken machen!

      Herzliche Grüße

      Matthias Scharwies

      --
      Die Signatur findet sich auf der Rückseite des Beitrags.
      1. problematische Seite

        Hallo Matthias Scharwies,

        autsch. Ich habe nur die Codewüste gesehen und nicht damit gerechnet, dann noch einen Link zu finden.

        Sorry, Ingo.

        Aber zum Vorwurf des Copy+Paste Programmierers stehe ich, hier ist die Vorlage, die verständnisfrei übernommen wurde. Statt dessen hat er uns den Müll stumpf vor die Füße gekübelt.

        Rolf

        --
        sumpsi - posui - obstruxi