jQuery / Escolher pais pela quantidade de filhos
Filtre pais candidatos com .filter(function () { ... }) e compare $(this).children(".item").length em cada callback. === 2 significa exatamente dois e >= 2 pelo menos dois. Use find() em vez de children() apenas para todos os descendentes aninhados.
Definir o que cada pai conta
.filter() mantém membros da seleção que passam no teste. this é o pai DOM examinado; true o mantém. O resultado contém pais, não filhos, e não remove os demais do documento.
.children(".item") conta correspondências um nível abaixo. Sem seletor, títulos e outros filhos elementos também contam. Texto e comentários ficam fora nos dois casos.
.find(".item") inclui descendentes mais profundos. Beta tem um filho direto com dois dentro: três descendentes. Ocultos continuam no DOM e contam. Apenas visíveis exige uma regra adicional explícita.
Exemplo completo: exato ou mínimo
Salve tudo em UTF-8 como child-count-demo.html e abra no navegador. A Internet carrega o arquivo oficial do jQuery 4.0.0. Não exige servidor nem pacotes. Condições, reinício e adições foram executados no Edge para Windows com 3.7.1 e 4.0.0.
Contagens diretas: Alpha 2, Beta 1, Gamma 0 e Delta 3. D3 oculto conta; títulos e texto não são .item. Candidatos são apenas .group diretos de #board, sem objetos internos.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Filter parents by child count</title>
<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<style>
body { font: 16px/1.6 sans-serif; margin: 20px; max-width: 760px; }
label { display: block; margin: 8px 0; }
select, input, button { font: inherit; max-width: 100%; }
.group { border: 2px solid #aaa; padding: 12px; margin: 12px 0; }
.group.chosen { border-color: teal; background: #e5f5f1; }
.item { display: inline-block; padding: 4px; border: 1px solid #777; margin: 3px; }
.item[hidden] { display: none; }
.group h2 { font-size: 20px; margin: 0; }
#result { white-space: pre-wrap; overflow-wrap: anywhere; }
</style>
</head>
<body>
<label>Count scope <select id="scope"><option value="direct">Direct children</option><option value="descendant">All descendants</option></select></label>
<label>Rule <select id="rule"><option value="exact">Exactly</option><option value="minimum">At least</option></select></label>
<label>Required count <input id="count" type="number" min="0" step="1" value="2"></label>
<button type="button" id="add">Add direct item to Alpha</button>
<button type="button" id="reset">Reset</button>
<div id="board">
<section class="group" id="alpha"><h2>Alpha</h2><span class="item">A1</span><span class="item">A2</span> plain text <!-- comment --></section>
<section class="group" id="beta"><h2>Beta</h2><div class="item">B1 <span class="item">B2</span><span class="item">B3</span></div></section>
<section class="group" id="gamma"><h2>Gamma</h2>Text without an item</section>
<section class="group" id="delta"><h2>Delta</h2><span class="item">D1</span><span class="item">D2</span><span class="item" hidden>D3 hidden</span></section>
</div>
<pre id="result" aria-live="polite"></pre>
<script>
$(function () {
const initial = $("#board").html();
let added = 0;
function apply() {
const $groups = $("#board > .group");
const scope = $("#scope").val(), rule = $("#rule").val();
const field = document.getElementById("count"), target = Number(field.value);
$groups.removeClass("chosen");
if (field.value === "" || !field.checkValidity() || !Number.isInteger(target) || target < 0) {
$("#result").text("Enter a nonnegative integer."); return;
}
function count(group) {
return scope === "direct" ? $(group).children(".item").length : $(group).find(".item").length;
}
const $selected = $groups.filter(function () {
const n = count(this);
return rule === "exact" ? n === target : n >= target;
});
$selected.addClass("chosen");
const ids = $selected.map(function () { return this.id; }).get();
const counts = $groups.map(function () { return this.id + "=" + count(this); }).get();
$("#result").text(`scope=${scope}; rule=${rule}; count=${target}\nselected=${ids.join(",") || "(none)"}\n${counts.join("; ")}`);
}
$("#scope, #rule, #count").on("change input", apply);
$("#add").on("click", function () {
added++; $("<span>").addClass("item").text("Added " + added).appendTo("#alpha"); apply();
});
$("#reset").on("click", function () {
$("#board").html(initial); added = 0;
$("#scope").val("direct"); $("#rule").val("exact"); $("#count").val(2); apply();
});
apply();
});
</script>
</body>
</html>
Inicialmente só Alpha, com exatamente dois filhos, recebe destaque.
scope=direct; rule=exact; count=2
selected=alpha
alpha=2; beta=1; gamma=0; delta=3
- At least seleciona Alpha e Delta. Exatamente dois difere de pelo menos dois.
- All descendants acrescenta Beta: passa de um para três.
- Exactly 3 seleciona Beta e Delta por descendentes, mas só Delta por Direct children.
- Exactly 0 escolhe Gamma; At least 0 permite zero e escolhe os quatro.
- Após Reset, Add direct item to Alpha leva-a a três; exatamente dois resulta em (none). Nenhum pai é removido.
- Vazio, negativo ou fracionário mostra erro e remove destaques. Reset restaura estrutura e condições.
Total conjunto e teste por pai
Pressione Reset e execute nas ferramentas de desenvolvimento para comparar coleção conjunta com filtro individual:
const $groups = $("#board > .group");
console.log($groups.children(".item").length);
console.log($groups.filter(function () {
return $(this).children(".item").length === 0;
}).map(function () { return this.id; }).get().join(","));
Seis é 2+1+0+3 combinado, sem informar qual pai tem dois. A segunda linha examina cada pai e retorna Gamma sem .item direto.
6
gamma
Uma função normal recebe this como pai atual. Trocar por seta mantendo this quebra a premissa. Com seta, receba explicitamente o segundo argumento elemento do callback.
Uma coleção filtrada salva não reavalia continuamente a condição. Após adicionar, o resultado antigo pode manter Alpha. O exemplo chama apply() com candidatos e números atuais. .filter() não observa alterações do DOM.
Escopo e erros comuns
Defina todos os elementos ou cartões, li ou controles específicos. Aqui só .item conta: Gamma é zero apesar de h2 e texto. Não significa contêiner totalmente vazio. Acrescente explicitamente visibilidade, disponibilidade ou estado dos dados quando necessário.
Se importa apenas existir um descendente, .has() pode ser mais simples. Quantidades exatas e mínimas ficam claras com números. Não confunda nth-child, posição entre irmãos, com quantidade total do pai.
Com milhares de pais e buscas profundas repetidas, limite candidatos e cálculos desnecessários. Mas não reutilize resultados antigos após mudanças estruturais. Confira estado inicial e atualizado.




