Buscando el método jQuery find (..) que incluye el nodo actual

134

El método transversal jQuery find (..) no incluye el nodo actual, comienza con los hijos del nodo actual. ¿Cuál es la mejor manera de llamar a una operación de búsqueda que incluye el nodo actual en su algoritmo de coincidencia? Mirando a través de los documentos, nada me sobresalta de inmediato.

John K
fuente

Respuestas:

153

Para jQuery 1.8 y superior, puede usar .addBack(). Se necesita un selector para que no necesite filtrar el resultado:

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

Antes de jQuery 1.8 con el que estaba atrapado .andSelf()(ahora en desuso y eliminado) que luego necesitaba filtrado:

object.find('selector').andSelf().filter('selector')
Robert
fuente
55
He incluido esto como un complemento jquery.findIncludeSelf, registrado en bower. Ver github.com/ronen/jquery.findIncludeSelf
ronen el
18
@ronen ¿Un archivo adicional para algo que se puede hacer en una línea? Gracias pero no gracias.
66
@ prc322 un archivo adicional no me molesta para las implementaciones que agrupan todo el javascript en un solo archivo de todos modos. En general, prefiero usar métodos de biblioteca (probados) incluso para cosas simples, en lugar de saturar mi código con cosas que me resultan más difíciles de leer y que introducen más posibilidades de errores. En este caso en particular, en mi humilde opinión, la necesidad de especificar 'selector'dos veces hace que la encapsulación sea más deseable. YMMV
ronen
Ok, entonces podría estar siendo grueso, pero no tienes que especificar 'selector'dos veces, (como mencionó @ronen), ¿no podrías simplemente usarlo object.parent().find('selector')? - Dicho esto, me gusta la idea de una biblioteca que lo haga por ti.
Sam
8
@ circa1983 object.parent().find('selector')incluye hermanos de objecty sus descendientes.
Robert
41

No puedes hacer esto directamente, lo más cerca que puedo pensar es en usar .andSelf()y llamar .filter(), así:

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

Lamentablemente .andSelf()no lleva un selector, lo que sería útil.

Nick Craver
fuente
77
Incluso agregaste un comentario a la página de jquery justo después de responder esta pregunta api.jquery.com/andSelf/#comment-50124533 Ahora que es minucioso. ¡Agradable! Hice mi diligencia debida y 'me gustó' esa también.
John K
2
El segundo sería alucinantemente lento. El primero es simplemente lento.
Tgr
@Tgr - No estoy en desacuerdo, aunque la primera no debería ser ese programa a menos que usted está tratando con un muy gran número de elementos. Si no necesita encadenar, puede omitir volver a filtrar esos elementos con seguridad.
Nick Craver
3
Curiosamente, closest(..)incluye el elemento DOM actual y el árbol hacia arriba, mientras que todos los métodos de recorrido hacia abajo del árbol, como find(..)etc., no coinciden con el elemento actual. Es como si el equipo de jQuery los implementara a propósito para que no se superpusieran cuando ambas operaciones se usaran juntas para una búsqueda vertical completa.
John K
17
Tenga en cuenta que .andSelf () ha quedado en desuso a partir de v1.8 y reemplazado con .addBack () que toma un selector como argumento. Ver 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;
};

luego usa

$.findSelf(selector);

en vez de

$find(selector);

Lamentablemente, jQuery no tiene esto incorporado. Realmente extraño por tantos años de desarrollo. Mis controladores AJAX no se aplicaron a algunos elementos principales debido a cómo funciona .find ().

Dmitriy Sintsov
fuente
Esto tiene errores. Agrega todo "self", incluso si solo uno de ellos coincide ... - Una razón para este error es un método jQuery mal llamado ...
Robert Siemer
Traté de corregir el error que ha informado. ¿Funciona correctamente ahora?
Dmitriy Sintsov
La mayoría de las otras respuestas se usan filter()allí, lo que tiene más sentido.
Robert Siemer
5
$('selector').find('otherSelector').add($('selector').filter('otherSelector'))

Puede almacenar $('selector')en una variable para acelerar. Incluso puede escribir una función personalizada para esto si la necesita mucho:

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

$('selector').andFind('otherSelector')
Tgr
fuente
Sin embargo, esto solo funciona si está comenzando con un selector, lo que puede no ser el caso. Además, es incorrecto, sería $('selector').find('otherSelector').add($('otherSelector')), lo que tienes ahora es equivalente a .andSelf(). Por último, el .andFind()filtro no se basa en la expresión, necesitarías .add($(this).filter(expr)):)
Nick Craver
@ Nick Craver: sí, olvidé la parte de filtrado, arreglada ahora. Realmente no importa si $('selector')se reemplaza por algún otro método para obtener un objeto jQuery (si eso es lo que quiso decir al no comenzar con un selector), add()puede manejar cualquier cosa de la misma manera $().
Tgr
Mi punto es que $('selector')puede ser $('selector').children('filter').closest('.class').last()... puede estar en una cadena y no tiene idea de cuál es el objeto que está agregando, por lo que la solución genérica debería tomar el objeto anterior como lo hace el filtro :)
Nick Craver
Todavía no veo por qué eso sería un problema. thises cualquier objeto jQuery en el que se invocó un complemento También podría ser el resultado de una cadena de llamadas.
Tgr
5

La respuesta aceptada es muy ineficiente y filtra el conjunto de elementos que ya coinciden.

//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
fuente
3

Si desea que el encadenamiento funcione correctamente, use el fragmento a continuación.

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

Después de la llamada de la función final, devuelve el elemento #foo.

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

Sin definir complementos adicionales, estás atascado con esto.

$('#foo')
    .find('.red')
        .addBack('.red')
            .css('color', 'red')
        .end()
    .end()
    .removeAttr('id');
SeregPie
fuente
Ah, no ... Si thishay más de un elemento this.is()ya está satisfecho si solo uno de ellos coincide.
Robert Siemer
3

En caso de que esté buscando exactamente un elemento , ya sea el elemento actual o uno dentro de él, puede usar:

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

En caso de que esté buscando múltiples elementos , puede usar:

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

El uso de andSelf/ andBackes bastante raro, no estoy seguro de por qué. Quizás por los problemas de rendimiento que algunos tipos mencionaron antes que yo.

(Ahora noté que Tgr ya dio esa segunda solución)

oriadam
fuente
2

Sé que esta es una vieja pregunta, pero hay una forma más correcta. Si el orden es importante, por ejemplo, cuando está haciendo coincidir un selector como :first, escribí una pequeña función que devolverá exactamente el mismo resultado que si find()realmente incluyera el conjunto actual 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);
};

No va a ser eficiente de ninguna manera, pero es lo mejor que he encontrado para mantener el orden adecuado.

Justin Warkentin
fuente
1

Creo que andSelfes lo que quieres:

obj.find(selector).andSelf()

Tenga en cuenta que esto siempre volverá a agregar el nodo actual, ya sea que coincida o no con el selector.

interjay
fuente
1

Si está buscando estrictamente en los nodos actuales, simplemente simplemente haga

$(html).filter('selector')
Mikewasmike
fuente
0

Estaba tratando de encontrar una solución que no se repita (es decir, no ingresar el mismo selector dos veces).

Y esta pequeña extensión jQuery lo hace:

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

Combina find()(solo descendientes) con filter()(solo conjunto actual) y admite cualquier argumento que ambos coman. El pushStack()permite .end()trabajar como se esperaba.

Usar así:

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

Aquí está la verdad correcta (pero triste):

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

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

Sarga
fuente
sin embargo, no funciona con nodos separados (y el documento en sí).
John Dvorak
2
Uh, no, esto se eliminará $(selector)del conjunto en todos los casos.
John Dvorak