Comment ajouter manuellement des contenus à pluginOutlet après un appel ajax ? Et comment réafficher ou actualiser un pluginOutlet ?

Salut, :wave:

Je suis nouveau sur le theming Discourse et emberjs, et je travaille actuellement sur un thème qui contient des éléments de navigation du site principal.
Les éléments de navigation JSON proviennent d’une requête ajax et je dois les afficher à 2 endroits.

Le 1er endroit est header-buttons:before. J’ai réussi à le faire avec api.decorateWidget et en déclenchant les appEvents site-header:force-refresh.

ajax( settings.site_navigation_links_endpoint ).then((result) => {

	if (!result.length) {
		return;
	}

	result.map((customHeaderLinksArray) => {

		const anchorAttributes = {
			title  : customHeaderLinksArray.title,
			href   : customHeaderLinksArray.url,
			target : "self"
		};

		headerLinks.push(
			h(
				`li.custom-header-nav-item`,
				h( "a.custom-header-nav-item-link", anchorAttributes, customHeaderLinksArray.title )
			)
		);

	});

	headerNav = h("ul.custom-header-nav", headerLinks);

	if( settings.site_navigation_position == "inline" ) {
		api.decorateWidget("header-buttons:before", (helper) => {
			return headerNav;
		});
	}

	appEvents.trigger("site-header:force-refresh");

	// Pour afficher à l'emplacement (2ème emplacement, voir ci-dessous)
	// ...
	// ...
}

Le 2ème endroit est via pluginOutlet, below-site-header.
Je pense que je ne peux pas faire la même chose qu’au-dessus, en utilisant api.decorateWidget, car il s’agit d’un pluginOutlet et non d’un widget(?).

Mes questions sont :

  1. Comment insérer manuellement le contenu ajax dans le pluginOutlet ?
  2. J’aimerais aussi savoir comment compiler un virtual-dom à la volée après mon appel ajax ? Par exemple, la variable ci-dessus, headerNav, j’aimerais obtenir une représentation HTML compilée. Je ne suis pas sûr de la bibliothèque / fonction à utiliser.
  3. Si possible, comment également ré-rendre un pluginOutlet ? Similaire à appEvents.trigger("site-header:force-refresh");

Merci d’avance ! :man_bowing:

2 « J'aime »

Correct. Il y a deux façons de procéder…

  1. Vous pouvez faire de votre personnalisation un widget, puis monter le widget dans le plugin outlet comme ceci :

    {{mount-widget widget="widget-name"}}
    

    Vous pouvez voir un exemple de la façon dont un widget est créé dans Discourse, par exemple le logo d’accueil : discourse/app/assets/javascripts/discourse/app/widgets/home-logo.js at 2dbcea9eeeb816dda347027497b3a49634ef851f · discourse/discourse · GitHub

    Dans un thème, vous ajouteriez votre fichier widget-name.js à un répertoire javascripts/discourse/widgets.

    Il y a plus d’informations sur les widgets dans A tour of how the Widget (Virtual DOM) code in Discourse works, mais notez que nous allons progressivement abandonner les widgets, donc tout ce que vous apprendrez dans ce processus ne sera pas utile à long terme.

  2. Gardez votre décorateur de widget tel quel, et créez un composant Ember séparé qui fait ce que vous voulez dans le plugin outlet. Nous avons progressivement abandonné les widgets au profit des composants Ember (qui constituent la majeure partie de Discourse).

    Ce processus ressemblerait à ceci :

    1. Créez un fichier JS et HBS (template) de composant dans le répertoire javascripts/discourse/components de votre thème.
    • component-name.js

    • component-name.hbs

    1. Construisez votre composant Ember… malheureusement, cette étape consiste essentiellement à « apprendre Ember » (Guides Ember) … mais je pense que cela vous donnera une idée générale pour commencer :
    • Dans component-name.js :
    import Component from "@glimmer/component";
    import { tracked } from "@glimmer/tracking";
    import { action } from "@ember/object";
    
    const endpoint = settings.site_navigation_links_endpoint;
    
    export default class ComponentName extends Component {
      @tracked navLinks = null;
    
      @action
      async fetchNavLinks() {
       try {
          const response = await fetch(endpoint);
          const data = await response.json(); // en supposant que ce soit du json
          this.navLinks = data;
        } catch (error) {
          console.error("Échec :", error);
        }
      }
    }
    
    • Dans component-name.hbs :
    <div {{did-insert this.fetchNavLinks}}>
     {{#each this.navLinks as |link|}}
       <a href={{link.anchor}}>{{link.title}}</a>
     {{/each}}
    </div>
    

    Cela appellera l’action fetchNavLinks chaque fois que le composant sera inséré (dans ce cas, lorsque vous visiterez le site Discourse et que l’application s’affichera). Chaque fois que navLinks sera mis à jour, le contenu du composant sera mis à jour car il s’agit d’une propriété suivie.

    Si vous souhaitez mettre à jour les liens plus souvent qu’au rendu du composant, vous devrez ajouter une logique supplémentaire au JS ici… en vérifiant si la route (page) actuelle remplit certaines conditions, par exemple.

    1. Ce composant serait ajouté à un plugin outlet en l’ajoutant à l’outlet dans javascripts/discourse/connectors/below-site-header/my-component-connector.hbs :
    <ComponentName />
    
9 « J'aime »

Merci beaucoup Kris ! C’est très utile.

J’ai opté pour la deuxième approche, en utilisant un composant, car les widgets sont progressivement abandonnés. Mis à part la petite faute de frappe dans l’appel de fonction, dans le fichier .hbs, il devrait s’agir de {{did-insert this. fetchNavLinks}}, tout fonctionne !

C’est formidable de savoir que nous avons did-insert, c’est un grand soulagement ! J’ai maintenant terminé la tâche. :man_bowing:

1 « J'aime »

ah, content que tu l’aies remarqué, j’ai corrigé mon message ci-dessus

1 « J'aime »

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.