jQuery / Selecionar e desmarcar todas as caixas
Use .prop("checked", true) para selecionar todas as caixas de um conjunto e .prop("checked", false) para desmarcar. Com uma caixa geral, recalcule seu estado quando cada item mudar. indeterminate indica seleção parcial.
Definir conjunto e estados gerais
.prop() lê ou altera checked atual. O atributo HTML por .attr() não gerencia a escolha atual do usuário. Passe booleanos true ou false, não strings.
O conjunto contém caixas habilitadas com classe item em #items, sem #all. :enabled exclui controles desabilitados, inclusive por herança de fieldset. Estar oculto apenas por CSS não exclui um controle.
A geral só fica marcada quando existe pelo menos um item disponível e todos estão selecionados. Parte selecionada significa checked=false e indeterminate=true; nenhuma, ambos false. Zero itens também desabilita a geral: zero igual a zero não significa seleção completa.
Exemplo completo em um arquivo
Salve tudo em UTF-8 como checkbox-demo.html e abra no navegador. A Internet carrega o arquivo oficial do jQuery 4.0.0. Não exige servidor nem pacotes. As funções principais foram executadas no Edge para Windows com 3.7.1 e 4.0.0.
Alpha começa marcada, Beta não. Locked está marcada, mas desabilitada, fora da operação e da contagem. A geral não tem name e não é enviada como valor de item.
<!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>
Saída inicial: um selecionado de dois disponíveis. A geral mostra estado parcial.
selected=1/2
master checked=false
master mixed=true
item changes=0
values=alpha
- Select all available items resulta em selected=2/2, master checked=true e master mixed=false. Outra ativação resulta em 0/2; Locked continua marcada.
- Apenas Beta resulta em 1/2 e master mixed=true. Selecionar Alpha também completa a geral. Rótulos e Espaço na caixa focada funcionam.
- Após selecionar tudo, Add item acrescenta Extra 1 desmarcada: 2/3 e parcial. Marque-a para seleção completa novamente.
- Remove items resulta em 0/0 e desabilita a geral. Adicionar um item volta a habilitá-la.
- Com Alpha e Beta, Inspect submission mostra item=alpha&item=beta. Locked fica fora; sem seleção disponível aparece (no successful controls).
- Reset example recria os três itens iniciais e limpa contadores e saída. Não envia nada e desfaz alterações.
Sincronizar mudanças individuais e dinâmicas
O manipulador change geral atribui this.checked aos disponíveis e chama sync() uma vez. .prop() não dispara change em cada filho. item changes cresce com mudanças individuais, não com seleção geral.
A delegação no #items estável atende novas caixas sem vinculação individual. available() consulta o DOM atual sempre. Uma coleção guardada no início poderia ignorar novos itens ou manter removidos.
Adicionar e remover chamam sync() explicitamente. Delegação não observa alterações estruturais do DOM. Se outro código muda disabled ou checked, conecte-o à mesma sincronização. Essas mudanças programadas não são detectadas automaticamente aqui.
Se a mudança individual também calcula preços, planeje esse trabalho na operação geral. .trigger("change") pode servir seletivamente, evitando recalcular tudo ou duplicar requisições para cada item. Aqui uma sincronização segue a atribuição conjunta.
Estado parcial, reinício e envio
indeterminate é um estado visual definido por JavaScript, não atributo HTML inicial nem valor adicional enviado. É independente de checked. sync() atribui ambos para não deixar indicadores antigos. Rótulos reais e caixas nativas preservam o teclado normal.
Inspect submission mostra FormData sem requisição de rede. Controles habilitados marcados fornecem nomes e valores. Se o negócio exige valores desabilitados, projete sua representação e validação do servidor explicitamente. Seleção cliente não substitui permissões do servidor.
Reset example é uma recriação personalizada. O reset nativo restaura valores padrão; depois recalcule a geral. Apenas mudar para type="reset" não removeria novos itens nem reiniciaria contadores do mesmo modo.
A seleção cobre itens presentes no documento. Linhas de outras páginas do servidor ainda não carregadas exigem estado separado no servidor. Separe grupos. Com filtro, defina se «todos» significa visíveis ou todos os habilitados do grupo e ajuste seletores e rótulos.




