Comment déclencher à chaque chargement de footer (ou de page ?).

J’essaie de charger un formulaire JavaScript dans un pied de page.

J’ai ceci dans l’en-tête :

<script type="text/discourse-plugin" version="0.8">
  let loadScript = require("discourse/lib/load-script").default;

  api.onPageChange(() => {
    loadScript("//js.hsforms.net/forms/current.js").then(() => {
      console.log("doing the thing");
      hbspt.forms.create({
        portalId: "229276",
        formId: "a86ca9cc",
        submitButtonClass: "button orange-button hubspot-button",
        target: ".subscription-form"
      });
    });
  });
</script>

Et ceci dans le pied de page :

<div class="subscription-form clearfix">
  <h5>Sign Up for Our Blog</h5>
</div>

La première fois que la page se charge, tout fonctionne correctement. Pour les pages suivantes (la plupart d’entre elles, en tout cas), le formulaire ne se charge pas et l’erreur suivante est signalée :

Couldn't find target container .subscription-form for HubSpot Form a86ca9cc. Not rendering form onto the page

Je pense que le pied de page est peut-être chargé après que le script s’est exécuté ?

Il me faudrait donc retarder l’exécution de ce script jusqu’à ce que le pied de page soit chargé.

plugin-api.js indique :

//  Listen for a triggered `AppEvent` from Discourse.

api.onAppEvent("inserted-custom-html", () => {
  console.log("a custom footer was rendered");
});

Peut-être dois-je simplement savoir quel AppEvent surveiller ?

Il y a un peu d’informations à ce sujet ici.

Javascripts targeting the footer doesn't work after page transitions - #4 by Johani

Lorsque vous utilisez ceci :

api.onAppEvent("inserted-custom-html", () => {
  // some code
});

Vous devez préciser quel HTML personnalisé vous souhaitez cibler — différents événements se déclenchent en fonction de cela.

Dans ce cas, vous voulez cibler le pied de page. Pouvez-vous essayer ceci et voir si cela fonctionne pour vous ?

api.onAppEvent("inserted-custom-html:footer", () => {
  // some code
});

Ha ! Ça a marché ! (Bien sûr, c’était après que je les ai convaincus que ce qu’ils essayaient de faire dans le pied de page ne valait pas la peine d’être fait dès le début). Je suis super ravi d’avoir résolu ce problème et j’apprécie votre aide ; je comprends progressivement ce genre de choses. (Et je pense qu’à présent, ils vont simplement supprimer le pied de page.)

Aha ! Je ne sais pas pourquoi je n’ai pas pensé à chercher « pied de page » ! :man_shrugging:

Donc inserted-custom-html fait référence à tout ce qui se trouve dans les thèmes ? Et ensuite, je pourrais ajouter :footer ou :header ou peut-être :head_tag ? Est-ce là le secret ? Est-ce que c’est juste moi, ou bien

https://github.com/discourse/discourse/blob/master/app/assets/javascripts/discourse/app/lib/plugin-api.js#L516

serait-il plus utile s’il disait plutôt :

   api.onAppEvent('inserted-custom-html:footer', () => {

JavaScript et Ember sont les choses les plus difficiles à comprendre pour moi depuis… peut-être que j’ai appris Lisp au milieu des années 1980, alors je ne parviens toujours pas à déterminer ce qui est « évident ».

Pas tout à fait. Cet événement ne se déclenche que lorsque le composant ember custom-html est rendu.

Alors, où utilisons-nous ce composant ember et que fait-il ?

Nous l’utilisons principalement dans le modèle d’application principal pour rendre deux champs de thème.

Onglet after_header du thème

Onglet pied de page du thème

Notez que nous l’utilisons ailleurs, mais cela n’a pas d’importance dans ce contexte.

Remarquez comment le pied de page contient également triggerAppEvent="true".

C’est pourquoi vous pouvez utiliser :

api.onAppEvent("inserted-custom-html:footer", () => {
  // some code
});

Vous ne pouvez pas faire la même chose avec l’onglet after_header. Discourse ne déclenche pas d’événement pour celui-ci. Donc, cela ne fonctionnera pas.

api.onAppEvent("inserted-custom-html:top", () => {
  // some code
});

Maintenant, pourquoi utilisons-nous ce composant ember pour rendre certains champs de thème ?

La réponse simple est que cela nous donne beaucoup plus de contrôle sur le moment où il est rendu.

Deux exemples à ce sujet… La liste des sujets et la page d’administration.

Nous ne voulons pas rendre le pied de page dans la liste des sujets tant qu’il reste des sujets à charger via le défilement infini.

Nous ne voulons pas non plus rendre les bannières ou le code de marque du site ajoutés dans l’onglet after_header sur la page d’administration.

Ainsi, l’utilisation du composant ember custom-html nous offre un contrôle plus granulaire sur ce genre de choses.

Revenons à votre question. Si vous devez effectuer certaines actions lorsque le pied de page est rendu, c’est l’enveloppe dont vous avez besoin :

api.onAppEvent("inserted-custom-html:footer", () => {
  // some code
});

Cette méthode d’API fonctionne pour tous les événements d’application. Donc, même si l’exemple qui s’y trouve n’est pas vraiment complet, c’est juste un exemple. Il existe de nombreux autres AppEvents que vous pouvez utiliser avec cette méthode. Par exemple, vous pouvez consulter ceci :

pour voir les noms de quelques événements qui se déclenchent.

this.appEvents.trigger("EVENT_NAME")

et comment nous nous y connectons pour apporter d’autres modifications :

this.appEvents.on("EVENT_NAME")

Vous pouvez vous connecter à n’importe quel événement déclenché par le noyau de Discourse dans votre thème. Donc, si je veux exécuter du code juste avant l’ouverture de l’éditeur de message (composer).

discourse/app/assets/javascripts/discourse/app/components/composer-editor.js at 1c38b4abf1fab8d67aaaa4b9f2810add64b709c4 · discourse/discourse · GitHub.

Je peux ajouter quelque chose comme ceci à mon thème :

api.onAppEvent("composer:will-open", () => {
  console.log("cela se déclenche juste avant l'ouverture de l'éditeur");
});

Cela dit, je suis d’accord avec vous. Nous devrions utiliser un exemple différent pour cette méthode dans le fichier d’API. J’ai pris note d’améliorer cet exemple.

C’est une excellente réponse, d’une clarté telle que même moi j’ai pu la comprendre.

Ce problème de « comment déclencher une action » revient assez souvent. Peut-être que les gens le trouveront ici, mais votre dernier post mériterait à lui seul de faire l’objet d’un nouveau sujet, voire d’être ajouté ou lié dans les guides sur les thèmes et/ou les plugins.

Et maintenant que « thème » signifie surtout « Ember » et « plugin » signifie surtout « Rails », il pourrait être judicieux d’envisager de refactoriser un peu ces sections. Il semble qu’à leurs débuts, il y avait beaucoup de fonctionnalités Ember nécessitant un plugin, alors qu’elles peuvent désormais être réalisées dans un composant de thème, n’est-ce pas ? Et aujourd’hui, vous pouvez gérer le code Ember soit dans un plugin, soit dans un composant de thème.

@Johani, une autre version de ce problème « comment déclencher ou être déclenché » est que j’utilise une version de Custom Header Links dans un plugin. Cela crée des liens vers certains éléments (« serveurs ») créés dans un modèle séparé ajouté par mon plugin. Lorsqu’un server est créé, je souhaite reconstruire les liens d’en-tête pour qu’ils pointent vers les deux serveurs créés le plus récemment. Je le fais actuellement dans un initialiseur et cela fonctionne très bien, sauf que pour que cela se mette à jour après l’ajout d’un serveur, vous devez recharger la page.

Vous m’avez expliqué comment ajouter et surveiller des déclencheurs, alors j’ai pensé pouvoir trouver une solution, mais la page qui effectue le travail se trouve dans discourse-subscriptions. Peut-être que ce que je veux faire, c’est soumettre une PR à discourse-subscriptions qui ajoute :

 this.appEvents.trigger("purchase-complete")

une fois l’achat terminé (et que l’achat déclenche l’ajout à un groupe, ce qui déclenche la création d’un serveur et le retrait de l’utilisateur du groupe). Ou, si je pouvais simplement déclencher un rechargement après la fin de l’achat, ou lorsque l’utilisateur clique sur « OK » dans la modale « achat terminé », cela me conviendrait aussi, mais je ne sais pas comment faire cela non plus (ce que j’ai essayé a simplement rechargé la page à l’infini…).

Donc, peut-être ici :

https://github.com/discourse/discourse-subscriptions/blob/main/assets/javascripts/discourse/controllers/s-show.js.es6#L71-L81

Je voudrais ajouter :

 this.appEvents.trigger("successful-transaction")

une fois que le chargement est défini sur false, puis je pourrais ajouter dans mon initialiseur :

 this.appEvents.on("successful-transaction")

pour effectuer la manipulation de l’en-tête ?

Je pense que, une fois cela fait, je devrai faire quelque chose de différent car je crains que :

      api.decorateWidget("header-buttons:before", (helper) => {
        return helper.h("ul.pfaffmanager-header-links", headerLinks);
      });

n’ajoute à header-buttons:before plutôt que de les remplacer, ce qui entraînerait l’apparition de nouveaux liens à chaque déclenchement ?

Cela m’a encore aidé ! Ce que je devais faire, c’était charger un script lorsque le flux de messages était mis à jour. Tous les exemples que j’ai trouvés étaient dans des composants qui avaient accès à appEvent via this. J’ai finalement trouvé ceci et maintenant dans un apiInitializer je peux

  api.onAppEvent('post-stream:refresh', args => {
   // do some stuff!!!
  });

Et maintenant, ces publicités se chargent à chaque chargement de lot de messages. J’ai déjà aimé votre message, j’ai donc dû écrire des remerciements plus détaillés. :wink:

C’est l’un de mes sujets préférés :heart: Je reviens ici de temps en temps :sweat_smile: J’apprécie vraiment cela ! :hugs: