Ardilla Quio Ardilla Quio

30 de Diciembre de 2011

jQuery: asociar eventos a elementos HTML creados dinámicamente

Para asociar eventos a elementos HTML con jQuery basta con usar bind() (o cualquiera de sus variantes) en el elemento y, cuando se cargue el código javascript, el evento quedará asociado. El problema viene dado cuando el elemento al que queremos asociar un evento no existe en el momento de cargar el javascript, sino que será creado dinámicamente en algún momento. Hasta que el elemento exista, no se le pueden asociar eventos. En este artículo veremos cómo podemos solucionar este problema con la función on() de jQuery.

Asociando eventos con bind

Para ilustrar el caso, voy a poner un ejemplo de lo que podríamos esperar que funcionase. Supongamos que tenemos este HTML:

<div id="blog-test-cont">
	<p class="blog-test">Pulsa para probar</p>
</div>

El código javascript sería este:

var bt_count = 0;
$("#blog-test-cont .blog-test").bind("click", function(){
	$(this).after("<p class=\"blog-test\">Pulsa para probar " + (++bt_count) + "</p>");
});

En este caso, como asociamos el evento a todos los elementos que tienen la clase blog-test, podríamos pensar que este evento se asociaría a todos los elementos que se crean dinámicamente con esa clase. Vamos a comprobar que sólo el elemento creado de antemano tiene este comportamiento:

Pulsa para probar

Esto se debe a que cuando se ejecuta el javascript, éste recorre el DOM y asocia el evento a todos los elementos que existen en ese momento que tengan la clase blog-test (descendientes del elemento blog-test-cont). Cuando se crean los elementos de forma dinámica, el javascript ya se ha ejecutado y, por lo tanto, los elementos creados después no tienen asociado el evento.

Asociando eventos con on

Este código sólo es válido para jQuery 1.7 o superior. Para versiones anteriores puede usarse delegate() (versión 1.4.3 o superior) o live(). En el último apartado veremos el mismo código con estas dos funciones.

Para que el código funcione como nosotros esperamos, en lugar de usar bind(), debemos usar on(), de esta forma:

var bt_count = 0;
$("#blog-test-cont").on("click", ".blog-test", function(){
	$(this).after("<p class=\"blog-test\">Pulsa para probar " + (++bt_count) + "</p>");
});

Veamos cómo funciona ahora:

Pulsa para probar

Podemos comprobar que ahora todos los elementos creados dinámicamente tienen el mismo comportamiento que el creado de antemano.

Esto se debe a que la función on() no asocia el evento a los elementos con clase blog-test, como hace bind(), sino que asocia el código al elemento blog-test-cont de forma que cuando el evento se dispara y se propaga por el DOM, ascendiendo hasta éste, comprueba si el elemento objetivo tiene clase blog-test y, en caso afirmativo, dispara el evento sobre él. De esta forma, no importa en qué momento se haya creado el elemento objetivo, ya que la comprobación se hace siempre que se ejecuta la acción.

Versiones anteriores de jQuery

El mismo código para versiones de jQuery menores que 1.7 y mayores o iguales a 1.4.3:

var bt_count = 0;
$("#blog-test-cont").delegate(".blog-test", "click", function(){
	$(this).after("<p class=\"blog-test\">Pulsa para probar " + (++bt_count) + "</p>");
});

El mismo código para versiones de jQuery menores que 1.4.3 y mayores o iguales a 1.3:

var bt_count = 0;
$("#blog-test-cont .blog-test").live("click", function(){
	$(this).after("<p class=\"blog-test\">Pulsa para probar " + (++bt_count) + "</p>");
});

53 comentarios

JuanFTP

20/08/2018 03:43:38

Muy bueno, me ha ayudado de mucho, un saludo.

KanguroAndino

14/08/2018 16:12:13

Gracias, realmente fue muy util

Charly

03/04/2018 18:13:44

Excelente!

Me solucionaste la vida.

Mil gracias!

juanjo

21/11/2017 14:02:16

ejemplo: <?php ifisset($nombre)echo '$nombre' ?>

juanjo.

21/11/2017 14:00:28

Hola respecto al envio de formulario los datos se pierden siempre que se usa php, hay que guardar los datos en una variable y volverla a sacar dentro del campo que quieras mostrarlo. un saludo

Javier

03/10/2017 21:11:55

Muchísimas gracias por esa explicación tan completa y sencilla de entender

Anonima

19/04/2017 00:32:42

Te amo!!! Gracias.

Andrés Benavides

26/01/2017 21:29:26

Gracias parcero, siempre había luchado con eso jejejejeje

canorioss

24/11/2016 20:57:20

Ups! Escribí un poco a prisa...

correcciones:

*sabía que debía existir una forma de solucionarlo.

** todo funcione muy bien y ahora veo que es muy simple.

@canorioss

24/11/2016 20:51:55

Excelente hermano, sabía que renuncie existir una forma de solucionarlo. Yo estoy trabajando con una tabla y me sorprendí al ver que no funcionaban los <a class="eliminarItem">Eliminar</a> creados mediante ajax y jquery...

Al principio no entendía y no podía implementar tu método pero viendo y analizando mas a fondo y leyendo los comentarios he logrado que todo funcione muy bien y ahora brinque es muy simple..

Gracias Luis y a los que comentaron y pusieron ejemplos.

Anónimo

28/09/2016 18:06:02

Excelente

Anónimo

30/08/2016 21:38:41

holas tengo un problema, resulta que estoy generando un formulario dinamicamente como lo muestra en el comienzao pero a memdida que van saliendo tengo 2 select los cuales los lleno desde una tabla de la base de datos con una funcion y ajax pero me rellena el inicial y los que comienzan a salir no se m despliega nada si alguien m puede ayudar le agradeceria mucho. de ante mano muchas gracias

Anónimo

04/02/2016 15:31:36

Loco me ayudó mucho. Gracias!

Anónimo

03/02/2016 05:39:09

gracias, me sirvio de mucho

Anónimo

08/12/2015 23:40:16

y si el id no existe aun osea el q usas primero para crear el segundo bloque ... si no que se añade despues ..

te funcionara ?? ... saludos .. :D ... por q no me funciona :(

carlos de la o

15/10/2015 23:42:54

muy bueno gracias

Carlos Enrique

30/09/2015 20:39:04

Hola compañeros también pueden usar este código:

$('body').on('click','a.pruebita',function(e){

e.preventDefault();

alert('Joder!!! esto es una prueba :D ');

});

Carlos Enrique

29/09/2015 16:23:38

Excelente pana, al principio pensé que el click se estaba haciendo en el div con el id, pero luego de ver el código un poco mas, vi que no es así sino al elemento que tiene la clase. Gracias por la documentación

saludos!!!

Gumiel

27/07/2015 16:58:58

muy buen articulo ;)

Agradecid@

01/07/2015 11:43:30

¡Genial! Me ha resultado muy útil porque me estaba volviendo loc@.

Gracias por tu aporte.

yeison

13/06/2015 00:33:11

Gracias por el aporte.. fue de gran ayuda para mi

Anónimo

10/06/2015 17:37:12

Como hago para enviar los datos a una base de datos.

Y despues como hago para que me muestre en el formulario los datos guardados tanto como inserte.

Gracias

Anónimo

21/04/2015 21:41:24

Tengo un problema, a mi el evento se me dispara tantas veces como lineas me queden para acabar de recorrer el objeto, esto trae el contenido de una tabla y al asociarle un evento on click me salta el alert tantas veces como lineas me queden por recorrer.

$.ajax({

type:"post",

url: "enviarTweet.php",

data: stringDato,

success: function(respuesta){

respuesta = $.parseJSON(respuesta);

var cont=1;

for(var i in respuesta){

$("#tweets").append("<div><p>"+respuesta[i].tw_text+"</p><input type='button' name='"+cont+"' value='EDITAR' /></div>");

$("#tweets").on("click","input",function(){alert("Has editado "+this.name);});

cont++;

}

}

});

Anónimo

05/04/2015 14:04:32

Muy buen aporte!!! Muy bien explicado y muy aclaratorio :) Gracias!

Oscar David Díaz Fortaleché

11/02/2015 16:23:28

Gracias, estaba como loco buscando algo que me resolviera ese pequeño problema.

Iván

03/02/2015 01:25:47

Muchas gracias por el aporte!!! Llevaba días loco tratando de solucionar esto...

Francisco Rosales

22/01/2015 05:43:10

Tengo un div que muestra contenido input text (al dar click sale un calendario) traido vía AJAX:

<div id="contenido_traido_con_ajax">

<input type="text" class="claseX" value="calendario " />

</div>

Afuera de ese div, tengo otro input text con la misma clase:

<input type="text" class="claseX" value="calendario " />

En un javascript externo tengo las funciones que se activan al hacer

click en el input text con la class=claseX

El problema es, el input que no fue traido vía ajax funciona

perfectamente, en cambio el que sí fue traido con ajax no funciona.

Estuve googleando y al parecer es un problema muy común, e intenté

copiar una función que en teoría es como que "recarga" el javascript

para "que se de cuenta que hay html nuevo" según entendí, pero la

verdad no lo logro hacer andar.

¿Alguien tiene experiencia con un problema así?

Saludos!

Samo

07/01/2015 16:38:44

Gracias, me ha servido mucho, estoy en un nuevo empleo como programador y me salvo en una nueva tarea que realizo.

franco

04/12/2014 20:58:41

Genio! Muchas gracias! Una vez lo necesitaba y de vago no lo busque! Muy bien explicado! Gracias nuevamente!

Franklin Ruiz

03/09/2014 23:23:51

Me has aclarado una duda que tenía desde hace años, no sabes cuantas líneas de código me has ahorrado. Gracias sinceras!

Comentario anónimo
Comentar como usuario