Hace ya algún tiempo, Doug Neiner escribía un artículo sobre este mismo tema que es interesante rescatar dado que se aún se continúa cayendo en el mismo error (o, al menos, mala práctica): el uso injustificado del return false en jQuery.
Introducción
Frecuentemente veo en el código de otros desarrolladores la coletilla de terminar siempre una función o un callback jQuery utilizando un return false.
Este recurso es, probablemente, una de las primeras cosas que se aprenden cuando comenzamos a desarrollar aplicaciones y que tiene como fin evitar el comportamiento por defecto del navegador frente a un evento.
Así, solemos encontrar códigos como el siguiente:
¿Os resulta familiar? En el ejemplo anterior, estamos detectando el evento submit de un formulario para realizar una petición al servidor con los datos que contiene vía Ajax. Para evitar que el navegador envie los datos por su cuenta (esto es haciendo el realmente el submit), utilizamos el return false con el que detenemos la ejecución.
Pues es una mala práctica!
Ahí queda eso! Es una mala práctica porque si lo que queremos es evitar el comportamiento por defecto del navegador, disponemos, de métodos propios para hacerlo en lugar de recurrir al return.
La explicación sobre por qué resulta poco ortodoxo utilizar return false es que hacemos más cosas además de la simple cancelación del evento: estamos evitando el concepto de propagación y deteniendo de forma inmediata la ejecución de los posibles callbacks que puedan aparecer con posterioridad.
Para cada uno de estos comportamientos, jQuery cuenta sus propios métodos los cuales deberíamos conocer y manejar: event.preventDefault(), event.stopPropagation() yevent.stopInmediatePropagation().
Escenario
Pensemos en el siguiente escenario: una galería fotográfica donde podemos ver una preview de las imágenes pinchando encima.
El código HTML podría ser el siguiente:
Un marcado sencillo: tenemos un contenedor general con dos imágenes (pequeñas) dentro de sus correspondientes capas; cada imagen tiene un enlace al archivo original (grande), su nombre y su autor. Luego hay un segundo contenedor donde visualizaremos la preview de aquella imagen seleccionada.
Escribamos el código jQuery para que, al pinchar sobre cada imagen, la original se envíe a la capapreview:
A primera vista, el código funciona como se espera. Si pinchamos sobre una imagen, se captura la dirección del enlace enviándola a la imagen preview para que la cargue. Para evitar que el navegador siga dicho enlace redirigiendo al usuario, cancelamos con un return false.
Añadamos ahora una nueva funcionalidad: cada vez que pinchemos sobre la capa que contiene una imagen, añadiremos una clase para indicar que está seleccionada:
Con esto conseguimos que, pinchando sobre una capa, esta quedaría seleccionada (entendemos que la clase picture_selected tiene, por ejemplo, un border rojo para indicarlo).
Pero, ¿y si pinchamos sobre la imagen que está dentro? ¿Se seleccionaría así también su capa? La respuesta es no. Al añadir el return false al click de la imagen, estamos cancelando también la propagación de eventos desde la misma hacia su contenedor. Por lo tanto, la clase picture_selected, nunca llega a añadirse.
jQuery event.preventDefault
El caso más frecuente es el que hemos mencionado arriba: deseamos cancelar o evitar el comportamiento por defecto del navegador frente a un determinado evento. Puede ser por ejemplo, el envío de un formulario o seguir un enlace como el ejemplo anterior.
El siguiente código muestra la forma correcta de hacerlo:
Si observamos, hemos introducido un argumento, e, y ejecutado sobre él el método preventDefault().
Todos los eventos manejados por jQuery se transmiten al callback mediante el primer argumento de la función anónima que lo ejecuta. Por convención, se utiliza la letra e (event) para guardar dicho evento: cachearlo permite efectuar operaciones sobre él como, en este caso, la cancelación de su comportamiento por defecto.
Con esta sencilla instrucción, conservamos la posibilidad de delegar eventos que el return falseprohibe y nuestro código funciona ahora correctamente.
Este comportamiento, sería también aplicable a aquellos eventos aplicados tanto con live como condelegate:
jQuery event.stopPropagation
En ocasiones, podemos necesitar el comportamiento contrario: evitar que un evento se propague sin que afecte al comportamiento natural del navegador.
Podríamos añadir al ejemplo anterior, un enlace hacia la web del autor en cada fotografía. En este caso, puede no interesarnos el que la capa quede seleccionada, ya que abandonamos la página.
El marcado HTML quedaría así:
Para evitar disparar el evento asociado a la capa picture al pinchar sobre el nuevo enlace, usaríamos el siguiente código:
Las ventaja de no utilizar en este caso un return false son obvias: evitariamos que se disparara el evento asociado a la capa pero también estaríamos impidiendo la redirección.
jQuery event.stopImmediatePropagation
En jQuery, todos los eventos asociados a un elemento se ejecutan en el orden en que han sido añadidos. Este metodo permite detener desde su ejecución cualquier otro futuro evento aplicado sobre el mismo objeto.
El siguiente código muestra cómo funciona:
Este tipo de códigos, aunque son raros durante un desarrollo, pueden darse como resultado de añadir bibliotecas de terceros que monitorizan los eventos de determinados elementos. Conocerlo nunca está de más.
Conclusión
Como resumen de todo lo anterior, podemos extraer que el método del return false no es la mejor manera en determinados escenarios para cancelar el comportamiento natural del navegador. Su uso debería limitarse a aquellos casos en los que se prentenda tanto anular este comportamiento como impedir la propagación de eventos. Aún en este supuesto, las guías de estilo jQuery recomiendan ejecutar las instrucciones anteriores por separado:
Como siempre, la idea es mantener un código lo más flexible posible utilizando las herramientas del lenguajes diseñadas para casa caso concreto.