Scriptia. Javascript y buenas prácticas en español



Scriptia / artículos / Ajax, eventos y jQuery

Ajax, eventos y jQuery

Saltar a Anotaciones relacionadas

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.



3 comentarios RSS

1 Carlos (2008-10-03 @ 9:33 am):

Hola, que tal:

me ha parecido bastante interesante el artículo, porque precisamente me acabo de encontrar con este problema. No tengo ninguna duda de su utilización cuando voy a recargar los comportamientos creados por mí. Pero… ¿qué pasa con el resto de plugins que estoy cargando en el head, como forms? Cada uno tiene su $(document).ready(). ¿Tengo que modificar los scrips de todos los plugin que cargue?

Un saludo y gracias:

Carlos.

2 choan (2008-10-11 @ 5:49 pm):

Hola Carlos.

Si el plugin actúa por su cuenta, no está actuando bien. Aún en caso de que lo haga, revisa su código. Seguramente ofrecerá alguna manera de replicar la inicialización.

3 Angel Rodriguez (2008-10-19 @ 9:25 pm):

Excelente amigo… me acabas de quitar un dolor de cabeza que tenia desde hace tiempo con esto y ajax !!!

Gracias !!


Acerca de Scriptia

Saltar a la caja de búsqueda

Scriptia forma parte del PDM de Choan C. Gálvez, desarrollador web residente en Barcelona. Scriptia pretende mejorar la calidad de la documentación acerca de javascript disponible en español.