Como adicionar manualmente conteúdos ao pluginOutlet após uma chamada ajax? E como re-renderizar ou atualizar um pluginOutlet?

Olá, :wave:

Sou novo em temas do Discourse e emberjs, e atualmente estou trabalhando em um tema que tem itens de navegação do site principal.
Os itens de navegação json vêm de uma requisição ajax e preciso exibi-los em 2 locais.

1º local é header-buttons:before. Consegui fazer isso com api.decorateWidget e disparando os 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");

	// Para exibir no local (2º local, veja abaixo)
	// ...
	// ...
}

O 2º local é via pluginOutlet, below-site-header.
Acredito que não posso fazer o mesmo que acima, usando api.decorateWidget, porque este é um pluginOutlet, não um widget(?).

Minhas perguntas são:

  1. Como inserir manualmente o conteúdo ajax no pluginOutlet?
  2. Gostaria também de saber como compilar um virtual-dom dinamicamente após minha chamada ajax? Por exemplo, a variável acima, headerNav, gostaria de obter uma marcação HTML compilada dela. Não tenho certeza de qual lib/função usar.
  3. Se possível, como também renderizar novamente um pluginOutlet? Semelhante a appEvents.trigger("site-header:force-refresh");

Obrigado antecipadamente! :man_bowing:

2 curtidas

Correto. Existem duas maneiras de fazer isso…

  1. Você pode fazer sua personalização ser um widget e, em seguida, montar o widget no plugin outlet assim:

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

    Você pode ver um exemplo de como um widget é criado no Discourse, por exemplo, o logo inicial: discourse/app/assets/javascripts/discourse/app/widgets/home-logo.js at 2dbcea9eeeb816dda347027497b3a49634ef851f · discourse/discourse · GitHub

    Em um tema, você adicionaria seu arquivo widget-name.js a um diretório javascripts/discourse/widgets

    Há mais sobre widgets em A tour of how the Widget (Virtual DOM) code in Discourse works, mas observe que vamos descontinuar gradualmente os widgets, então qualquer coisa que você aprender neste processo não será útil a longo prazo.

  2. Mantenha seu decorador de widget como está e crie um componente Ember separado que faça o que você deseja no plugin outlet. Estamos descontinuando os widgets em favor de componentes Ember (que é o que a maior parte do Discourse é construída).

    Este processo seria assim:

    1. Crie um arquivo JS e HBS (template) do componente no diretório javascripts/discourse/components do seu tema.
    • component-name.js

    • component-name.hbs

    1. Construa seu componente Ember… infelizmente esta etapa é essencialmente “aprender Ember” (Guias Ember) … mas acho que isso pode lhe dar uma ideia geral para começar:
    • Em 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(); // assumindo que é json
          this.navLinks = data;
        } catch (error) {
          console.error("Falha:", error);
        }
      }
    }
    
    • Em component-name.hbs:
    <div {{did-insert this.fetchNavLinks}}>
     {{#each this.navLinks as |link|}}
       <a href={{link.anchor}}>{{link.title}}</a>
     {{/each}}
    </div>
    

    Isso chamará a ação fetchNavLinks sempre que o componente for inserido (neste caso, quando você visita o site do Discourse e o aplicativo renderiza). Sempre que navLinks for atualizado, o conteúdo do componente será atualizado porque é uma propriedade rastreada.

    Se você quiser atualizar os links com mais frequência do que na renderização do componente, precisará adicionar mais lógica ao JS aqui… verificando se a rota (página) atual atende a certas condições, por exemplo.

    1. Este componente seria adicionado a um plugin outlet adicionando-o ao outlet em javascripts/discourse/connectors/below-site-header/my-component-connector.hbs:
    <ComponentName />
    
9 curtidas

Muito obrigado, Kris! Isso é muito útil.

Optei pela segunda abordagem, usando componente, já que os widgets estão gradualmente sendo descontinuados. Exceto pelo pequeno erro de digitação na chamada da função, no arquivo .hbs deveria ser {{did-insert this. fetchNavLinks}}, tudo funciona!

É ótimo saber que temos did-insert, isso é um grande alívio! Terminei a tarefa. :man_bowing:

1 curtida

ah, ainda bem que você notou, corrigi minha postagem acima

1 curtida

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