Hallo Jörg,
dein Vorschlag lässt an „Schönheit“ zu wünschen übrig. Es gibt Redundanzen und unnötige Komplexität.
-
Der selectAll Button wird nicht gepostet. Er braucht also weder name noch value. Das mag ein Relikt aus der Zeit sein, wo ein Select All noch einen HTTP Fallback hatte 😀
-
Die Sichtbarmachung von selectAll über eine Style-Zuweisung
display:inline
ist unschön. Du forcierst einen bestimmten Display-Stil. Bzw. wenn Du unterschiedliche Stile hast, musst Du mehrere Klassen nutzen. Oder data-Attribute. Oder oder. Sinnvoller wäre eine Klasse js-only, die ein display:none !important hinzufügt und die vom JavaScript einfach entfernt wird. Schwups, ist das Element da. Man könnte sogar am Body eine Klasse "no-js" setzen und im CSS den Selektor.no-js .js-only
verwenden, um das display:none zu setzen. Und das Script muss dann nicht suchen, sondern kann einfach die no-js Klasse am Body entfernen. Das ist aber jetzt eine Korinthe... -
Ob die MultiSelector Checkboxen eine ID brauchen, glaube ich nicht. Für den Postback ist das name-Attribut relevant. Im Zweifelsfall findet man sie mit querySelector. Eine ID mit eckigen Klammern drin macht die Handhabbarkeit ohnehin schwieriger. Paralleles Setzen von name und id scheint mir ohnehin ein Relikt aus der Zeit zu sein, wo es querySelector noch nicht gab (vor IE 8). Man kann bei Nutzung von Namenskonvention sogar auf eine Klasse verzichten, die die Zeilenselektoren identifiziert...
-
Das Umregistrieren des click-Handlers halte ich für sehr unbeholfen, vor allem weil beide Handler so ähnlich sind. Sowas macht man mit einem einzigen Handler, und um festzustellen, ob man Select All oder Clear Selection auszuführen hat, kann man ein data-Attribut oder eine Klasse am Button nutzen. Wenn man's mit einer Klasse macht, könnte man sogar per CSS den Text austauschen.
Mein HTML sähe so aus (mit ein paar Zeilenumbrüchen weniger um vertical space im Posting zu sparen):
<form method="POST" action="/handle_the_form.php">
<button type="button" class="js-only" id="selectAll"><span>Alles auswählen</span><span>Auswahl aufheben</span></button>
<button name="deleteSelected" value="1">Gewählte Löschen</button>
<table>
<tr>
<td><input type="checkbox" name="selector[1]"></td>
<td>Daten 1</td>
<td><button name="edit" value="1">edit</button><button name="delete" value="1">delete</button></td>
</tr>
<tr>
<td><input type="checkbox" name="selector[2]"></td>
<td>Daten 2</td>
<td><button name="edit" value="2">edit</button><button name="delete" value="2">delete</button></td>
</tr>
</table>
</form>
und das CSS dazu so:
.no-js .js-only { display: none !important; }
#selectAll.all-selected span:first-child { display: none; }
#selectAll:not(.all-selected) span:last-child { display: none; }
mit diesem JavaScript
if (!document.querySelector || !document.body.classList) return; /* Browser zu alt */
document.body.classList.remove("no-js");
var o = document.getElementById('selectAll');
o.addEventListener("click", handleMultiSelectClick);
function handleMultiSelectClick(e) {
var btn = locateButton(e.target);
var newCheckedState = !btn.classList.contains('all-selected');
var ar = document.querySelector("input[type=checkbox][name^=selector]");
for (var i = 0; i < ar.length; i++) {
ar[i].checked=newCheckedState;
}
btn.classList.toggle('all-selected');
btn.textContent = newCheckedState ? "Auswahl aufheben" : "Alles auswählen";
}
function locateButton(e) {
// Element.prototype.closest wäre einfacher, braucht aber Polyfill im IE
while (e && e.tagName != "BUTTON") e = e.parentElement;
return e;
}
Wenn man Browser vor IE10 unterstützen will, braucht's noch einen Polyfill oder eine alternative Implementierung für die classList Operationen. locateButton habe ich als Ersatz für closest('button') genommen. Statt dessen geht auch ein Polyfill für closest.
Rolf
sumpsi - posui - clusi