Aggiungi componenti Ember a Discourse

Nel tutorial precedente ho mostrato come configurare sia la parte lato server che quella lato client di Discourse per rispondere a una richiesta.

Ora ti consigliamo di leggere la documentazione sui componenti Ember: Introducing Components - Components - Ember Guides

Prima di scrivere un componente, controlla il UI kit dei componenti, helper e modificatori condivisi; la maggior parte dei controlli comuni è già presente lì.

Vecchio tutorial

In questo tutorial, creerò un nuovo Ember Component come modo per incapsulare Javascript di terze parti. Sarà simile a un video di YouTube che ho realizzato un po’ di tempo fa, che potresti trovare informativo, solo che questa volta è specifico per Discourse e per come organizziamo i file nel nostro progetto.

Perché i Componenti?

Handlebars è un linguaggio piuttosto semplice e allettante. È solo HTML normale con alcune parti dinamiche. È semplice da imparare e ottimo per la produttività, ma non lo è altrettanto per il riutilizzo del codice. Se stai sviluppando un’applicazione grande come Discourse, scoprirai di voler riutilizzare alcune delle stesse cose di nuovo e di nuovo.

I componenti sono la soluzione di Ember a questo problema. Creiamo un componente che visualizzerà il nostro snack in un modo più gradevole.

Creare un nuovo Componente

I componenti devono avere un trattino nel loro nome. Sceglierò fancy-snack come nome per questo. Creiamo il nostro template:

app/assets/javascripts/admin/templates/components/fancy-snack.hbs

<div class="fancy-snack-title">
  <h1>{{snack.name}}</h1>
</div>

<div class="fancy-snack-description">
  <p>{{snack.description}}</p>
</div>

Ora, per usare il nostro componente, sostituiamo il nostro template esistente admin/snack con questo:

app/assets/javascripts/admin/templates/snack.hbs

{{fancy-snack snack=model}}

Ora possiamo riutilizzare il nostro componente fancy-snack in qualsiasi altro template, passando semplicemente il modello come richiesto.

Aggiungere Codice Javascript Personalizzato

Oltre alla riutilizzabilità, i componenti in Ember sono ottimi per aggiungere in modo sicuro Javascript personalizzato, jQuery e altri codici esterni. Ti danno il controllo di quando il componente viene inserito nella pagina e quando viene rimosso. Per fare questo, definiamo un Ember.Component con un po’ di codice:

app/assets/javascripts/admin/components/fancy-snack.js

export default Ember.Component.extend({
  didInsertElement() {
    this._super();
    this.$().animate({ backgroundColor: "yellow" }, 2000);
  },

  willDestroyElement() {
    this._super();
    this.$().stop();
  },
});

Se aggiungi il codice sopra e aggiorni la pagina, vedrai che il nostro snack ha un’animazione di uno sfondo giallo che svanisce lentamente.

Spieghiamo cosa sta succedendo qui:

  1. Quando il componente viene renderizzato nella pagina, chiamerà didInsertElement

  2. La prima riga di didInsertElement (e willDestroyElement) è this._super(), che è necessaria perché stiamo creando una sottoclasse di Ember.Component.

  3. L’animazione viene eseguita usando la funzione animate di jQuery.

  4. Infine, l’animazione viene annullata nell’hook willDestroyElement, che viene chiamato quando il componente viene rimosso dalla pagina.

Potresti chiederti perché ci preoccupiamo di willDestroyElement; la ragione è che in un’applicazione Javascript longeva come Discourse è importante fare le pulizie, altrimenti potremmo perdere memoria o lasciare cose in esecuzione. In questo caso, fermiamo l’animazione, il che dice a qualsiasi timer di jQuery che non hanno più bisogno di attivarsi poiché il componente non è più visibile nella pagina.

Dove andare da qui

Il tutorial finale di questa serie copre il test automatizzato.


Questo documento è versionato - suggerisci modifiche su github.

18 Mi Piace

Hi, how do i extend a discourse component thru a plugin? Can you give me some points. Thanks

1 Mi Piace

Generally we prefer you don’t extend Discourse plugins, and you stick to plugin outlets or using the widget decoration API to add stuff.

But if you must, you can create an initializer and use Ember’s extend code. Here’s an example that extends an Ember object.

4 Mi Piace

Tried with initializer but didnt worked. What i actually want to do is to add 2 more classNames and some actions:

import { withPluginApi } from 'discourse/lib/plugin-api';

function initializeComponentTopicList(api) {
  // extend component from jsapp/components/topic-list.js.es6
  const TopicList = api.container.lookupFactory('component:topic-list');

  TopicList.extend({
    classNames: ['topic-list', 'round', 'table'],
    actions: {
        clickMe: function() {
            console.log('click');
        }
    }
  });
};

export default {
  name: "extend-for-component-topic-list",

  initialize() {
    withPluginApi('0.1', initializeComponentTopicList);
  }
};

And by “didnt worked”, i mean that topic list completly disappeared from page.
Thank you

Were there any logs in the console?

Nope, no logs at all. However i managed to fix it this way. I hope it will help someone.

import { default as TopicList } from 'discourse/components/topic-list';
import { withPluginApi } from 'discourse/lib/plugin-api';

function initializeComponentTopicList(api) {
  TopicList.reopen({
    classNames: ['topic-list', 'round', 'table'],
  });
};

export default {
  name: "extend-for-component-topic-list",

  initialize() {
    withPluginApi('0.1', initializeComponentTopicList);
  }
};
3 Mi Piace

I just ran into the same problem. Add the following as a css/html customisation and observe empty user cards:

<script type="text/discourse-plugin" version="0.5">
    api.container.lookupFactory('component:user-card-contents')
</script>
2 Mi Piace

Sarebbe bello vedere qui una documentazione aggiornata, che potrebbe rimandare alla documentazione di componente Glimmer.

3 Mi Piace