Apprivoiser JavaScript dans Drupal (comprend les FAQ)
Publié: 2023-02-07Les expériences Web interactives offrent une expérience plus attrayante et agréable aux utilisateurs. Cela conduit à une satisfaction accrue des utilisateurs et à une perception positive d'un site Web. Par exemple, un formulaire qui fournit des commentaires et une validation instantanés, plutôt que de faire attendre l'utilisateur pour une actualisation de la page, peut améliorer considérablement l'expérience utilisateur.
JavaScript joue un rôle important dans Drupal en fournissant les moyens de créer des expériences dynamiques et interactives pour les utilisateurs sur le frontend d'un site Web Drupal. Il permet aux développeurs de modifier le comportement de certains éléments d'une page, tels que des formulaires, des liens ou tout autre élément DOM, sans avoir à actualiser la page entière. Les comportements Drupal sont des fonctions JavaScript qui sont exécutées lorsque des événements spécifiques se produisent sur une page. Les comportements facilitent la maintenance et la mise à niveau d'un site pour les développeurs, car ils n'ont pas besoin de modifier le code HTML sous-jacent. Découvrez tout ce que vous vouliez savoir sur les comportements Drupal dans l'article.
Que sont les comportements Drupal ?
Drupal.behaviors est un objet à l'intérieur de la structure Javascript de Drupal, qui nous permet d'attacher des fonctions à exécuter à certains moments de l'exécution de l'application. Il est appelé lorsque le DOM est entièrement chargé, mais ces comportements peuvent être appelés à nouveau. La documentation JavaScript officielle de Drupal suggère que les modules doivent implémenter JavaScript en attachant une logique à Drupal.behaviors .
Pourquoi avons-nous besoin des comportements Drupal ?
L'avantage des comportements est qu'ils sont automatiquement réappliqués à tout contenu chargé via AJAX. Ils peuvent être appelés à tout moment avec un contexte qui représente de nouveaux ajouts ou modifications au DOM. C'est mieux que $(document).ready() ou document DOMContentLoaded où le code n'est exécuté qu'une seule fois.
Quand les comportements Drupal sont-ils indésirables ?
Les comportements Drupal ne sont pas toujours la solution parfaite pour écrire du Javascript dans Drupal. Dans certains cas, comme indiqué ci-dessous, les comportements Drupal ne sont pas du tout nécessaires !
- Lorsque nous devons exécuter du code qui n'affecte pas le DOM. Par exemple. Initialiser un script externe comme Google Analytics
- Lorsqu'une opération JS doit être effectuée sur le DOM une seule fois, sachant que l'élément sera disponible lors du chargement de la page (ce scénario est différent de l'utilisation d'une fois).
Quand les comportements Drupal sont-ils appelés ?
- Une fois qu'une superposition d'administration a été chargée dans la page.
- Une fois que l'API de formulaire AJAX a soumis un formulaire.
- Lorsqu'une requête AJAX renvoie une commande qui modifie le code HTML, telle que ajax_command_replace() .
Autres moments où les comportements Drupal sont invoqués
- CTools l'appelle après le chargement d'un modal.
- Media l'appelle après le chargement du navigateur multimédia.
- Panels l'appelle une fois l'édition sur place terminée.
- Views l'appelle après avoir chargé une nouvelle page qui utilise AJAX.
- Views Load More l'appelle après avoir chargé le prochain bloc d'éléments.
- Le JavaScript des modules personnalisés peut appeler Drupal.attachBehaviors() lorsqu'ils ajoutent ou modifient des parties de la page.
Écrire du code sans comportements Drupal
Dans ce code, nous ajoutons un écouteur d'événement click à la classe .views-row qui calcule le nombre de fois que nous cliquons sur cette ligne. Mais il n'est ajouté qu'une seule fois aux éléments qui arrivent dans le DOM lors du chargement initial de la page. Après avoir cliqué sur Charger plus et chargé plus d'éléments, l'écouteur de clic ne fonctionne pas sur les éléments nouvellement chargés.
// No Drupal Behaviors (function () { let header = document.querySelector(".food-list-header"); if (header) { let greatFoodSpan = document.createElement("span"); greatFoodSpan.textContent = "Get ready for great food!!!!!!"; header.append(greatFoodSpan); } // Add the event listener for each click on the food let foods = document.querySelectorAll(".views-row"); foods.forEach((food) => { food.addEventListener("click", () => { let foodCounter = food.querySelector(".food-click-counter"); let timesClicked = parseInt(foodCounter.textContent.trim()); foodCounter.textContent = ++timesClicked; }); }); })();
Comment utilisons-nous les comportements Drupal ?
Réponse : Utilisation de la méthode d' attachement
Choses dont il faut se rappeler:
- Le nouvel objet doit avoir au moins une méthode d'attachement.
- Chaque fois que Drupal.attachBehaviors est appelé, il parcourt tous les objets de comportement et appelle leurs méthodes d'attachement respectives.
Ajout du comportement Drupal à notre code
Après avoir ajouté les comportements Drupal, le code ressemble à ceci.
(function (Drupal) { Drupal.behaviors.exampleBehaviour1 = { attach: (context, settings) => { // Add a delicious text to the top of the document let header = document.querySelector(".food-list-header"); // jQuery Equivalent // $(".food-list-header"); if (header) { let greatFoodSpan = document.createElement("span"); greatFoodSpan.textContent = "Get ready for great food!!!!!!"; header.append(greatFoodSpan); } // Add the event listener for each click on the food let foods = document.querySelectorAll(".views-row"); foods.forEach((food) => { food.addEventListener("click", () => { let foodCounter = food.querySelector(".food-click-counter"); let timesClicked = parseInt(foodCounter.textContent.trim()); foodCounter.textContent = ++timesClicked; }); }); }, }; })(Drupal);
Mais quelque chose d'étrange apparaît en haut lorsque nous cliquons sur Charger plus :
En effet, le comportement de Drupal est appelé de nombreuses fois et, par la suite, nous obtenons un comportement involontaire.
Qu'est-ce que le contexte dans "contexte Drupal" ?
- Lors de l'appel de la méthode attach pour tous les comportements, Drupal transmet un paramètre de contexte .
- Le paramètre de contexte passé peut souvent donner une meilleure idée de l'élément DOM en cours de traitement.
- Lors du chargement initial de la page, ce sera le document HTML complet ; lors des appels suivants, ce ne seront que les éléments ajoutés à la page ou modifiés.
Comment ajouter du contexte ?
Le problème précédent peut être résolu en utilisant le paramètre de contexte fourni par Drupal Behaviors. Dans ce cas, la première fois que la page se charge, nous obtenons l'intégralité du document HTML en tant que contexte et c'est à ce moment-là que nous attachons l'en-tête. Pour les opérations ultérieures, ce sera la partie du code qui est affectée par les comportements Drupal et donc cette partie du code est contrôlée en toute sécurité.
(function (Drupal) { Drupal.behaviors.exampleBehaviour2 = { attach: (context, settings) => { // Add a delicious text to the top of the document. // The context parameter now can be used for adding // certain functionality which removes unwanted repeatability let header = context.querySelector(".food-list-header"); // jQuery Equivalent // $(".food-list-header", context); if (header) { let greatFoodSpan = document.createElement("span"); greatFoodSpan.textContent = "Get ready for great food!!!!!!"; header.append(greatFoodSpan); } // Add the event listener for each click on the food let foods = context.querySelectorAll(".views-row"); foods.forEach((food) => { food.addEventListener("click", () => { let foodCounter = food.querySelector(".food-click-counter"); let timesClicked = parseInt(foodCounter.textContent.trim()); foodCounter.textContent = ++timesClicked; }); }); }, }; })(Drupal);
Encore une fois, il y a un comportement étrange lorsque nous cliquons sur Charger plus . Les aliments initialement chargés fonctionnent bien. Mais après avoir cliqué sur Charger plus, les nouveaux éléments obtiennent l'écouteur de clic et fonctionnent normalement. Mais les éléments initialement chargés rattachent l'écouteur et cliquer dessus appelle l'événement click plus d'une fois !
Quand les comportements Drupal commencent-ils à mal se comporter ?
- Écrire tous les écouteurs d'événements dans les comportements Drupal sans utiliser Once et Context.
- Déclarer des fonctions indésirables dans les comportements Drupal, ce qui conduit à la redéclaration des fonctions à chaque fois que la méthode attach est appelée.
"Une fois" à la rescousse
- Une fois garantit que quelque chose n'est traité qu'une seule fois en ajoutant un attribut data-once dans un élément DOM après l'exécution du code.
- Si le comportement est appelé à nouveau, l'élément avec l'attribut data-once est ignoré pour une exécution ultérieure.
- Once est une implémentation moderne de jQuery.once (qui est une tentative de s'éloigner de jQuery)
- Une fois, en combinaison avec le contexte, contrôle parfaitement l'ensemble de la fonctionnalité dont nous avons besoin.
Ajout d'une fois pour corriger les écouteurs d'événements dans notre code
(function (Drupal, once) { Drupal.behaviors.exampleBehaviour3 = { attach: (context, settings) => { once("food-header-initialized", ".food-list-header", context).forEach( (header) => { let greatFoodSpan = document.createElement("span"); greatFoodSpan.textContent = "Get ready for great food!!!!!!"; header.append(greatFoodSpan); } ); // jQuery Equivalent // $(".food-list-header", context).once("food-header-initialized", function (header) { // // }); // Add the event listener for each click on the food once("food-initialized", ".views-row", context).forEach((food) => { food.addEventListener("click", () => { let foodCounter = food.querySelector(".food-click-counter"); let timesClicked = parseInt(foodCounter.textContent.trim()); foodCounter.textContent = ++timesClicked; }); }); }, }; })(Drupal, once);
Maintenant, tout fonctionne comme prévu. Nous obtenons un attribut data-once pour les éléments auxquels les écouteurs d'événement sont attachés et les éléments nouvellement chargés et les éléments précédemment chargés fonctionnent correctement.
La méthode Need for Detach
La méthode Detach agit comme un anti-héros (pas maléfique), supprimant tout ce que nous avons fait dans la méthode attach. Tout code de la méthode detach sera appelé chaque fois que le contenu est supprimé du DOM. Cela nous aide à nettoyer notre application. Par exemple, la méthode Detach nous permet de supprimer les écouteurs d'événements indésirables qui consomment des ressources comme une situation d'interrogation continue.
Exemples de détachement
Supposons que nous ayons un formulaire ajax à remplir et que nous utilisions une minuterie pour afficher le temps écoulé. Nous utilisons setTimeOut pour gérer la minuterie. Nous enregistrons cette minuterie dans la console pour la surveillance.
(function (Drupal, once) { let counter = 0; Drupal.behaviors.exampleBehaviour4 = { attach: (context, settings) => { once("timer-initalized", ".contact-timer", context).forEach((ele) => { const timer = context.querySelector(".contact-timer-sec"); timer.textContent = counter; // Set the timer for user to see the time elapsed setInterval(() => { console.log("This is logging"); const timer = document.querySelector(".contact-timer-sec"); timer.textContent = ++counter; }, 1000); }); }, }; })(Drupal, once);
Lors de la soumission du formulaire, la minuterie sur DOM est supprimée mais la console commence à générer une erreur. En effet, l'élément sur lequel agit setTimeOut a été supprimé du DOM :
Pour éviter cela, nous pouvons utiliser la méthode detach comme ceci :
(function (Drupal, once) { let counter = 0; let intervalStopper; Drupal.behaviors.exampleBehaviour4 = { attach: (context, settings) => { // Set the timer for user to see the time elapsed once("timer-initialized", ".contact-timer", context).forEach((ele) => { const timer = context.querySelector(".contact-timer-sec"); timer.textContent = counter; intervalStopper = setInterval(() => { const timer = document.querySelector(".contact-timer-sec"); timer.textContent = ++counter; console.log("This is logging"); }, 1000); }); }, // Clear the timer on confirmation detach: (context, settings, trigger) => { const timer = context.querySelector(".contact-timer-sec"); if (trigger == "unload" && timer) { clearInterval(intervalStopper); } }, }; })(Drupal, once);
Cela supprime la minuterie lors du déchargement et, comme le montre l'enregistreur, l'erreur ne se produit pas.
Expressions de fonction immédiatement invoquées (IIFE) - Le wrapper pour JS
Nous avons utilisé IIFE pour écrire notre code Drupal. Les parenthèses ouvrantes initiales définissent une fonction anonyme qui aide à empêcher la portée de la fonction de polluer la portée globale de l'ensemble de l'application. Vous pouvez passer des arguments à votre fonction anonyme en les incluant comme arguments à la fin de la définition de la fonction.
Cela nous aide également à espacer les paramètres de la manière dont nous voulons qu'ils soient utilisés.
Exemple:
// Function name crisis!!!! // The function is vulnearble to // be replaced by some other function function someFunction() { // Some code for this function } (function (Drupal) { // Function name crisis averted! function someFunction() { // Some code for this other function } Drupal.behaviors.exampleBehaviour6 = { attach: (context, settings) => { someFunction(); }, }; })(Drupal);
Dernières pensées
La mise en œuvre des comportements Drupal permet une interactivité dynamique, une interaction utilisateur simplifiée, une rétroaction améliorée des utilisateurs, un développement efficace et une expérience utilisateur globale améliorée de votre site Web. Les comportements Drupal sont flexibles et modulaires, en ce sens qu'ils peuvent être exécutés plusieurs fois sur une page, peuvent remplacer et étendre le comportement existant, et peuvent être automatiquement réappliqués à tout contenu chargé via Ajax.
Vous recherchez une agence de développement Drupal pour vous aider à créer des expériences Web interactives, en tirant le meilleur parti de Drupal ? Nous serions ravis de parler !