Eseguire JavaScript nel tema

Utilizzando $(document).ready(function () {} il codice nella funzione viene eseguito solo al caricamento iniziale della pagina, invece con i behaviors viene eseguito anche al caricamento di nuovo contenuto dopo una chiamata AJAX.

Drupal.behaviors

Con l'utilizzo di Drupal.behaviors il codice JavaScript viene eseguito solo quando il DOM è stato caricato interamente e ogni volta che viene caricato nuovo contenuto via AJAX. Il nome di ciascun behavior deve essere univoco e in camelCase:

(function($, window, Drupal) { //per usare JQuery dichiararlo come dipendenza nel file .libraries.yml

    Drupal.behaviors.nomeTemaClick = {
        attach: function(context, settings) { //all'inizio context è document, dopo una chiamata AJAX è il contenuto aggiunto
            // aggiungere once()
            $('.example', context).click(function() {
                $(this).next('ul').toggle('show');
            });
            $(context).find('a.cool-link').on('click', function() {
                console.log("Link cliccato");
            });
        },
        detach: function(context, settings, trigger) {
            if (trigger === 'unload') {
                // codice da eseguire quando l'elemento è rimosso dalla pagina
            }
        }
    };

})(jQuery, window, Drupal);

La funzione attach()

Il parametro context

Al primo caricamento della pagina il parametro context equivale all'oggetto document, al caricamento di nuovo contenuto dopo una chiamata AJAX context contiene il nuovo contenuto, in questo modo non è necessario scansionare l'intero DOM per agganciare eventi ai selettori.

AJAX e riesecuzione dei behaviors

La funzione once()

La funzione detach()

Dipendenze JavaScript nel .libraries.yml

global-styling:
  version: 1.x
  js:
    js/custom.js: {}
  dependencies:
    - core/jquery
    - core/jquery.once

Passaggio di dati da PHP a JavaScript

Passare dati da PHP a JavaScript con drupalSettings

Se è necessario passare delle variabili da PHP a JavaScript si usa la libreria drupalSettings, che deve essere indicata come dipendenza nel file .libraries.yml.

Nel file .theme:

<?php
/**
* Implements hook_page_attachments_alter().
*/
function nome_tema_page_attachments_alter(array &$attachments) {
  $account = \Drupal::currentUser();
  if ($account->isAuthenticated()) {
    // includiamo la libreria nella pagina solo se l'utente è loggato
    $attachments['#attached']['library'][] = 'nome_tema/nome_libreria';
    // facciamo in modo che nel file JavaScript esista la variabile drupalSettings.nome_tema.name
    $attachments['#attached']['drupalSettings']['nome_tema']['name'] = $account->getDisplayName();
    //dato che il nome varia per ogni utente bisogna impostare la cache in modo che ogni utente veda il proprio nome
    $attachments['#cache']['contexts'][] = 'user';
  }
}

?>

Nel file della libreria JavaScript:

(function (Drupal, drupalSettings) {
  if (drupalSettings.nome_tema.name) {
    var siteName = document.getElementsByClassName('site-branding__name')[0];
    siteName.getElementsByTagName('a')[0].innerHTML = 'Ciao, ' + drupalSettings.nome_tema.name + '!';
  }
})(Drupal, drupalSettings);

Cache context quando i dati variano per utente

Generazione di HTML dentro JavaScript con Drupal.theme

Quando si vuole creare al volo dei pezzi di HTML (ad esempio un messaggio di alert) è meglio non inserire delle stringhe fisse perchè altrimenti le altre funzioni non potrebbero modificarle. E' meglio scrivere una funzione riutilizzabile agganciandola all'oggetto Drupal.theme:

(function ($, window, Drupal, drupalSettings) {

    Drupal.theme.mioMessaggioAvviso = function (messaggio) {
        return '<div class="alert alert-warning" role="alert">' + Drupal.checkPlain(messaggio) + '</div>';
    };

    Drupal.behaviors.nomeTemaMessaggi = {
        attach: function (context, settings) {

            var html = Drupal.theme.mioMessaggioAvviso('Attenzione: sessione in scadenza!');

             $('.mio-contenitore', context).html(html);
            
        },
        detach: function (context, settings, trigger) {
            // Eventuale codice di pulizia
        }
    };

})(jQuery, window, Drupal, drupalSettings);

Sicurezza nella generazione di HTML