sábado, 27 de febrero de 2010

Event Delegation en Javascript

Hace unos días haciendo una página que básicamente es un listado con 3 radio buttons por fila (si, porras, aunque en tu charla del madrid-rb del jueves dijeras que no sabes para que se usan, a veces son útiles), quería que se enviara el formulario al seleccionar uno de los radio-buttons sin tener que pulsar en submit.

Para hacerlo un poco limpio, lo hice con javascript no intrusivo y prototype de la siguiente forma, donde cada uno de los input tiene definida la clase radio_submit

document.observe("dom:loaded", function() {
    $$('input.radio_submit').each(function(item) {
        item.observe('click', function() {
            item.parentNode.submit();
        });
    });
});

Pero no me gustaba esa solución donde tengo 3 function anidados, así que le pedí consejo a Paco a ver si se le ocurría una mejor solución.

Y evidentemente había una solución mejor, basada en Event Delegation

document.observe("dom:loaded", function() {
  $('user_source_list').observe('click', function(event){
    var element = event.target;
    if (element.match('input.radio_submit')){
      element.up('form').submit();
    }
  });
});


La idea es que en lugar de crear un evento en cada uno de los elementos, se crea sólo un evento en un objeto que los contiene a todos (en este caso es un div con el id 'user_source_list'), y capturamos el click sobre ese objeto.

Otra mejora que me propuso es que en lugar de usar parentNode para ir al elemento padre usara up('form'), de esa forma, si cambia el diseño de la página y se introduce algún elemento intermedio en el dom de la página, el código seguirá funcionando.

Paco tambien me pasó este enlace donde se ve como en Rails 3 se utilizará la misma técnica de javascript no intrusivo con delegación de eventos.