Ajax, eventos y jQuery
Un «problema» con el que todo novato de la programación con jQuery se encuentra tarde o temprano (y las listas de correo lo demuestran) es que el contenido cargado (o generado) dinámicamente no dispara los manejadores de eventos asignados en $(document).ready.
Y, hoygan, esto es de lo más normal.
Si repasamos nuestra forma habitual de trabajar con jQuery, y reflexionamos un poquito…
$(document).ready(function() {
$('selecciono.algo')
.bind('click', hazCosasBonitas);
});
… recordaremos que estamos utilizando $(document).ready porque no podemos seleccionar elementos que no existen. De ahí que tengamos que esperar a disponer de un árbol DOM completo. De ahí que los manejadores de eventos no afecten a elementos nuevos.
¿Entonces?
Opciones las hay adecuadas a unos casos y a otros. La más sencilla, para casos sencillos, es inicializar los contenidos nuevos una vez los hayamos insertado en el documento.
Necesitamos, pues, una función que nos permita seleccionar y actuar dentro de un contexto. Recuerda que jQuery provee de selecciones basadas en contexto. Si utilizas
$('a');
seleccionarás todos los enlaces del documento. Pero si usas
$('a', unElementoSelecto);
seleccionarás los enlaces descendientes de unElementoSelecto.
Por tanto, podemos crear nuestra función de inicialización según contexto como sigue.
function initLinks(context) {
$('a', context)
.bind('click', hazCosasBonitas)
}
Que ejecutaremos desde nuestro manejador para $(document).ready, pasando el documento como contexto de búsqueda:
$(document).ready(function() {
initLinks(document);
});
Así que estamos como al principio… pero mucho más cerca del final. Lo único que nos queda por hacer es ejecutar initLinks cuando recuperemos nuevo contenido. Si usamos load, el más simplón de los métodos Ajax de jQuery, basta con usar una función de callback:
function loadNewContent() {
$('#holder').load('ajax-content.html #response p', function() {
// `this` apunta al elemento que acabamos de rellenar
initLinks(this);
});
}
Y esta es la idea básica, que he reflejado en esta pequeña demo en latín.
Por supuesto, hay otras opciones. Si eres de los que para clavar un clavo usa un plugin, échale un vistazo a LiveQuery; si tienes un serio trasiego de elementos vivos, mejor apostar por la delegación de eventos. Pero esas son otras historias que contaré a su debido momento.