keyboard_arrow_up

Symfony - Initialiser les comportements JavaScript sur un fragment hinclude

Rédigé par Sylvain Lavielle
Développeur web freelance expert Drupal sur Toulouse

Le 11/02/2020

Symfony dispose d’une fonction twig render_hinclude permettant d’insérer du contenu de manière asynchrone en utilisant hinclude.js.

Cette fonction peut être très pratique notamment pour insérer un fragment HTML qui doit rester dynamique dans une page qui utilise un système de cache comme FOSHttpCacheBundle.

Cependant ce fragment HTML peut nécessiter l’exécution de JavaScript une fois chargé permettant d'initialiser certains comportements comme par exemple un menu dropdown présent dans ce fragment. Cette initialisation ne peut être fait de manière synchrone dans le script principal de la page car au moment de l'exécution de ce script, le fragment ne sera pas encore chargé. Il va donc falloir recourir à une initialisation asynchrone.

En premier lieu, il va falloir être prévenu lorsque le chargement du fragment est terminé et inséré dans le DOM. Pour nous aider, la librairie hinclude.js dispose d’un événement "hinclude" qu’elle produit à la fin du chargement d’un fragment et dont on va pouvoir se servir. Voici un exemple de la façon dont on peut l'utiliser.

Implantation du hinclude dans le fichier twig

Un des templates twig composant la page principale contiendra la fonction render_hinclude.

{{ render_hinclude(path('path_to_fragment_route', {}), { 
  'default': 'loading-hinclude_placeholder.html.twig', 
  'attributes': {'class': 'hinclude-header'}
}) }}

Cette fonction twig va générer le code HTML suivant dans lequel la librairie hinclude.js va déclencher automatiquement le chargement du fragment dynamique.

<hx:include class="hinclude-header" src="/menu/main">
	...
</hx:include>

Initialisation JavaScript

Dans le JavaScript chargé initialement dans la page principale, Il est alors possible de lancer l’initialisation en capturant l’évènement "hinclude" :

document.addEventListener("DOMContentLoaded", function() {
   initHInclude() ;
});

/**
 * Initialisation lors du chargement d'un hinclude.
 */
function initHInclude() {
  const hincludeElements = document.getElementsByTagName('hx:include') ;
  hincludeElements.forEach(function(hincludeElement) {
    // Initialisation du header
    if (hincludeElement.classList.contains('hinclude-header')) {
      hincludeElement.addEventListener('hinclude', function(e) {
          
        // Initialisation JS …

      })
    })
  }
}

Sujets abordés dans cet article