Control de eventos con jQuery para elementos HTML generados dinámicamente

Cuando el contenido de la página es estático es muy sencillo capturar los eventos con jQuery, ya sea por su id, por clase o de cualquier otra forma que podamos identificar los elementos para los que se quieren añadir eventos pero cuando se crea un nuevo elemento dinámicamente llega el «problema» porque los handlers (controladores, manejadores o como los quieras llamar) de jQuery solo capturan los eventos de los elementos que se crearon antes de que se crease el handler y por este motivo se suelen declarar en el $(document).ready() justo después de que este cargado todo el contenido de la página.


//  Handlers para elementos creados antes de la declaracion
$('.botonA').click(function(){
    alert("Hola");
});

$('.botonB').on('click', function(){
    alert("Hola");
});

Desasociar y volver a asociar los eventos

La primera idea para solucionarlo puede ser crear un nuevo handler cada vez que se crea el nuevo elemento pero la vamos a descartar porque estar creando y eliminando handlers es ineficiente y no podemos olvidar que antes de crear el nuevo handler hay que borrar el anterior para que el evento solo se ejecute una vez, con lo que no es una si no 2 las acciones innecesarias que estamos realizando.


/**
 * Elimina y vuelve a anadir el handler para el evento click
 */

function controlarClick() {}
    $('.botonB').off('click');
    $('.botonB').on('click', function(){
        alert("Hola");
    });
}

/**
 * Crea un nuevo boton y le anade su handler
 *
 * @param nombre Nombre del boton
 */

function anadirBoton(nombre) {
    $('#contenedor').add('
' + nombre + '
'); controlarClick(); }

Delegar el control de los eventos

La solución es declarar el handler sobre un elemento que sepamos que va a estar siempre presente, por ejemplo podría ser el contenedor donde añadimos los botones para el ejemplo anterior y si no siempre nos podemos ir a los casos más generales como declararlo sobre el body o en document e indicar al handler la clase sobre la que se aplica el evento añadiendo un parámetro adicional después del tipo de evento.


$('#contenedor').on('click', '.botonA', function(){
    alert("Hola");
});

$(document).on('click', '.botonB', function(){
    alert("Hola");
});

Y con este tipo de handler podemos estar seguros de que se ejecuten siempre tanto para los elementos creados antes como después del propio handler.

Finalmente un ejemplo un poco tonto para verlo en funcionamiento con 2 clases de botones que generan un nuevo botón de la otra clase y escriben el nombre del botón en un contenedor precedido de – para los eventos controlados por los handlers que solo aplican a los elementos creados inicialmente y con + para los que se han creado con el handler que funciona para los eventos creados dinámicamente y obviamente también para los creados inicialmente.

See the Pen Eventos sobre elementos creados dinámicamente con jQuery by Ivan Salas (@isc7) on CodePen.