Método jQuery .live () vs .on () para agregar un evento click después de cargar html dinámico

216

Estoy usando jQuery v.1.7.1 donde el método .live () aparentemente está en desuso.

El problema que tengo es que al cargar dinámicamente html en un elemento usando:

$('#parent').load("http://..."); 

Si intento agregar un evento de clic luego, no registra el evento usando ninguno de estos métodos:

$('#parent').click(function() ...); 

o

// according to documentation this should be used instead of .live()
$('#child').on('click', function() ...); 

¿Cuál es la forma correcta de lograr esta funcionalidad? Solo parece funcionar con .live () para mí, pero no debería estar usando ese método. Tenga en cuenta que #child es un elemento cargado dinámicamente.

Gracias.

Sean Thoman
fuente
25
¿Por qué dices "supuestamente en desuso" ? ¿No crees en los documentos?
66
Supuestamente no está en desuso: está en desuso. Si miras el jQuery doco.live() , te dice cómo reescribir los usos existentes de .live()usar .delegate()o .on()(dependiendo de si estás en la versión 1.7+ o no). Sin embargo, tenga en cuenta que si agrega un controlador con .click()"después" como menciona, es decir, después de cargar elementos dinámicamente, debería funcionar: el único problema es tratar de asignar .click() antes de cargar elementos dinámicamente.
nnnnnn
Cambié la redacción a 'aparentemente' ya que eso es básicamente lo que quise decir. De todos modos, ahora entiendo que, obviamente, dado que el evento .load () es asíncrono, entonces el elemento #child solo podría reconocerse de manera confiable en el controlador de éxito, lo que tiene sentido.
Sean Thoman
¿Posible duplicado de enlace
showdev

Respuestas:

606

Si desea que el controlador de clics funcione para un elemento que se carga dinámicamente, configure el controlador de eventos en un objeto primario (que no se carga dinámicamente) y le da un selector que coincida con su objeto dinámico de esta manera:

$('#parent').on("click", "#child", function() {});

El controlador de eventos se adjuntará al #parentobjeto y cada vez que se genere un evento de clic que se originó en #childél, activará su controlador de clic. Esto se denomina manejo de eventos delegados (el manejo de eventos se delega a un objeto primario).

Se hace de esta manera porque puede adjuntar el evento al #parentobjeto incluso cuando el #childobjeto aún no existe, pero cuando luego exista y se haga clic en él, el evento de clic burbujeará hasta el #parentobjeto, verá que se originó #childy Hay un controlador de eventos para hacer clic #childy activar su evento.

jfriend00
fuente
23
¡Gran explicación! Nunca antes he sido capaz de envolver mi cabeza alrededor live()vs. on()pero esta noche decidí una vez más a tratar, y su explicación de inmediato reveló lo que había estado perdiendo todo el tiempo. ¡Gracias!
MikeSchinkel
66
Un millón de ups . Comencé a usar knockout antes de darme cuenta de que esto era posible en jQuery para niños creados dinámicamente, muchas gracias.
Brock Hensley
99
Debería considerar escribir un libro o algo así: su pequeño texto me ha sido más útil que la página completa en los documentos de jQuery sobre « on () ». ¡Muchas gracias!
Colesterol
@ jfriend00, ¿sabe cómo podemos aplicar este mismo proceso a una situación activa y no activa? ¿Hay alguna fuente que hable de esto?
klewis
@blackhawk: mira esta respuesta . Usted puede inscribirse para las mouseentery los mouseleaveeventos y prueba dentro del manejador de los cuales uno fue provocado. El pseudo evento "hover" de jQuery no está disponible con delegación.
jfriend00
33

Prueba esto:

$('#parent').on('click', '#child', function() {
    // Code
});

De la $.on()documentación:

Los controladores de eventos están vinculados solo a los elementos seleccionados actualmente; deben existir en la página en el momento en que su código realiza la llamada .on().

Su #childelemento no existe cuando lo llama $.on(), por lo que el evento no está vinculado (a diferencia $.live()). #parentSin embargo, existen, por lo que la unión del evento a que está muy bien.

El segundo argumento en mi código anterior actúa como un 'filtro' para disparar solo si el evento burbujeó #parentdesde #child.

Bojangles
fuente
Si llamo al método $ .on () después del método $ .load (), ¿por qué no existiría el elemento #child en ese punto?
Sean Thoman
66
@SeanThoman: tendría que llamarlo desde el controlador de éxito del .load()método, no desde el código después del .load()método. #childsolo se sabe que se carga cuando el controlador de éxito se ejecuta realmente y no antes.
jfriend00
e incluso entonces, el tiempo que lleva insertar los datos que obtuvo en el DOM significa que es posible que no se conecte. Últimamente he estado trabajando mucho en aplicaciones de una sola página y mi estándar es var $ body = $ ('body'); $ body.on ("evento", ".elemento / # clase", función (e) {}); para todo. 1 selector. No se preocupe por lo que está o no cargado.
lupos
21

$(document).on('click', '.selector', function() { /* do stuff */ });

EDITAR: Estoy proporcionando un poco más de información sobre cómo funciona esto, porque ... palabras. Con este ejemplo, está colocando un oyente en todo el documento.

Cuando clickcoincide con cualquier elemento (s) .selector, el evento aparece en el documento principal, siempre que no haya otros oyentes que llamenevent.stopPropagation() método, lo que aumentaría el burbujeo de un evento a los elementos principales.

En lugar de vincularse a un elemento específico o conjunto de elementos, está escuchando cualquier evento que provenga de elementos que coincidan con el selector especificado. Esto significa que puede crear un oyente, una vez, que coincida automáticamente con los elementos existentes actualmente, así como con cualquier elemento agregado dinámicamente.

Esto es inteligente por varias razones, incluido el rendimiento y la utilización de la memoria (en aplicaciones a gran escala)

EDITAR:

Obviamente, el elemento padre más cercano en el que puede escuchar es mejor, y puede usar cualquier elemento en lugar de documentsiempre que los niños para los que desea monitorear eventos estén dentro de ese elemento padre ... pero eso realmente no tiene nada que ver con la pregunta

L422Y
fuente
23
Intentó $(element).on(...). Esto es $(document).on(...,element,...). Diferentes bestias
cHao
@ArnoldRoa sí, mejor rendimiento. no tendrá un oyente en varios hijos, no tiene que volver a aplicar el oyente cada vez que se modifica el DOM y los eventos se propagan a través del DOM de forma predeterminada. Ejecutar una vez y cada niño que coincida con el selector activará la función dada al hacer clic.
L422Y
El comentario de @ L422Y aquí es muy engañoso. Si tiene curiosidad sobre las implicaciones de rendimiento, eche un vistazo al comentario de @ jfriend00 sobre la respuesta de @ Jared
Gust van de Wal
@GustvandeWal ¿Cómo es engañoso? Si va y emite cien $ (esto) .on (...) frente a escuchar un evento una vez en un elemento padre, es sustancialmente más eficiente.
L422Y
Solo estás hablando de adjuntar los eventos. Los cuellos de botella de rendimiento en el mundo real son demasiados oyentes que se disparan (como los que delega), no grandes cantidades de elementos que necesitan un evento adjunto.
Gust van de Wal
12

El equivalente de .live () en 1.7 se ve así:

$(document).on('click', '#child', function() ...); 

Básicamente, mire el documento para ver los eventos de clic y filtrelos para #child.

Jared
fuente
Porque así es como el controlador de eventos se adjunta al documento (como lo .live()hace).
cHao
17
Una razón que .live()está en desuso ahora es porque es malo poner todos los controladores de eventos en vivo en el objeto del documento. Las cosas pueden realmente, realmente desacelerarse. No solo los eventos tienen que burbujear hasta el documento, sino que también puede tener muchos controladores de eventos para revisar en el objeto del documento. La principal ventaja de esto .on()es que puede adjuntarlo a un objeto principal que esté mucho más cerca del objeto real y mejorar drásticamente el rendimiento. Entonces ... NO recomendaría usar .on()con el objeto de documento. Mucho mejor elegir un objeto padre más cercano.
jfriend00
Gracias por la aclaración. Por lo que vale, el rendimiento de los eventos se ha mejorado mucho con on (), por lo que debería ser un problema menor de lo que solía ser. Si se adjunta a un padre, supongo que tendría que ser un padre que existe en el documento listo o vería problemas similares.
Jared
En el peor, esto no emular el obsoleto .live()enfoque; Sin embargo, la capacidad de controlar la delegación es ciertamente ventajosa.
Dan Lugg
9

Sé que es un poco tarde para una respuesta, pero he creado un polyfill para el método .live (). Lo he probado en jQuery 1.11, y parece funcionar bastante bien. Sé que se supone que debemos implementar el método .on () siempre que sea posible, pero en grandes proyectos, donde no es posible convertir todas las llamadas .live () a las llamadas equivalentes .on () por cualquier razón, lo siguiente podría trabajo:

if(jQuery && !jQuery.fn.live) {
    jQuery.fn.live = function(evt, func) {
        $('body').on(evt, this.selector, func);
    }
}

Simplemente inclúyalo después de cargar jQuery y antes de llamar a live ().

NS V
fuente
5

.on () es para jQuery versión 1.7 y superior. Si tiene una versión anterior, use esto:

$("#SomeId").live("click",function(){
    //do stuff;
});
Matt Cashatt
fuente
8
OP dice "Estoy usando jQuery v.1.7.1"
Selvakumar Arumugam
1
@ jfriend: ¿por qué no publicar su propia respuesta en lugar de rechazar la mía? Uso live () todos los días con todas las versiones anteriores a la 1.6 y funciona bien. Puedo ver que eres bueno leyendo la documentación, pero a veces es más útil poner algo en práctica para una persona. .live () funciona. Período.
Matt Cashatt
55
@MatthewPatrickCashatt: publiqué mi propia respuesta y no desestimé la tuya, no hagas suposiciones tan ciegas. Pre 1.7, .delegate()funciona mucho mejor .live()que por lo que jQuery doc lo recomienda y lo desprecia .live(). Sí, .live()todavía funciona, pero las respuestas aquí en SO deberían recomendar la mejor manera de hacer las cosas. Lo he visto 20 veces aquí en SO. Si publica el código .live()aquí en SO, será rechazado (por lo general no por mí, a menos que haya algo más mal).
jfriend00
1
No voté negativamente, pero aunque .live()definitivamente funciona incluso en la versión 1.7, aún debería usarlo .delegate()o .on()porque .live()fue desaprobado por una buena razón. Siempre y cuando note el cambio en la sintaxis para las dos funciones más nuevas, ambas funcionarán bien.
nnnnnn
1
@ jfriend00- Tienes toda la razón. Día largo. Mis disculpas.
Matt Cashatt
3

Usé 'live' en mi proyecto, pero uno de mis amigos sugirió que debería usar 'on' en lugar de live. Y cuando intenté usar eso, experimenté un problema como el que tú tenías.

En mis páginas creo filas de tablas de botones y muchas cosas de dom de forma dinámica. pero cuando uso en la magia desapareció.

Las otras soluciones como usarlo como un niño solo llaman a sus funciones cada vez que hace clic. Pero encuentro una manera de hacer que vuelva a suceder y aquí está la solución.

Escribe tu código como:

function caller(){
    $('.ObjectYouWntToCall').on("click", function() {...magic...});
}

Llamar a la persona que llama (); después de crear su objeto en la página de esta manera.

$('<dom class="ObjectYouWntToCall">bla... bla...<dom>').appendTo("#whereeveryouwant");
caller();

De esta forma, se llama a su función cuando se supone que no debe hacer cada clic en la página.

Coderx07
fuente