soy Kseso y esto EsCSS

Javascript con Furoya: Cómo añadir estilos si en el contenido hay una palabra clave

Nuevo artículo de Furoya sobre Javascript. En esta ocasión versa sobre cómo saber si hay una palabra concreta en el texto, o no, y en función de ello aplicar unos estilos Css u otros.

Javascript con Furoya: Cómo añadir estilos si en el contenido hay una palabra clave

✎ 0
COLABORACIÓN AUTOR INVITADO
Cómo añadir estilos si en el contenido hay o no cierta cadena textual

Este artículo se va a dividir en tres partes. Más que nada porque exige algún manejo cómodo de nuevos métodos y funciones que recién vamos a ver aquí por primera vez. Así que empezamos con una versión fácil, y dejamos un tiempo para que quien quiera practicar y buscar más información en manuales y tutoriales lo pueda hacer.

A estas alturas todos conocemos en CSS los selectores "avanzados", con los que podemos dar un formato a un elemento según tengan un atributo o valor de atributo conocido.

Pero muchas veces el texto de referencia para aplicar estilos se encuentra en el contenido del elemento, y puede ocurrir que no lo escribamos nosotros. Un caso práctico sería el mostrar en nuestra página unas noticias que provee un servicio contratado, y queremos resaltar el párrafo cuando nos mencionan, o quizá cuando nombren a alguno de los personajes que tengan una afinidad con nuestro sitio.

Hoy vamos a ver cómo "leer" el contenido de elementos para encontrar palabras clave, y así, si las hay, aplicar formatos diferenciados.

Para eso hay tres etapas (una vez que tengamos el documento cargado):

  1. recorrer uno a uno los elementos.
  2. buscar en cada uno la palabra clave que nos interesa.
  3. y agregar una clase diferente a los que tengan al menos una coincidencia.

Para simplificar las cosas vamos a suponer que hay un solo párrafo, y queremos saber si contiene una palabra determinada.

Ya conocemos textContent, que permite capturar el texto dentro de un elemento para tratarlo como una cadena o string. Lo que vamos a ver ahora es otra función que busca caracter a caracter hasta hallar la coincidencia con un texto dado, y devuelve su posición de inicio en forma de número. Es indexOf() y se usa así:

<script type="text/javascript"> alert( "mentalmente".indexOf("mental") ); /*DEVUELVE 0*/ alert( "mentalmente".indexOf("mente") ); /*DEVUELVE 6*/ </script>

El primer mensaje de alerta muestra '0' (cero), porque el índice de "mental" en la palabra "mentalmente" coincide con el caracter 0 (cero). El segundo devuelve '6', porque la subcadena "mente" empieza en el caracter 6.

m e n t a l m e n t e 0 1 2 3 4 5 6 7 8 9 10
¿Y qué pasa si no encuentra nada?
La convención es que devuelva '-1'.
<script type="text/javascript"> alert( "mentalmente".indexOf("espiritual") ); /*DEVUELVE -1*/ %lt;/script>

Ahora ya sabemos que hay una forma de confirmar cuando una palabra se encuentra en un texto. Si indexOf() devuelve '-1', no está, y si devuelve cualquier otro número, entonces sí está. Hay un detalle que hoy no vamos a desarrollar, y es que la coincidencia debe ser exacta. Cualquier diferencia entre mayúsculas o minúsculas (por ejemplo) hace palabras distintas.

Hay maneras de ajustar la búsqueda usando expresiones regulares, que muchos ya conoceréis de javascript o también por las usadas en HTML 5: son las mismas que se usan en el atributo pattern="" de los formularios.

Y usar match() o search() son alternativas a indexOf(), con sutiles diferencias.

Veamos un HTML simple.

<!DOCTYPE html> <html lang="es-ar"> <head> <meta charset="utf-8" /> <body> <p>alfa, bravo, charly, delta, eco</p> </body> </html>

La idea es confirmar si el párrafo contiene una palabra que estamos buscando, y para decirle al "buscador" cuál queremos, vamos a usar un ya conocido mensaje modal, el prompt(" "," "), que funciona así:

  • En el primer juego de comillas ponemos una descripción de lo que el usuario debe hacer.
  • En el segundo podemos poner un ejemplo que se va a ver en un campo de texto donde el usuario debe tipear y que tiene 2 botones para cerrarlo:
    1. Aceptar devuelve al escript el valor que tenga escrito en el campo
    2. Cancelar cierra sin enviar el valor, y el prompt devuelve la palabra reservada null, que para el script es un valor de referencia que le permite saber que no es un valor elegido.
      Esto será importante cuando debamos confirmar si el usuario canceló la operación aunque haya escrito un texto, o si el texto a buscar es la cadena null (p.e., como parte de la palabra "nulling"). ;-)

Éste sería un ejemplo en forma de código:

<!DOCTYPE html> <html lang="es-ar"> <head> <meta charset="utf-8" /> <style type="text/css"> .parrafo { font: bold 2em/2 fantasy; text-align: center; background: yellow; } .nop { transition: background 10s linear; background: tomato; } .see { transition: background 10s linear; background: yellowgreen; } </style> </head> <body> <p class=parrafo>alfa. bravo. charly. delta. eco.</p> <script type="text/javascript"> /* EL TEXTO QUE BUSCAMOS Y LO ASIGNAMOS A UNA VARIABLE*/ var miTextoABuscar = prompt("Escriba una palabra del documento (u otra).", "delta"); alert("miTextoABuscar : " + miTextoABuscar); /*UBICAMOS EL PÁRRAFO DEL DOCUMENTO Y LO 'GUARDAMOS' EN miParrafo*/ var miParrafo = document.querySelector("p"); /*LE EXTRAEMOS EL CONTENIDO DE TEXTO Y LO GUARDAMOS EN miContenido*/ var miContenido = miParrafo.textContent; alert("miContenido : " + miContenido); /*EN LA CADENA SACADA DEL PÁRRAFO, UBICAMOS LA POSICIÓN DEL TEXTO BUSCADO*/ var miPosicion = miContenido.indexOf(miTextoABuscar); alert("miPosicion : " + miPosicion); /*ELEGIMOS QUÉ HACER EN CASO DE QUE LA POSICIÓN SEA -1 (SIN COINCIDENCIA) O SEA OTRA (HAY COINCIDENCIA)*/ if(miPosicion == -1) { /*AGREGAMOS A LOS VALORES DE class EL NUEVO VALOR "nop"*/ miParrafo.classList.add("nop"); } else { /* O AGREGAMOS A LOS VALORES DE class EL NUEVO VALOR "see"*/ miParrafo.classList.add("see"); } alert("miParrafo.className : " + miParrafo.className); </script> </body> </html>

NOTA DEL AUTOR: No hay pen de ejemplo para evitar que los modales se disparen con las consiguientes molestias. Para ver en acción el script sólo necesitas copiar y pegar el código y ejecuatarlo.

Con los comentarios puestos en el script y los mensajes de alerta confirmando cada paso, no debería haber problemas para entenderlo. Sin embargo, hay algunas novedades que voy a explicar más detalladamente.

Como tenemos 2 posibilidades (-1 si la palabra no está y otro número si sí está) tenemos que usar un condicional para que agregue (con add()) una clase u otra al párrafo dependiendo del caso. La sintaxis del condicional if else se interpreta así:

si( se cumple esta condición ) {
 ejecuto esta operación
}
de cualquier otro modo {
 ejecuto esta otra operación
}

En este caso la condición es que comparando miPosicion con el número -1, ambos sean iguales (el doble signo de igual es un operador de comparación de igualdad de valor). Si miPosicion es -1 entonces resultó que el escript no halló la palabra del prompt en el contenido del párrafo, y al final de los valores del atributo class del párrafo va a agregar nop. De otra forma (si miPosicion tiene otro número) resulta que la palabra sí apareció en alguna posición, entonces la primera condición no se cumple, y pasa a la segunda (y última en este caso) que agrega a las clases el valor see.

Un detalle: Al comienzo hablamos del valor null que devuelve el mensaje modal si lo cancelamos. Tal como está el ejemplo, si clickamos en "Cancel" el escript trabaja hasta el final, y como null de ninguna forma puede ser igual a -1, el párrafo se tiñe de rojo. Si agregamos otra condición, podemos detener el cambio de clase.

/*SI SE CANCELÓ*/ if(miTextoABuscar == null) { miParrafo.style.textDecoration = "line-through"; } /*SI NO SE ENCONTRÓ COINCIDENCIA (Y ADEMÁS NO SE CANCELÓ)*/ else if(miPosicion == -1) { miParrafo.classList.add("nop"); } /*OTRO CASO (QUE SÓLO PUEDE SER "ACEPTADO" Y "ENCONTRADO")*/ else { miParrafo.classList.add("see"); }

La sintaxis es sencilla:

si( miTextoABuscar es null ) {
 a "miParrafo" le doy el estilo inline de tachado (método alternativo, en vez de las clases)
}
de otro modo, si( miPosicion es -1 ) {
 agrego a las clases de "miParrafo" el valor "nop"
}
de cualquier otro modo {
 agrego a las clases de "miParrafo" el valor "see"
}

Obviamente la nueva condición es un filtro, porque como ya dijimos en el ejemplo anterior, si se cancela resulta que null no será igual a -1 (ni siquiera es un número) y daría el mismo resultado que si no hay coincidencia. Con estas condicionales if; else if; else si se cumple una, a las siguientes las salta. Usando if; if; else, probaría cada condición hasta llegar a else

Aquí ya estamos viendo algo de lógica básica de programación. Como las máquinas no piensan, uno tiene que decirles cómo comportarse en todos los casos, y probar cuál es la mejor combinación de instrucciones para conseguir el efecto que buscamos.

A partir de estudiar esta situación, estoy seguro de que más de uno va a entender por qué resulta tan desesperante para un desarrollador cuando un cliente espera que su programa tenga criterio propio y razone como una persona (vamos, que razone como él, que tampoco va a ser como piense el vecino de enfrente, ¿no?).

Autoría

Furoya: Autor del artículo

Artículo original de Furoya.
La intención del autor con sus colaboraciones no es que los artículos sirvan para hacer un copy&paste de códigos sino que comprendas y aprendas la lógica y el cómo trabaja javaScript.
Y a partir de lo expuesto experimentes tú.
El autor del post y el editor del blog te animamos a que plantees tus dudas o reflexiones y que compartas tus realizaciones en base a lo expuesto en los comentarios. Recuerda que puedes incluir pens (ejemplos en Codepen.io) en ellos.