drupal-header

Drupal: Porque usar Drupal.behaviors en lugar de $(document).ready();

Durante mucho tiempo estuve usando $(document).ready(); para poner mi js en Drupal, y funcionaba la mar de bien. Esto me permitía ejecutar javascript inmediatamente después que el DOM estuviera cargado evitando así errores de referencias a objetos que todavía no existieran al querer manipularlos.

Ahora bien, hay un problema que vamos a encontrar por medio de un ejemplo simple:

Si tuviéramos un listado de nodos y a ese listado hiciéramos que al pinchar sobre sus enlaces hiciera un alert de su atributo “title” usando jQuery:

¿Qué pasa si por medio de AJAX se agregaran nuevos nodos? te lo digo, que no reaccionarían al hacer click sobre ellos, y es por que el método .click() de jQuery se ejecuta una sola vez en busca de elementos que macheen con su criterio y una vez finalizado ya está, no hace mas. Es un comportamiento de lo mas entendible ya que imaginemos que estuviera escaneando constantemente por nuevos elementos ese selector mas los otros 50 que estemos usando para hacer mas cosas…. Google Chrome lo soportaría sin apenas darle carga al procesador y RAM, pero piensen en la basura de IE…..

Perdonen que me vaya por las ramas, como les decía, dado el problema que se planteo para el listado de nodos que di como ejemplo, se implemento una solucion (bueno cubre mas problemas pero este es de los mas comunes) la solución fue usar al objeto Drupal.behaviors a modo de controlador. Drupal.behaviors relanza todas las funciones que almacena por cada vez que se lance una petición AJAX, dándonos la oportunidad de re procesar cosas. Así pues en el ejemplo anterior lo podemos poner dentro de un behavior para poder aplicar nuestra funcionalidad incluso a los nuevos elementos provenientes de la petición:

Como ven lo único que hay que reemplazar en nuestros actuales ficheros de javascript es jQuery(document).ready(function($) {}) por Drupal.behaviors.alertarEnlaces = function(context) {} y no se preocupen por el hecho de que su código este ahora asignado dentro de una función(“Drupal.behaviors.alertarEnlace() “), porque esta se ejecuta solita, y veanlo incluso como una ventaja, pueden invocarla ustedes mismos cuando quieran ademas.

11 Comments

  • Uriberde 08/03/2011

    Tengo una pregunta para usted…¿conoces alguna solución para esto pero que sea necesario usar drupal? Ya sabes, algunos usamos otro tipo de tecnologías 😉

  • Johnny Gamba 08/03/2011

    Buen tip, ese problema me pasaba al utilizar los popups en Drupal ya que estos se cargaban por ajax, recuerda tambien que la funcion live() de jquery hace lo mismo para este caso en particular que behaviousrs, saludos.

  • Brian 07/06/2012

    Estoy intentando implementar unos ficheros Jquery a mi drupal, pero la funcion principal no se ejecuta. Concretamente implementar esto:

    http://tympanus.net/Tutorials/BeautifulBackgroundImageNavigation/

    Espero que me puedas ayudar.

    Muchas gracias.

  • kanzer 07/11/2012

    Muy buen post precisamente ando haciendo con views un listado de canciones se filtran categorias y estilos de musica gracias a un bloque con los filtros expuestos que recargan el listado de canciones en ajax,
    A cada row le puse por ejemplo el link del archivo mp3 le puse una clase .add-music que con javascript recoge los atirbutos href y los carga a la playlist de jplayer

    pero despues de cada ajax ya no me reconoce las clases tal y como dices solo chrome lo reconoce

    me sucede el problema que dices ademas de que estoy intengrando todo desde un block mira checa lo que tengo en mi block:

    se que es una manera sucia de hacerlo pero tengo problemas en integrarlo en mi template.php, me podrias hechar una mano gracias por tu post

    • Capy 09/11/2012

      Es drupal 7 o 6?

      • kanzer 14/01/2013

        Hola Capy es drupal 7 ya logre avanzar mas mira te explico

        primeramente abrí mi archivo sub_theme.info
        y agregue lo siguiente:


        scripts[] = js/audioteca.js
        scripts[] = js/jquery.jplayer.min.js
        scripts[] = js/jplayer.playlist.min.js

        a jquery.min.js no lo agregue por que ya viene por con drupal 7

        bueno hasta aquí todo bien dentro de audioteca.js tengo lo siguiente:


        (function ($) {
        Drupal.behaviors.MyfunctionTheme = {
        attach: function(context, settings) {
        $(document).ready(function(){

        var myPlaylist = new jPlayerPlaylist({
        jPlayer: "#jquery_jplayer_N",
        cssSelectorAncestor: "#jp_container_N"
        }, [
        {
        title:"El pescador",
        artist:"40",
        mp3:"http://red.comppa.com/sites/default/files/audios/EL%20Pescador.mp3",
        }
        ], {
        playlistOptions: {
        enableRemoveControls: true
        },
        swfPath: "../js",
        supplied: "oga, mp3"
        });

        // Click handlers for jPlayerPlaylist method demo

        // Audio mix playlist
        $('.add-music').click(
        function() {
        myPlaylist.add({
        title: $(this).attr('data-title'),

        artist: $(this).attr('data-artist'),
        mp3: $(this).attr('href')
        });
        return false; // Not required when href omitted.
        });

        // The remove commands

        $("#playlist-remove").click(function() {
        myPlaylist.remove();
        });

        $("#playlist-remove--2").click(function() {
        myPlaylist.remove(-2);
        });
        $("#playlist-remove--1").click(function() {
        myPlaylist.remove(-1);
        });
        $("#playlist-remove-0").click(function() {
        myPlaylist.remove(0);
        });
        $("#playlist-remove-1").click(function() {
        myPlaylist.remove(1);
        });
        $("#playlist-remove-2").click(function() {
        myPlaylist.remove(2);
        });

        // The shuffle commands

        $("#playlist-shuffle").click(function() {
        myPlaylist.shuffle();
        });

        $("#playlist-shuffle-false").click(function() {
        myPlaylist.shuffle(false);
        });
        $("#playlist-shuffle-true").click(function() {
        myPlaylist.shuffle(true);
        });

        // The select commands

        $("#playlist-select--2").click(function() {
        myPlaylist.select(-2);
        });
        $("#playlist-select--1").click(function() {
        myPlaylist.select(-1);
        });
        $("#playlist-select-0").click(function() {
        myPlaylist.select(0);
        });
        $("#playlist-select-1").click(function() {
        myPlaylist.select(1);
        });
        $("#playlist-select-2").click(function() {
        myPlaylist.select(2);
        });

        // The next/previous commands

        $("#playlist-next").click(function() {
        myPlaylist.next();
        });
        $("#playlist-previous").click(function() {
        myPlaylist.previous();
        });

        // The play commands

        $("#playlist-play").click(function() {
        myPlaylist.play();
        });

        $("#playlist-play--2").click(function() {
        myPlaylist.play(-2);
        });
        $("#playlist-play--1").click(function() {
        myPlaylist.play(-1);
        });
        $("#playlist-play-0").click(function() {
        myPlaylist.play(0);
        });
        $("#playlist-play-1").click(function() {
        myPlaylist.play(1);
        });
        $("#playlist-play-2").click(function() {
        myPlaylist.play(2);
        });

        // The pause command

        $("#playlist-pause").click(function() {
        myPlaylist.pause();
        });

        // Changing the playlist options

        // Option: autoPlay

        $("#playlist-option-autoPlay-true").click(function() {
        myPlaylist.option("autoPlay", true);
        });
        $("#playlist-option-autoPlay-false").click(function() {
        myPlaylist.option("autoPlay", false);
        });

        // Option: enableRemoveControls

        $("#playlist-option-enableRemoveControls-true").click(function() {
        myPlaylist.option("enableRemoveControls", true);
        });
        $("#playlist-option-enableRemoveControls-false").click(function() {
        myPlaylist.option("enableRemoveControls", false);
        });

        // Option: displayTime

        $("#playlist-option-displayTime-0").click(function() {
        myPlaylist.option("displayTime", 0);
        });
        $("#playlist-option-displayTime-fast").click(function() {
        myPlaylist.option("displayTime", "fast");
        });
        $("#playlist-option-displayTime-slow").click(function() {
        myPlaylist.option("displayTime", "slow");
        });
        $("#playlist-option-displayTime-2000").click(function() {
        myPlaylist.option("displayTime", 2000);
        });

        // Option: addTime

        $("#playlist-option-addTime-0").click(function() {
        myPlaylist.option("addTime", 0);
        });
        $("#playlist-option-addTime-fast").click(function() {
        myPlaylist.option("addTime", "fast");
        });
        $("#playlist-option-addTime-slow").click(function() {
        myPlaylist.option("addTime", "slow");
        });
        $("#playlist-option-addTime-2000").click(function() {
        myPlaylist.option("addTime", 2000);
        });

        // Option: removeTime

        $("#playlist-option-removeTime-0").click(function() {
        myPlaylist.option("removeTime", 0);
        });
        $("#playlist-option-removeTime-fast").click(function() {
        myPlaylist.option("removeTime", "fast");
        });
        $("#playlist-option-removeTime-slow").click(function() {
        myPlaylist.option("removeTime", "slow");
        });
        $("#playlist-option-removeTime-2000").click(function() {
        myPlaylist.option("removeTime", 2000);
        });

        // Option: shuffleTime

        $("#playlist-option-shuffleTime-0").click(function() {
        myPlaylist.option("shuffleTime", 0);
        });
        $("#playlist-option-shuffleTime-fast").click(function() {
        myPlaylist.option("shuffleTime", "fast");
        });
        $("#playlist-option-shuffleTime-slow").click(function() {
        myPlaylist.option("shuffleTime", "slow");
        });
        $("#playlist-option-shuffleTime-2000").click(function() {
        myPlaylist.option("shuffleTime", 2000);
        });

        // AVOID COMMANDS

        $("#playlist-avoid-1").click(function() {
        myPlaylist.remove(2); // Removes the 3rd item
        myPlaylist.remove(3); // Ignored unless removeTime=0: Where it removes the 4th item, which was originally the 5th item.
        });

        $("#jplayer_inspector_1").jPlayerInspector({jPlayer:$("#jquery_jplayer_N")});
        });

        }}
        })( jQuery );

        pero me sigue dando errores con firefox sorprendentemente en ie9 y chrome funca bien te dejo el link por si quieres echar un vistazo
        http://red.comppa.com/audioteca

        gracias por responder hombre

  • PHPepe 06/12/2012

    Excelente explicacion !

    Yo tambien vengo usando $(function) por todos lados, y siempre me pregunte para que carajo eran esas cosas de los bahavoirs, pense que era mas burocracia no mas.

    Ese problema del binding en elementos creados al vuelo esta siempre. Por lo general lo que hago en aplicaciones muy ajaxeras, es encapsular los bindings en algo como function bindElements(), y la llamo onDocumentReady y luego de crear elementos js.

    Lo voy a probar,, pero me quedan dudas: como se da cuenta drupal de que se creo un nodo en el browser, y automaticamente hacerle un binding ?

  • angel 19/02/2014

    NO crees que el metodo Jquery on() o delegate() hacen mejor la chamba de Drupal.behaviors?

    • Capy 19/02/2014

      jQuery.on() no está disponible para la versión 1.4.4 (la que viene con Drupal), y delegate no serviría porque Drupal no emite eventos, lo que hace es localizar todos los Drupal.behaviors.X() y los ejecuta uno a uno.

      Estoy de acuerdo con vos en una cosa, esa forma de operar no es la mas elegante, pero hasta que no salga Drupal 8 nos vamos a tener que conformar 😀

      Saludos!

      • angel 19/02/2014

        Pero bueno puedes sobrescribir la versión de jQquery ya sea con el modulo Jquery-update o manualmente. La verdad empece a usar jQuery on() desde hace tiempo porque no había descubierto Drupal.behaviors y ahora me pregunto si estoy haciendo las cosas mal.. :S

        • Capy 19/02/2014

          Jquery_update es una buena opción, pero hay veces que estas condenado a no poder actualizar la versión de jquery porque algún modulo no es compatible con versiones superiores de este ¬¬

:).