Procurando pelo método jQuery find (..) que inclui o nó atual

134

O método transversal do jQuery find (..) não inclui o nó atual - ele começa com os filhos do nó atual. Qual é a melhor maneira de chamar uma operação de localização que inclua o nó atual em seu algoritmo de correspondência? Examinando os documentos, nada imediatamente salta para mim.

John K
fonte

Respostas:

153

Para o jQuery 1.8 e superior, você pode usar .addBack(). É preciso um seletor para que você não precise filtrar o resultado:

object.find('selector').addBack('selector')

Antes do jQuery 1.8, você estava preso .andSelf()(agora obsoleto e removido), que precisava de filtragem:

object.find('selector').andSelf().filter('selector')
Robert
fonte
5
Agrupei isso como um plugin jquery.findIncludeSelf, registrado no bower. Veja github.com/ronen/jquery.findIncludeSelf
ronen
18
@ronen Um arquivo extra para algo que pode ser feito em uma linha? Obrigado, mas não, obrigado.
6
@ prc322 um arquivo extra não me incomoda em implantações que agrupam todo o javascript em um único arquivo de qualquer maneira. Geralmente, prefiro usar métodos de biblioteca (testados) mesmo para coisas simples, em vez de sobrecarregar meu código com coisas que acho mais difíceis de ler e que apresentam mais possibilidades de erros. Neste caso em particular, IMHO a necessidade de especificar 'selector'duas vezes torna o encapsulamento extra desejável. YMMV
ronen
Ok, então eu posso estar sendo grossa, mas para que você não precise especificar 'selector'duas vezes (como mencionado por @ronen), você não poderia simplesmente usar object.parent().find('selector')??? - Dito isto, gosto da idéia de uma biblioteca que faz isso por você.
Sam
8
@ circa1983 object.parent().find('selector')inclui irmãos objecte seus descendentes.
Robert
41

Você não pode fazer isso diretamente, o mais próximo que consigo pensar é usar .andSelf()e chamar .filter(), assim:

$(selector).find(oSelector).andSelf().filter(oSelector)
//or...
$(selector).find('*').andSelf().filter(oSelector);

Infelizmente .andSelf()não é necessário um seletor, o que seria útil.

Nick Craver
fonte
7
Você até adicionou um comentário à página jquery logo após responder a essa pergunta api.jquery.com/andSelf/#comment-50124533 Agora, isso é exaustivo. Agradável! Fiz minha diligência e 'gostei' dessa também.
John K
2
O segundo seria incrivelmente lento. O primeiro é simplesmente lento.
Tgr
@ Tgr - Eu não discordo, embora o primeiro não deva ser esse show, a menos que você esteja lidando com um número muito grande de elementos. Se você não precisar encadear, poderá ignorar a re-filtragem desses elementos, com certeza.
Nick Craver
3
Curiosamente, closest(..)inclui o elemento DOM atual e a árvore, enquanto todos os métodos transversais de árvore, como find(..)etc, não correspondem ao elemento atual. É como se a equipe do jQuery os tivesse implementado propositalmente, sem sobreposição quando as duas operações foram usadas juntas para uma pesquisa vertical completa.
John K
17
Lembre-se de que .andSelf () foi descontinuado na v1.8 e substituído por .addBack () que usa um seletor como argumento. Veja api.jquery.com/addBack
kkara
9

Definir

$.fn.findSelf = function(selector) {
    var result = this.find(selector);
    this.each(function() {
        if ($(this).is(selector)) {
            result.add($(this));
        }
    });
    return result;
};

então use

$.findSelf(selector);

ao invés de

$find(selector);

Infelizmente, o jQuery não possui esse recurso. Realmente estranho por tantos anos de desenvolvimento. Meus manipuladores AJAX não foram aplicados a alguns dos principais elementos devido a como o .find () funciona.

Dmitriy Sintsov
fonte
Isso é buggy. Ele adiciona todo o "self", mesmo que apenas um deles corresponda ... - Uma razão para esse bug é um método jQuery de má qualidade ...
Robert Siemer
Tentei corrigir o bug que você relatou. Funciona corretamente agora?
Dmitriy Sintsov 23/03
A maioria das outras respostas é usada filter()lá, o que faz mais sentido.
Robert Siemer
5
$('selector').find('otherSelector').add($('selector').filter('otherSelector'))

Você pode armazenar $('selector')em uma variável para acelerar. Você pode até escrever uma função personalizada para isso, se precisar muito:

$.fn.andFind = function(expr) {
  return this.find(expr).add(this.filter(expr));
};

$('selector').andFind('otherSelector')
Tgr
fonte
Isso só funciona se você estiver começando com um seletor, o que pode não ser o caso. Além disso, é incorreto, o $('selector').find('otherSelector').add($('otherSelector'))que você tem agora é equivalente .andSelf(). Por fim, o .andFind()filtro não é baseado na expressão, você precisaria .add($(this).filter(expr)):) :)
Nick Craver
@ Nick Craver: sim, eu esqueci a parte de filtragem, corrigida agora. Realmente não importa se $('selector')foi substituído por algum outro método de obter um objeto jQuery (se é isso que você quis dizer com não iniciar com um seletor), ele add()pode lidar com tudo da mesma maneira que $()pode.
Tgr
Meu argumento foi que você $('selector')pode estar $('selector').children('filter').closest('.class').last()... pode estar em cadeia e você não tem idéia do que está adicionando, então a solução genérica deve pegar o objeto anterior como o filtro :)
Nick Craver
Ainda não vejo por que isso seria um problema. thisé qualquer objeto jQuery em que um plug-in foi chamado. Poderia ser o resultado de uma cadeia de chamadas.
Tg
5

A resposta aceita é muito ineficiente e filtra o conjunto de elementos que já correspondem.

//find descendants that match the selector
var $selection = $context.find(selector);
//filter the parent/context based on the selector and add it
$selection = $selection.add($context.filter(selector);
erikrestificar
fonte
3

Se você deseja que o encadeamento funcione corretamente, use o trecho abaixo.

$.fn.findBack = function(expr) {
    var r = this.find(expr);
    if (this.is(expr)) r = r.add(this);
    return this.pushStack(r);
};

Após a chamada da função final, ele retorna o elemento #foo.

$('#foo')
    .findBack('.red')
        .css('color', 'red')
    .end()
    .removeAttr('id');

Sem definir plugins extras, você está preso a isso.

$('#foo')
    .find('.red')
        .addBack('.red')
            .css('color', 'red')
        .end()
    .end()
    .removeAttr('id');
SeregPie
fonte
Ah, não ... Se thismais de um elemento this.is()já estiver satisfeito, se apenas um deles corresponder.
Robert Siemer
3

Caso esteja procurando exatamente um elemento , o atual ou o outro, pode usar:

result = elem.is(selector) ? elem : elem.find(selector);

Caso esteja procurando por vários elementos, você pode usar:

result = elem.filter(selector).add(elem.find(selector));

O uso de andSelf/andBack é bastante raro, não sei por quê. Talvez por causa dos problemas de desempenho que alguns caras mencionaram antes de mim.

(Agora notei que o Tgr já deu essa segunda solução)

oriadam
fonte
2

Sei que essa é uma pergunta antiga, mas existe uma maneira mais correta. Se a ordem é importante, por exemplo, quando você está combinando um seletor como :first, escrevi uma pequena função que retornará exatamente o mesmo resultado como se find()realmente incluísse o conjunto atual de elementos:

$.fn.findAll = function(selector) {
  var $result = $();

  for(var i = 0; i < this.length; i++) {
    $result = $result.add(this.eq(i).filter(selector));
    $result = $result.add(this.eq(i).find(selector));
  }

  return $result.filter(selector);
};

Não será eficiente de forma alguma, mas é o melhor que eu tenho para manter a ordem correta.

Justin Warkentin
fonte
1

Eu acho andSelfque é o que você quer:

obj.find(selector).andSelf()

Observe que isso sempre adicionará novamente o nó atual, independentemente de corresponder ou não ao seletor.

interjay
fonte
1

Se você está olhando estritamente nos nós atuais, simplesmente faz

$(html).filter('selector')
mikewasmike
fonte
0

Eu estava tentando encontrar uma solução que não se repita (ou seja, não insere o mesmo seletor duas vezes).

E essa pequena extensão jQuery faz isso:

jQuery.fn.findWithSelf = function(...args) {
  return this.pushStack(this.find(...args).add(this.filter(...args)));
};

Ele combina find()(apenas descendentes) com filter()(apenas o conjunto atual) e suporta os argumentos que ambos comem. O pushStack()permite.end() trabalhar como esperado.

Use assim:

$(element).findWithSelf('.target')
Robert Siemer
fonte
-2

Aqui está a verdade certa (mas triste):

$(selector).parent().find(oSelector).filter($(selector).find('*'))

http://jsfiddle.net/SergeJcqmn/MeQb8/2/

Sarja
fonte
não funciona com nós desanexados (e o próprio documento), no entanto.
John Dvorak
2
Não, isso se removerá $(selector)do conjunto em todos os casos.
John Dvorak