Der Checkbox-Hack

Ich bin da neulich beim Programmieren an einem Kanboard-Plugin auf etwas gestossen.

In Webseiten werden Ja/Nein Optionen üblicherweise mit einer Checkbox realisiert. Nun werden aber leider die damit getroffene Einstellung nur bei der Option Ja, das heisst Haken gesetzt, an den Server übermittelt. Bei Nein wird die Einstellung ignoriert, nicht an den Server übertragen. Irgendwo habe ich gelesen, das sei schon richtig so und müsse so sein. Möglicherweise ist es ja in den meisten Anwendungsfällen wirklich egal. Aber wenn man die vorgenommene Einstellung auf dem Server speichern muss, ist es keinesfalls egal. Man kann demnach nur einmal Ja übermitteln, jeder Versuch, die Einstellung wieder auf Nein zu wechseln, schlägt scheinbar unausweichlich fehl. Sucht man im Netz nach dem Problem und möglichen Lösungen, entsteht der Eindruck, dass daran schon viele Leute zu kauen gehabt haben. Eine elegante und universell brauchbare Lösung habe ich nicht gefunden.

Workaround

Sämtliche Konfigurationsdialoge im Kanboard sind davon betroffen, man verwendet dort eigentlich fast nirgends Checkboxen. Ausser auf der eigenen Settings-Seite. Meine Neugierde liess mich das untersuchen und ich weiss jetzt auch wieso das so ist.

Für alle Checkboxen wird der ausgelassene Eintrag simuliert nachgereicht. Der Server kriegt nun auch bei Option Nein einen Wert 0 geliefert. Damit können beide Zustände abgespeichert werden. Ziel erreicht.

Will man in einem eigenen Setting-Dialog eine Checkbox haben, muss man zwangsläufig überall so einen Null-Patch einfügen oder einen eigenen Setting-Controller schreiben und die Umsetzung dort realisieren. Für eine bis ein paar wenige Checkboxen ein erheblicher Aufwand.

Und sollte man das Prinzip nicht allgemein verwendbar umsetzen können? Ich finde schon, dass das möglich sein sollte und machte mich auf die Suche.

Lösung

Ein selbst geschriebenes Plugin kann das auch lösen. Per Javascript hängt es jeder Post-Form auf allen Seiten einen Event-Listener für der submit Event an. Die Funktion fügt für alle Checkboxen, bei denen kein Haken gesetzt ist (unchecked) ein unsichtbares <input> Tag mit demselben Namen wie die Checkbox und dem Attribut value=0 an. Diese werden, im Gegensatz zu den Checkboxen, an den Server übermittelt und ganz normal verarbeitet.

'strict';

$(function () {
    $('form[method=post]').each(function () {
        let form = this;
        form.addEventListener('submit', () => {
            $('input[type=checkbox]').each(function () {
                if (!this.checked) {
                    // console.log(`Need to patch ${this.name}`);
                    const dummy = document.createElement('input');
                    dummy.name = this.name;
                    dummy.value = 0;
                    dummy.hidden = true;
                    form.append(dummy);
                }
            });
            return true;
        });
    });
});

Ich habe das hinreichend getestet und konnte keinerlei unerwünschte Nebenwirkungen feststellen. Falls das so bleibt, werde ich das Plugin bei Kanboard registrieren.