Addomesticare JavaScript in Drupal (include domande frequenti)

Pubblicato: 2023-02-07

Le esperienze Web interattive offrono un'esperienza più coinvolgente e divertente per gli utenti. Porta a una maggiore soddisfazione degli utenti e a una percezione positiva di un sito web. Ad esempio, un modulo che fornisce feedback e convalida istantanei, invece di far attendere l'utente per un aggiornamento della pagina, può migliorare significativamente l'esperienza dell'utente.

JavaScript svolge un ruolo importante in Drupal fornendo i mezzi per creare esperienze dinamiche e interattive per gli utenti sul frontend di un sito Web Drupal. Consente agli sviluppatori di modificare il comportamento di determinati elementi su una pagina, come moduli, collegamenti o qualsiasi altro elemento DOM, senza dover aggiornare l'intera pagina. I comportamenti Drupal sono funzioni JavaScript che vengono eseguite quando si verificano eventi specifici su una pagina. I comportamenti semplificano agli sviluppatori la manutenzione e l'aggiornamento di un sito poiché non è necessario modificare alcun codice HTML sottostante. Scopri tutto quello che volevi sapere sui comportamenti di Drupal nell'articolo.

Addomesticare JavaScript in Drupal

Cosa sono i comportamenti Drupal?

Drupal.behaviors è un oggetto all'interno della struttura Javascript in Drupal, che ci permette di allegare funzioni da eseguire in determinati momenti durante l'esecuzione dell'applicazione. Viene chiamato quando il DOM è completamente caricato, ma questi comportamenti possono essere richiamati di nuovo. La documentazione JavaScript ufficiale di Drupal suggerisce che i moduli dovrebbero implementare JavaScript allegando la logica a Drupal.behaviors .

Perché abbiamo bisogno dei comportamenti Drupal?

Il vantaggio dei comportamenti è che vengono riapplicati automaticamente a qualsiasi contenuto caricato tramite AJAX. Possono essere richiamati in qualsiasi momento con un contesto che rappresenta nuove aggiunte o modifiche al DOM. Questo è meglio di $(document).ready() o document DOMContentLoaded dove il codice viene eseguito solo una volta.

Quando i comportamenti Drupal sono indesiderati?

I comportamenti Drupal non sono sempre la soluzione perfetta per scrivere Javascript in Drupal. In alcuni casi, come indicato di seguito, i comportamenti Drupal non sono affatto necessari!

  • Quando abbiamo bisogno di eseguire del codice che non influisce sul DOM. Per esempio. Inizializzazione di uno script esterno come Google Analytics
  • Quando alcune operazioni JS devono essere eseguite sul DOM solo una volta sapendo che l'elemento sarà disponibile al caricamento della pagina (questo scenario è diverso dall'utilizzo di Once).

Quando vengono chiamati i comportamenti Drupal?

  • Dopo che un overlay di amministrazione è stato caricato nella pagina.
  • Dopo che l'API del modulo AJAX ha inviato un modulo.
  • Quando una richiesta AJAX restituisce un comando che modifica l'HTML, come ajax_command_replace() .

Altre volte in cui vengono invocati i comportamenti Drupal

  • CTools lo chiama dopo che è stato caricato un modale.
  • Media lo chiama dopo che il browser multimediale è stato caricato.
  • Panels lo chiama dopo che la modifica sul posto è stata completata.
  • Views lo chiama dopo aver caricato una nuova pagina che utilizza AJAX.
  • Views Load More lo chiama dopo aver caricato il blocco successivo di elementi.
  • JavaScript da moduli personalizzati può chiamare Drupal.attachBehaviors() quando aggiungono o modificano parti della pagina.

Scrivere codice senza comportamenti Drupal

In questo codice, stiamo aggiungendo un listener di eventi click alla classe .views-row che calcola il numero di volte in cui clicchiamo su questa riga. Ma viene aggiunto solo una volta agli elementi che entrano nel DOM durante il caricamento iniziale della pagina. Dopo aver fatto clic su Carica altro e aver caricato più elementi, il click listener non funziona sugli elementi appena caricati.

 // 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; }); }); })(); 
ascoltatore di eventi

Come usiamo i comportamenti Drupal?

Risposta: utilizzo del metodo di collegamento

Cose da ricordare:

  • Il nuovo oggetto deve avere almeno un metodo di collegamento.
  • Ogni volta che Drupal.attachBehaviors viene chiamato, scorrerà tutti gli oggetti comportamento e chiamerà i rispettivi metodi di collegamento.

Aggiunta del comportamento Drupal al nostro codice

Dopo aver aggiunto Drupal Behaviors, il codice è simile a questo.

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

Ma qualcosa di strano appare in alto quando clicchiamo su Carica altro:

comportamento

Questo perché il comportamento di Drupal viene chiamato molte volte e successivamente otteniamo un comportamento non intenzionale.

Cos'è il contesto in "contesto Drupal"?

  • Quando si chiama il metodo attach per tutti i comportamenti, Drupal passa un parametro di contesto .
  • Il parametro di contesto che viene passato può spesso dare un'idea migliore di quale elemento DOM viene elaborato.
  • Durante il caricamento iniziale della pagina questo sarà il documento HTML completo; durante le chiamate successive, questi saranno solo gli elementi che vengono aggiunti alla pagina o vengono modificati.

Come aggiungere contesto?

Il problema precedente può essere risolto utilizzando il parametro di contesto fornito da Drupal Behaviors. In questo caso, la prima volta che la pagina viene caricata, otteniamo l'intero documento HTML come contesto ed è allora che alleghiamo l'intestazione. Per ulteriori operazioni, sarà la parte del codice che è interessata dai comportamenti Drupal e quindi quella parte del codice è controllata in modo sicuro.

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

Ancora una volta c'è un comportamento strano quando clicchiamo su Carica altro . Gli alimenti inizialmente caricati funzionano bene. Ma dopo aver fatto clic su Carica altro, i nuovi elementi ottengono il click listener e funzionano normalmente. Ma gli elementi inizialmente caricati attirano nuovamente l'ascoltatore e facendo clic su di essi si richiama l'evento clic più di una volta!

Carica di più

Quando i comportamenti Drupal iniziano a comportarsi male?

  • Scrivere tutti gli ascoltatori di eventi all'interno dei comportamenti Drupal senza utilizzare Once e Context.
  • Dichiarare funzioni indesiderate all'interno dei comportamenti Drupal che porta alla nuova dichiarazione delle funzioni ogni volta che viene chiamato il metodo attach.

"Una volta" in soccorso

  • Once assicura che qualcosa venga elaborato solo una volta aggiungendo un attributo data-once in un elemento DOM dopo che il codice è stato eseguito.
  • Se il comportamento viene richiamato di nuovo, l'elemento con l'attributo data-once viene ignorato per un'ulteriore esecuzione.
  • Once è un'implementazione moderna di jQuery.once (che è uno sforzo per allontanarsi da jQuery)
  • Once, in combinazione con il contesto, controlla perfettamente l'intera funzionalità di cui abbiamo bisogno.

Aggiunta di Once per correggere i listener di eventi nel nostro codice

 (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);
dati una volta

Ora tutto funziona come previsto. Otteniamo un attributo data-once per gli elementi in cui sono collegati i listener di eventi e gli elementi caricati di recente e gli elementi caricati in precedenza funzionano correttamente.

Il metodo Need for Detach

Il metodo Detach agisce come un antieroe (non malvagio), rimuovendo tutto ciò che abbiamo fatto nel metodo attach. Qualsiasi codice nel metodo detach verrà chiamato ogni volta che il contenuto viene rimosso dal DOM. Questo ci aiuta a ripulire la nostra applicazione. Ad esempio, il metodo Detach ci consente di rimuovere i listener di eventi indesiderati che consumano risorse come una situazione di polling continuo.

Esempi di Detach

Supponiamo di avere un modulo Ajax da compilare e di utilizzare un timer per mostrare il tempo trascorso. Usiamo setTimeOut per gestire il timer. Registriamo questo timer nella console per il monitoraggio.

 (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);
impostare il timeout

All'invio del modulo, il timer su DOM viene rimosso ma la console inizia a generare un errore. Questo perché l'elemento su cui agisce setTimeOut è stato rimosso dal DOM:

staccare

Per evitare ciò possiamo utilizzare il metodo di distacco in questo modo:

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

Questo rimuove il timer allo scaricamento e, come visto dal logger, l'errore non si verifica.

Dimostrazione JS

Espressioni di funzioni immediatamente richiamate (IIFE): il wrapper per JS

Abbiamo utilizzato IIFE per scrivere il nostro codice Drupal. Le parentesi di apertura iniziali definiscono una funzione anonima che impedisce all'ambito della funzione di inquinare l'ambito globale dell'intera applicazione. Puoi passare argomenti alla tua funzione anonima includendoli come argomenti alla fine della definizione della funzione.

Questo ci aiuta anche a definire lo spazio dei parametri nel modo in cui vogliamo che vengano utilizzati.

Esempio:

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

Pensieri finali

L'implementazione dei comportamenti Drupal consente un'interattività dinamica, un'interazione semplificata con l'utente, un migliore feedback degli utenti, uno sviluppo efficiente e un'esperienza utente complessiva migliorata del tuo sito web. Drupal.behaviors sono flessibili e modulari, in quanto possono essere eseguiti più volte su una pagina, possono sovrascrivere ed estendere il comportamento esistente e possono essere riapplicati automaticamente a qualsiasi contenuto caricato tramite Ajax.

Cerchi un'agenzia di sviluppo Drupal che ti aiuti a creare esperienze web interattive, sfruttando al meglio Drupal? Ci piacerebbe parlare!