JavaScript in Drupal zähmen (inklusive FAQs)

Veröffentlicht: 2023-02-07

Interaktive Weberlebnisse bieten Benutzern ein ansprechenderes und angenehmeres Erlebnis. Dies führt zu einer erhöhten Benutzerzufriedenheit und einer positiven Wahrnehmung einer Website. Beispielsweise kann ein Formular, das sofortiges Feedback und Validierung bietet, anstatt den Benutzer auf eine Seitenaktualisierung warten zu lassen, die Benutzererfahrung erheblich verbessern.

JavaScript spielt eine wichtige Rolle in Drupal, indem es die Mittel bereitstellt, um dynamische und interaktive Erfahrungen für Benutzer auf dem Frontend einer Drupal-Website zu erstellen. Es ermöglicht Entwicklern, das Verhalten bestimmter Elemente auf einer Seite wie Formulare, Links oder andere DOM-Elemente zu ändern, ohne die gesamte Seite aktualisieren zu müssen. Drupal Behaviors sind JavaScript-Funktionen, die ausgeführt werden, wenn bestimmte Ereignisse auf einer Seite auftreten. Verhaltensweisen erleichtern Entwicklern die Wartung und Aktualisierung einer Website, da sie keinen zugrunde liegenden HTML-Code ändern müssen. Erfahren Sie im Artikel alles, was Sie über Drupal Behaviors wissen wollten.

JavaScript in Drupal zähmen

Was sind Drupal-Verhaltensweisen?

Drupal.behaviors ist ein Objekt innerhalb der Javascript-Struktur in Drupal, mit dem wir Funktionen anhängen können, die zu bestimmten Zeiten während der Ausführung der Anwendung ausgeführt werden sollen. Es wird aufgerufen, wenn das DOM vollständig geladen ist, aber diese Verhaltensweisen können erneut aufgerufen werden. Die offizielle JavaScript-Dokumentation von Drupal schlägt vor, dass Module JavaScript implementieren sollten, indem sie Logik an Drupal.behaviors anhängen .

Warum brauchen wir Drupal-Verhalten?

Der Vorteil von Verhaltensweisen besteht darin, dass sie automatisch auf alle Inhalte angewendet werden, die über AJAX geladen werden. Sie können jederzeit mit einem Kontext aufgerufen werden, der neue Ergänzungen oder Änderungen am DOM darstellt. Dies ist besser als $(document).ready() oder document DOMContentLoaded, wo der Code nur einmal ausgeführt wird.

Wann ist Drupal-Verhalten unerwünscht?

Drupal-Verhaltensweisen sind nicht immer die perfekte Lösung, um Javascript in Drupal zu schreiben. In einigen Fällen, wie unten angegeben, werden Drupal-Verhaltensweisen überhaupt nicht benötigt!

  • Wenn wir Code ausführen müssen, der das DOM nicht beeinflusst. Z.B. Initialisieren eines externen Skripts wie Google Analytics
  • Wenn einige JS-Operationen nur einmal auf dem DOM ausgeführt werden müssen, da bekannt ist, dass das Element verfügbar ist, wenn die Seite geladen wird (dieses Szenario unterscheidet sich von der Verwendung von Once).

Wann werden Drupal-Verhalten aufgerufen?

  • Nachdem ein Administrations-Overlay in die Seite geladen wurde.
  • Nachdem die AJAX-Formular-API ein Formular übermittelt hat.
  • Wenn eine AJAX-Anforderung einen Befehl zurückgibt, der den HTML-Code ändert, wie z. B. ajax_command_replace() .

Andere Male, wenn Drupal-Verhalten aufgerufen werden

  • CTools ruft es auf, nachdem ein Modal geladen wurde.
  • Media ruft es auf, nachdem der Medienbrowser geladen wurde.
  • Panels ruft es auf, nachdem die direkte Bearbeitung abgeschlossen wurde.
  • Views ruft es nach dem Laden einer neuen Seite auf, die AJAX verwendet.
  • Views Load More ruft es nach dem Laden des nächsten Teils von Elementen auf.
  • JavaScript von benutzerdefinierten Modulen kann Drupal.attachBehaviors() aufrufen, wenn sie Teile der Seite hinzufügen oder ändern.

Schreiben von Code ohne Drupal-Verhalten

In diesem Code fügen wir der .views-row- Klasse einen Click- Event-Listener hinzu, der berechnet, wie oft wir auf diese Zeile klicken. Aber es wird nur einmal zu den Elementen hinzugefügt, die während des anfänglichen Ladens der Seite in das DOM kommen. Nachdem Sie auf Mehr laden geklickt und weitere Elemente geladen haben, funktioniert der Klick-Listener nicht mit den neu geladenen Elementen.

 // 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; }); }); })(); 
Ereignis-Listener

Wie verwenden wir Drupal-Verhalten?

Antwort: Mit der Attach- Methode

Dinge, an die Sie sich erinnern sollten:

  • Das neue Objekt muss mindestens eine Attach-Methode haben.
  • Jedes Mal, wenn Drupal.attachBehaviors aufgerufen wird, durchläuft es alle Verhaltensobjekte und ruft ihre jeweiligen Attach-Methoden auf.

Hinzufügen von Drupal-Verhalten zu unserem Code

Nach dem Hinzufügen von Drupal Behaviors sieht der Code in etwa so aus.

 (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);

Aber oben erscheint etwas Seltsames, wenn wir auf Mehr laden klicken:

Verhalten

Dies liegt daran, dass das Drupal-Verhalten oft aufgerufen wird und wir anschließend ein unbeabsichtigtes Verhalten erhalten.

Was ist Kontext im „Drupal-Kontext“?

  • Beim Aufruf der Attach-Methode für alle Verhaltensweisen übergibt Drupal einen Kontextparameter .
  • Der übergebene Kontextparameter kann oft eine bessere Vorstellung davon vermitteln, welches DOM-Element verarbeitet wird.
  • Beim erstmaligen Laden der Seite ist dies das vollständige HTML-Dokument; bei nachfolgenden Aufrufen sind dies nur die Elemente, die der Seite hinzugefügt oder geändert werden.

Wie füge ich Kontext hinzu?

Das vorherige Problem kann gelöst werden, indem der Kontextparameter verwendet wird, der von Drupal Behaviors bereitgestellt wird. In diesem Fall erhalten wir beim ersten Laden der Seite das gesamte HTML-Dokument als Kontext, und dann hängen wir den Header an. Für weitere Operationen wird es der Teil des Codes sein, der von Drupal-Verhaltensweisen betroffen ist, und daher wird dieser Teil des Codes sicher kontrolliert.

 (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);

Wieder gibt es ein seltsames Verhalten, wenn wir auf Load More klicken. Die ursprünglich geladenen Lebensmittel funktionieren einwandfrei. Aber nachdem Sie auf Mehr laden geklickt haben, erhalten die neuen Elemente den Klick-Listener und funktionieren normal. Aber die anfangs geladenen Elemente werden dem Listener erneut hinzugefügt, und ein Klick darauf ruft das Click-Ereignis mehr als einmal auf!

Mehr laden

Wann fangen Drupal-Verhaltensweisen an, sich schlecht zu verhalten?

  • Alle Ereignis-Listener in Drupal-Verhalten schreiben, ohne Once und Context zu verwenden.
  • Deklaration unerwünschter Funktionen innerhalb von Drupal-Verhalten, was bei jedem Aufruf der Attach-Methode zur Neudeklaration von Funktionen führt.

„Einmal“ zur Rettung

  • Once stellt sicher, dass etwas nur einmal verarbeitet wird, indem ein Data-Once-Attribut in einem DOM-Element hinzugefügt wird, nachdem der Code ausgeführt wurde.
  • Wenn das Verhalten erneut aufgerufen wird, wird das Element mit dem Data-Once-Attribut zur weiteren Ausführung übersprungen.
  • Once ist eine moderne Implementierung von jQuery.once (was ein Versuch ist, sich von jQuery zu entfernen)
  • Einmal, in Kombination mit Kontext, steuert die gesamte Funktionalität perfekt so, wie wir sie brauchen.

Einmal hinzufügen, um die Ereignis-Listener in unserem Code zu reparieren

 (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);
Daten einmal

Jetzt funktioniert alles wie vorgesehen. Wir erhalten ein Data-Once- Attribut für die Elemente, an denen die Ereignis-Listener angehängt sind, und neu geladene Elemente und zuvor geladene Elemente funktionieren ordnungsgemäß.

Die Need-for-Detach-Methode

Die Detach-Methode verhält sich wie ein Antiheld (nicht böse) und entfernt alles, was wir in der Attach-Methode gemacht haben. Jeglicher Code in der Methode „detach“ wird immer dann aufgerufen, wenn Inhalt aus dem DOM entfernt wird. Dies hilft uns, unsere Anwendung zu bereinigen. Die Detach-Methode ermöglicht es uns beispielsweise, unerwünschte Ereignis-Listener zu entfernen, die Ressourcen wie eine kontinuierliche Abfragesituation verbrauchen.

Beispiele für Trennen

Angenommen, wir müssen ein Ajax-Formular ausfüllen und verwenden einen Timer, um die verstrichene Zeit anzuzeigen. Wir verwenden setTimeOut, um den Timer zu verwalten. Wir protokollieren diesen Timer in der Konsole zur Überwachung.

 (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);
Zeitüberschreitung einstellen

Beim Absenden des Formulars wird der Timer auf DOM entfernt, aber die Konsole beginnt, einen Fehler auszugeben. Dies liegt daran, dass das Element, auf das setTimeOut wirkt, aus DOM entfernt wurde:

ablösen

Um dies zu vermeiden, können wir die Detach-Methode wie folgt verwenden:

 (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);

Dadurch wird der Timer beim Entladen entfernt, und wie aus dem Logger ersichtlich, tritt der Fehler nicht auf.

JS-Demo

Sofort aufgerufene Funktionsausdrücke (IIFE) – Der Wrapper für JS

Wir haben IIFE verwendet, um unseren Drupal-Code zu schreiben. Die anfänglich öffnenden Klammern definieren eine anonyme Funktion, die verhindert, dass der Bereich der Funktion den globalen Bereich der gesamten Anwendung verschmutzt. Sie können Argumente an Ihre anonyme Funktion übergeben, indem Sie sie als Argumente am Ende der Funktionsdefinition einfügen.

Dies hilft uns auch, die Parameter so zu benennen, wie wir sie verwenden möchten.

Beispiel:

 // 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);

Abschließende Gedanken

Die Implementierung von Drupal-Verhalten ermöglicht dynamische Interaktivität, optimierte Benutzerinteraktion, verbessertes Benutzerfeedback, effiziente Entwicklung und insgesamt verbesserte Benutzererfahrung Ihrer Website. Drupal.behaviors sind flexibel und modular, da sie mehrfach auf einer Seite ausgeführt werden können, vorhandenes Verhalten überschreiben und erweitern und automatisch auf jeden über Ajax geladenen Inhalt erneut angewendet werden können.

Suchen Sie nach einer Drupal-Entwicklungsagentur, die Ihnen hilft, interaktive Web-Erlebnisse zu erstellen und das Beste aus Drupal herauszuholen? Wir würden uns gerne unterhalten!