Seleccionar elemento por coincidencia exacta de su contenido

161

Muy bien, me pregunto si hay una manera de hacer que el :contains()selector de jQuery seleccione elementos con solo la cadena que se escribe

por ejemplo -

<p>hello</p>
<p>hello world</p>

$('p:contains("hello")').css('font-weight', 'bold');

El selector seleccionará ambos pelementos y los pondrá en negrita, pero quiero que seleccione solo el primero.

Julian
fuente
Bueno, podrías anular el :containsselector con tu propio código, pero ¿no supongo que eso es lo que querías decir?
Blazemonger
Puede definir un selector personalizado: stackoverflow.com/questions/12244929/…
BLSully
Posible duplicado de: Selector Jquery, contiene a iguales
BinaryTox1n
posible duplicado de Seleccionar enlace por texto (coincidencia exacta)
FishBasketGordo

Respuestas:

215

No, no hay un selector jQuery (o CSS) que haga eso.

Puedes usar fácilmente filter:

$("p").filter(function() {
    return $(this).text() === "hello";
}).css("font-weight", "bold");

No es un selector , pero hace el trabajo. :-)

Si desea manejar espacios en blanco antes o después del "hola", puede agregar un mensaje $.trimallí:

return $.trim($(this).text()) === "hello";

Para los optimizadores prematuras por ahí, si no te importa que no coincide <p><span>hello</span></p>y similares, puede evitar las llamadas a $y textutilizando innerHTMLdirectamente:

return this.innerHTML === "hello";

... pero tendrías que tener muchos párrafos para que importen, tantos que probablemente tengas otros problemas primero. :-)

TJ Crowder
fuente
77
También podría quererlo $.trimde cualquier espacio en blanco perdido antes de hacer la comparación.
Blazemonger
Por alguna razón, tuve que usar "==" para que esto funcione en lugar de "===".
Stephan
3
@Stephan: Si estuvieras comparando con un número, tendrías que usar ==( == 2) o poner el número en una cadena ( === "2"), porque el valor que obtienes text()o innerHTMLsiempre es una cadena. Si estaba comparando con una cadena, no importa si usa ==o ===.
TJ Crowder
Es una pena que jQuery haya implementado, :containsque es bastante más complejo, pero no ha implementado un selector para la coincidencia exacta del texto. = {
Paulo Bueno
54

Intente agregar una pseudo función extendida:

$.expr[':'].textEquals = $.expr.createPseudo(function(arg) {
    return function( elem ) {
        return $(elem).text().match("^" + arg + "$");
    };
});

Entonces puedes hacer:

$('p:textEquals("Hello World")');
Amadu Bah
fuente
2
gran solución: pequeña adición: para asegurarme de no sobrescribir un expr existente, yo haría:$.expr[':'].textEquals = $.expr[':'].textEquals || $.expr.createPseudo(function(arg) {
Mischa Molhoek
9

Puede usar la función filter () de jQuery para lograr esto.

$("p").filter(function() {
// Matches exact string   
return $(this).text() === "Hello World";
}).css("font-weight", "bold");
dsgriffin
fuente
9

Entonces, la respuesta de Amandu funciona principalmente. Sin embargo, al usarlo en la naturaleza, me encontré con algunos problemas, donde las cosas que hubiera esperado encontrar no se encontraban. Esto se debió a que a veces hay espacios en blanco al azar que rodean el texto del elemento. Creo que si está buscando "Hello World", todavía querrá que coincida con "Hello World", o incluso "Hello World \ n". Por lo tanto, acabo de agregar el método "trim ()" a la función, que elimina los espacios en blanco circundantes, y comenzó a funcionar mejor.

Específicamente...

$.expr[':'].textEquals = function(el, i, m) {
    var searchText = m[3];
    var match = $(el).text().trim().match("^" + searchText + "$")
    return match && match.length > 0;
}

Además, tenga en cuenta que esta respuesta es extremadamente similar a Seleccionar enlace por texto (coincidencia exacta)

Y la nota secundaria ... trimsolo elimina los espacios en blanco antes y después del texto buscado. No elimina los espacios en blanco en el medio de las palabras. Creo que este es un comportamiento deseable, pero podría cambiarlo si lo desea.

bwest87
fuente
5

Encontré una forma que funciona para mí. No es 100% exacto, pero elimina todas las cadenas que contienen más que solo la palabra que estoy buscando porque verifico que la cadena no contenga espacios individuales también. Por cierto, no necesitas estos "". jQuery sabe que estás buscando una cadena. Asegúrese de tener solo un espacio en la parte: contiene (), de lo contrario no funcionará.

<p>hello</p>
<p>hello world</p>
$('p:contains(hello):not(:contains( ))').css('font-weight', 'bold');

Y sí, sé que no funcionará si tienes cosas como <p>helloworld</p>

rf1234
fuente
1
¡Uso inteligente de coincidencias simples con contiene (..) sin usar un filtro o extensión! No funcionará en nada que requiera espacios en el primero contiene (..), pero tratar de encontrar una solución para eso. ¡Gracias!
JoePC
3

Como TJ Crowder dijo anteriormente, la función de filtro hace maravillas. No estaba funcionando para mí en mi caso específico. Necesitaba buscar múltiples tablas y sus respectivas etiquetas td dentro de un div (en este caso, un diálogo jQuery).

$("#MyJqueryDialog table tr td").filter(function () {
    // The following implies that there is some text inside the td tag.
    if ($.trim($(this).text()) == "Hello World!") {
       // Perform specific task.
    }
});

¡Espero que esto sea útil para alguien!

Greg A
fuente
Soy bastante nuevo en jquery, pero creo que sería un poco mejor usar each () en lugar de filter () ya que el objetivo del filtro es devolver una submatriz. Pero definitivamente inspiró la solución, ya que tuve los mismos problemas :)
JeopardyTempest
0

Una línea que funciona con bibliotecas alternativas a jQuery:

$('p').filter((i, p) => $(p).text().trim() === "hello").css('font-weight', 'bold');

Y este es el equivalente a un a:contains("pattern")selector de jQuery :

var res = $('a').filter((i, a) => $(a).text().match(/pattern/));
leogama
fuente
-4

El .first () ayudará aquí

$('p:contains("hello")').first().css('font-weight', 'bold');
tymeJV
fuente
Claro ... en este caso específico. ¿Qué pasa si la orden no se conoce en tiempo de desarrollo?
BLSully