¿Cómo agregar manualmente contenido a pluginOutlet después de una llamada ajax? ¿Y cómo volver a renderizar o actualizar un pluginOutlet?

Hola, :wave:

Soy nuevo en la tematización de Discourse y emberjs, y actualmente estoy trabajando en un tema que tiene elementos de navegación del sitio web principal.
Los elementos de navegación JSON provienen de una solicitud ajax y necesito mostrarlos en 2 ubicaciones.

La primera ubicación es header-buttons:before. Logré hacerlo con api.decorateWidget y activando los eventos de la aplicación 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");

	// Para mostrar en la ubicación (2da ubicación, ver abajo)
	// ...
	// ...
}

La segunda ubicación es a través de pluginOutlet, below-site-header.
Creo que no puedo hacer lo mismo que lo anterior, usando api.decorateWidget, porque esto es un pluginOutlet, ¿no un widget?

Mis preguntas son:

  1. ¿Cómo inserto manualmente contenido ajax en el pluginOutlet?
  2. También me gustaría saber cómo compilar un virtual-dom sobre la marcha después de mi llamada ajax. Por ejemplo, la variable anterior, headerNav, me gustaría obtener una representación HTML compilada de ella. No estoy seguro de qué biblioteca/función usar.
  3. Si es posible, ¿cómo volver a renderizar también un pluginOutlet? similar a appEvents.trigger("site-header:force-refresh");

¡Gracias de antemano! :man_bowing:

2 Me gusta

Correcto. Hay dos maneras de hacerlo…

  1. Puedes hacer que tu personalización sea un widget y luego montar el widget en el plugin outlet de esta manera:

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

    Puedes ver un ejemplo de cómo se crea un widget en Discourse, por ejemplo el logo de inicio: discourse/app/assets/javascripts/discourse/app/widgets/home-logo.js at 2dbcea9eeeb816dda347027497b3a49634ef851f · discourse/discourse · GitHub

    En un tema, añadirías tu archivo widget-name.js a un directorio javascripts/discourse/widgets.

    Hay más información sobre widgets en A tour of how the Widget (Virtual DOM) code in Discourse works, pero ten en cuenta que vamos a eliminar gradualmente los widgets, por lo que cualquier cosa que aprendas en este proceso no será útil a largo plazo.

  2. Mantén tu decorador de widget como está y crea un componente Ember separado que haga lo que quieras en el plugin outlet. Hemos estado eliminando gradualmente los widgets en favor de los componentes Ember (que es en lo que se basa la mayor parte de Discourse).

    Este proceso se vería así:

    1. Crea un archivo JS y HBS (plantilla) del componente en el directorio javascripts/discourse/components de tu tema.
    • component-name.js

    • component-name.hbs

    1. Construye tu componente Ember… desafortunadamente este paso es esencialmente “aprender Ember” (Guías de Ember) … pero creo que esto te dará una idea aproximada para empezar:
    • En 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(); // asumiendo que es json
          this.navLinks = data;
        } catch (error) {
          console.error("Falló:", error);
        }
      }
    }
    
    • En component-name.hbs:
    <div {{did-insert this.fetchNavLinks}}>
     {{#each this.navLinks as |link|}}
       <a href={{link.anchor}}>{{link.title}}</a>
     {{/each}}
    </div>
    

    Esto llamará a la acción fetchNavLinks cada vez que se inserte el componente (en este caso, cuando visites el sitio de Discourse y la aplicación se renderice). Cada vez que navLinks se actualice, el contenido del componente se actualizará porque es una propiedad rastreada.

    Si quieres actualizar los enlaces con más frecuencia que al renderizar el componente, necesitarás añadir algo más de lógica al JS aquí… comprobando si la ruta actual (página) cumple ciertas condiciones, por ejemplo.

    1. Este componente se añadiría a un plugin outlet añadiéndolo al outlet en javascripts/discourse/connectors/below-site-header/my-component-connector.hbs:
    <ComponentName />
    
9 Me gusta

¡Muchas gracias Kris! Esto es muy útil.

Opté por el segundo enfoque, usando componentes, ya que los widgets están siendo gradualmente eliminados. Aparte del pequeño error tipográfico en la llamada a la función, en el archivo .hbs debería ser {{did-insert this. fetchNavLinks}}, ¡todo funciona!

Me alegra saber que tenemos did-insert, es un gran alivio. He terminado la tarea. :man_bowing:

1 me gusta

Ah, me alegro de que te hayas dado cuenta, he corregido mi publicación anterior

1 me gusta

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