jQuery / Cocher et décocher toutes les cases

Utilisez .prop("checked", true) pour tout cocher et .prop("checked", false) pour tout décocher dans un ensemble. Avec une case générale, recalculez aussi son état lorsque chaque élément change. indeterminate indique une sélection partielle.

Définir les éléments et les états

.prop() lit et modifie la propriété checked actuelle. L’attribut HTML via .attr() ne sert pas à gérer les choix actuels. Fournissez des booléens true ou false, pas des chaînes.

Ici, l’ensemble comprend les cases actives de classe item dans #items. #all en est exclue. :enabled écarte les contrôles désactivés, notamment par un fieldset. Être masqué uniquement par CSS n’exclut pas un élément.

La case générale n’est cochée que si au moins un élément est disponible et tous sont sélectionnés. Une partie donne checked=false et indeterminate=true ; aucun donne les deux false. Zéro élément désactive aussi la case générale : zéro égal à zéro ne signifie pas tout sélectionné.

Exemple complet dans un fichier

Enregistrez tout en UTF-8 sous checkbox-demo.html et ouvrez-le dans le navigateur. Internet charge le fichier officiel jQuery 4.0.0. Aucun serveur ou paquet n’est nécessaire. Le fonctionnement principal a été exécuté dans Edge sous Windows avec 3.7.1 et 4.0.0.

Alpha est cochée, Beta non. Locked est cochée mais désactivée, donc exclue de l’opération et du décompte. La case générale n’a pas de name et n’est pas envoyée comme valeur d’élément.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Select all eligible checkboxes</title>
  <script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
  <style>
    body { font: 16px/1.6 sans-serif; max-width: 760px; margin: 20px; }
    label { display: block; padding: 6px; }
    button { font: inherit; margin: 4px; }
    fieldset { margin: 12px 0; }
    pre { white-space: pre-wrap; overflow-wrap: anywhere; }
  </style>
</head>
<body>
  <form id="choices">
    <label><input type="checkbox" id="all"> Select all available items</label>
    <fieldset id="items"><legend>Items</legend></fieldset>
    <button type="button" id="add">Add item</button>
    <button type="button" id="clear">Remove items</button>
    <button type="button" id="reset">Reset example</button>
    <button type="submit">Inspect submission</button>
  </form>
  <pre id="result" aria-live="polite"></pre>
  <pre id="submission"></pre>
  <script>
    $(function () {
      const $form = $("#choices"), $all = $("#all");
      let next = 1, itemChanges = 0;
      function available() { return $("#items input.item:checkbox:enabled"); }
      function sync() {
        const $items = available(), total = $items.length;
        const count = $items.filter(":checked").length;
        $all.prop({ checked: total > 0 && count === total,
          indeterminate: count > 0 && count < total, disabled: total === 0 });
        const values = $items.filter(":checked").map(function () { return this.value; }).get();
        $("#result").text(`selected=${count}/${total}\nmaster checked=${$all.prop("checked")}\nmaster mixed=${$all.prop("indeterminate")}\nitem changes=${itemChanges}\nvalues=${values.join(",")}`);
      }
      function addItem(value, text, checked, disabled) {
        const label = document.createElement("label"), input = document.createElement("input");
        input.type = "checkbox"; input.name = "item"; input.className = "item";
        input.value = value; input.checked = checked; input.disabled = disabled;
        label.append(input, document.createTextNode(" " + text));
        document.getElementById("items").append(label);
      }
      $all.on("change.selectAllLesson", function () {
        available().prop("checked", this.checked);
        sync(); // Setting checked does not emit change on each item.
      });
      $("#items").on("change.selectAllLesson", "input.item:checkbox", function () {
        itemChanges++; sync();
      });
      $("#add").on("click", function () {
        addItem("extra" + next, "Extra " + next, false, false); next++; sync();
      });
      $("#clear").on("click", function () { $("#items label").remove(); sync(); });
      $("#reset").on("click", function () {
        $("#items label").remove(); $("#items").prop("disabled", false);
        addItem("alpha", "Alpha", true, false);
        addItem("beta", "Beta", false, false);
        addItem("locked", "Locked (unavailable)", true, true);
        next = 1; itemChanges = 0; $("#submission").empty(); sync();
      });
      $form.on("submit", function (event) {
        event.preventDefault();
        const params = new URLSearchParams(new FormData(this));
        $("#submission").text(params.toString() || "(no successful controls)");
      });
      $("#reset").trigger("click");
    });
  </script>
</body>
</html>

Sortie initiale : un élément sélectionné sur deux disponibles. La case générale affiche l’état partiel.

selected=1/2
master checked=false
master mixed=true
item changes=0
values=alpha
  1. Select all available items donne selected=2/2, master checked=true, master mixed=false. Une autre activation donne 0/2 ; Locked reste cochée.
  2. Beta seule donne 1/2 et master mixed=true. Cochez aussi Alpha pour tout sélectionner. Étiquettes et Espace sur une case focalisée fonctionnent également.
  3. Après sélection complète, Add item ajoute Extra 1 non cochée : 2/3 et état partiel. Cochez-la pour revenir à tout.
  4. Remove items donne 0/0 et désactive la case générale. Ajouter un élément la réactive.
  5. Avec Alpha et Beta, Inspect submission affiche item=alpha&item=beta. Locked est exclue ; sans sélection disponible, (no successful controls) apparaît.
  6. Reset example recrée les trois éléments initiaux et vide compteurs et sortie. Il n’envoie rien et annule les changements.

Synchroniser changements individuels et dynamiques

Le gestionnaire change général applique this.checked aux éléments disponibles puis appelle sync() une fois. Affecter .prop() ne déclenche pas change sur chaque enfant. item changes augmente donc pour les changements individuels, pas pour l’opération générale.

La délégation sur #items, qui reste en place, prend en charge les ajouts sans nouvelle liaison individuelle. available() relit le DOM à chaque appel. Une collection conservée depuis le démarrage pourrait ignorer les nouveaux éléments ou garder les anciens.

Ajout et suppression appellent explicitement sync(). La délégation ne surveille pas la structure du DOM. Si un autre code change disabled ou checked, reliez-le à cette synchronisation. Ces modifications programmées ne sont pas détectées automatiquement ici.

Si les changements individuels calculent également des prix, prévoyez ce travail pour l’opération générale. .trigger("change") peut convenir ponctuellement, mais évitez de recalculer tout l’ensemble ou de répéter les requêtes pour chaque élément. Ici, une seule synchronisation suit l’affectation groupée.

État partiel, réinitialisation et envoi

indeterminate est un état visuel défini par JavaScript, pas un attribut HTML initial ou une valeur envoyée supplémentaire. Il est indépendant de checked. sync() définit les deux propriétés pour supprimer tout ancien indicateur partiel. Les vrais labels et cases natives conservent le clavier habituel.

Inspect submission affiche FormData sans requête réseau. Les contrôles actifs cochés fournissent noms et valeurs. Si des valeurs désactivées sont nécessaires métier, concevez explicitement leur représentation et la validation serveur. La sélection cliente ne remplace jamais les contrôles d’autorisation serveur.

Reset example est une recréation personnalisée. La réinitialisation native du formulaire restaure les valeurs par défaut ; recalculez ensuite la case générale. Remplacer simplement le bouton par type="reset" ne supprimerait pas pareillement les ajouts et compteurs.

La sélection concerne les éléments présents dans le document. Les lignes d’autres pages serveur non chargées nécessitent un état serveur distinct. Limitez chaque groupe. Avec un filtre, décidez si « tout » signifie les éléments visibles ou tous les actifs du groupe, puis adaptez sélecteurs et libellés.