Drupal Behaviors

Il arrive souvent d'écrire du JavaScript dans le cadre du développement des modules ou thèmes Drupal personnalisés, dans cet article nous allons voir les bonnes pratiques à adopter afin d'avoir un code JavaScript propre et bien interprété coté Drupal et coté navigateur.

Nous avons pris l'habitude de grouper le code jQuery dans la méthode ready() comme dans cet exemple :

$(document).ready(function () {
 // jQuery code here
});

L'utilisation de cette méthode nous garantie que le code ne va pas être exécuté qu'après le chargement complet du Document Object Model (DOM), en outre cela nous permet de placer notre code jQuery n'importe où dans la page. Drupal s'est inspiré de cette méthode pour fournir une solution plus efficace qui est bien les Drupal behaviors (comportements), le principe est le même qu'avec le document.ready sauf qu'ici il est géré par Drupal une fois que le DOM est chargé complètement.
N'importe quel site développé avec Drupal contient l'objet global Drupal qui comporte plusieurs objets, un parmi eux et qui nous intéresse dans cet article est bien l'objet Drupal.behaviours qui contient le code JavaScript qu'on souhaite exécuter une fois que le DOM sera chargé complétement.

Exemple d'un Behavior Drupal :

(function ($, Drupal) {
  Drupal.behaviors.CustomBehavior = {
    attach: function (context, settings) {
     // jQuery code here.
      });
    }
  };
})(jQuery, Drupal);

Le système de behaviors est très utile lorsqu'il s'agit d'une modification du DOM via des appels Ajax sans chargement de page, entre autre après l'ajout de nouveaux éléments dans le DOM, Drupal invoque Drupal.behaviors afin d'être attachés aux éléments ajoutés, de même ce systéme de Behaviors nous fournit un objet context qui contient la partie du DOM qui vient d'être ajoutée que ce soit via appel Ajax ou autres méthodes.

Considérons le code suivant :

(function ($, Drupal) {
  Drupal.behaviors.uniqueKey = {
    attach:function () {
      // Search the DOM for an element with class .behavior_example and logs it in the console.
      $(".behavior_example").once("unique-key").each(function () {
        console.log($(this));
      });
    }
  };
}(jQuery, Drupal));

Je tiens à préciser qu'il faudra ajouter "core/jquery.once" comme dépendance à la librairie du module afin de pouvoir l'utiliser.

La problématique dans cet exemple c'est qu'à chaque ajout d'un nouvel élément dans le DOM, ce dernier va être complétement analysé pour chercher l'élément avec la classe behavior_example ce qui entraînera une perte en performance.

C'est ici que context peut entrer en action pour mettre fin à cette problématique et donner un code plus efficient :

(function ($, Drupal) {
  Drupal.behaviors.uniqueKey = {
    attach:function (context) {
      // This example solves the problem by searching only in the context which contains only the part that is being added to the DOM.
      $(context).find(".behavior_example").once("unique-key").each(function () {
        console.log($(this));
      });
    }
  };
}(jQuery, Drupal));

Après le chargement de page, context contient le DOM tout entier et après des appels Ajax, context prend la partie du DOM qui vient d'être chargée et ajoutée.