Wie fügt man nach einem Ajax-Aufruf manuell Inhalte zu pluginOutlet hinzu? Und wie rendert oder aktualisiert man ein pluginOutlet neu?

Hallo, :wave:

Ich bin neu bei Discourse-Theming und ember.js und arbeite derzeit an einem Theme, das Navigationselemente von der Hauptwebsite enthält.
Die Nav-Elemente-JSON stammen aus einer Ajax-Anfrage und ich muss sie an 2 Stellen anzeigen.
Der 1. Ort ist header-buttons:before. Das ist mir mit api.decorateWidget und dem Auslösen von site-header:force-refresh gelungen.

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

	// Um an Ort (2. Ort, siehe unten) anzuzeigen
	// ...
	// ...
}

Der 2. Ort ist über pluginOutlet, below-site-header.
Ich glaube, ich kann nicht dasselbe wie oben tun, indem ich api.decorateWidget verwende, weil dies ein pluginOutlet und kein Widget ist(?).

Meine Fragen sind:

  1. Wie füge ich Ajax-Inhalte manuell in das pluginOutlet ein?
  2. Ich würde auch gerne wissen, wie man ein virtuelles DOM im laufenden Betrieb nach meinem Ajax-Aufruf kompiliert? z.B. die obige Variable headerNav, ich möchte eine kompilierte HTML-Markup davon erhalten. Ich bin mir nicht sicher, welche Bibliothek / Funktion ich verwenden soll.
  3. Wenn möglich, wie rendert man ein pluginOutlet neu? Ähnlich wie appEvents.trigger("site-header:force-refresh");

Vielen Dank im Voraus! :man_bowing:

2 „Gefällt mir“

Korrekt. Es gibt zwei Möglichkeiten, dies zu tun…

  1. Sie können Ihre Anpassung zu einem Widget machen und das Widget dann wie folgt im Plugin-Outlet montieren:

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

    Ein Beispiel, wie ein Widget in Discourse erstellt wird, finden Sie zum Beispiel beim Home-Logo: discourse/app/assets/javascripts/discourse/app/widgets/home-logo.js at 2dbcea9eeeb816dda347027497b3a49634ef851f · discourse/discourse · GitHub

    In einem Theme würden Sie Ihre Datei widget-name.js in ein Verzeichnis javascripts/discourse/widgets einfügen.

    Es gibt mehr über Widgets unter A tour of how the Widget (Virtual DOM) code in Discourse works, aber beachten Sie, dass wir Widgets schrittweise ausmustern werden, sodass alles, was Sie in diesem Prozess lernen, langfristig nicht nützlich sein wird.

  2. Behalten Sie Ihren Widget-Decorator bei und erstellen Sie eine separate Ember-Komponente, die das tut, was Sie im Plugin-Outlet möchten. Wir haben Widgets zugunsten von Ember-Komponenten (auf denen ein Großteil von Discourse basiert) ausgemustert.

    Dieser Prozess würde wie folgt aussehen:

    1. Erstellen Sie eine Komponente JS- und HBS-Datei (Vorlage) im Verzeichnis javascripts/discourse/components Ihres Themes.
    • component-name.js

    • component-name.hbs

    1. Erstellen Sie Ihre Ember-Komponente… leider ist dieser Schritt im Wesentlichen “Ember lernen” (Ember Guides) … aber ich denke, dies könnte Ihnen eine grobe Vorstellung für den Anfang geben:
    • In 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(); // assuming this is json
          this.navLinks = data;
        } catch (error) {
          console.error("Failed:", error);
        }
      }
    }
    
    • In component-name.hbs:
    <div {{did-insert this.fetchNavLinks}}>
     {{#each this.navLinks as |link|}}
       <a href={{link.anchor}}>{{link.title}}</a>
     {{/each}}
    </div>
    

    Dadurch wird die Aktion fetchNavLinks aufgerufen, wenn die Komponente eingefügt wird (in diesem Fall, wenn Sie die Discourse-Site besuchen und die App gerendert wird). Immer wenn navLinks aktualisiert wird, wird der Inhalt der Komponente aktualisiert, da es sich um eine getrackte Eigenschaft handelt.
    Wenn Sie die Links öfter als beim Rendern der Komponente aktualisieren möchten, müssen Sie hier etwas mehr Logik in das JS einfügen… zum Beispiel prüfen, ob die aktuelle Route (Seite) bestimmte Bedingungen erfüllt.

    1. Diese Komponente würde zu einem Plugin-Outlet hinzugefügt, indem sie im Outlet in javascripts/discourse/connectors/below-site-header/my-component-connector.hbs hinzugefügt wird:
    <ComponentName />
    
9 „Gefällt mir“

Vielen Dank, Kris! Das ist sehr hilfreich.

Ich habe mich für den zweiten Ansatz entschieden, die Komponente zu verwenden, da Widgets nach und nach auslaufen. Abgesehen von dem kleinen Tippfehler im Funktionsaufruf, in der .hbs-Datei sollte es {{did-insert this. fetchNavLinks}} heißen, funktioniert alles!

Es ist großartig zu wissen, dass wir did-insert haben, das ist eine große Erleichterung! Ich habe die Aufgabe nun abgeschlossen. :man_bowing:

1 „Gefällt mir“

Ah, gut, dass du es bemerkt hast, ich habe meinen Beitrag oben korrigiert.

1 „Gefällt mir“

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