Ember-Komponenten zu Discourse hinzufügen

In dem vorherigen Tutorial habe ich gezeigt, wie man sowohl den serverseitigen als auch den clientseitigen Teil von Discourse so konfiguriert, dass er auf eine Anfrage reagiert.

Wir empfehlen Ihnen nun, die Dokumentation zu Ember-Komponenten zu lesen: Introducing Components - Components - Ember Guides

Altes Tutorial

In diesem Tutorial werde ich eine neue Ember-Komponente erstellen, um JavaScript von Drittanbietern zu kapseln. Dies ähnelt einem YouTube-Video, das ich vor einiger Zeit erstellt habe und das informativ sein könnte. Diesmal ist es jedoch spezifisch für Discourse und dafür, wie wir die Dateien in unserem Projekt strukturieren.

Warum Komponenten?

Handlebars ist eine recht einfache und einladende Sprache. Es ist einfach reguläres HTML mit einigen dynamischen Teilen. Das ist einfach zu lernen und großartig für die Produktivität, aber nicht so gut für die Wiederverwendbarkeit von Code. Wenn Sie eine große Anwendung wie Discourse entwickeln, werden Sie feststellen, dass Sie einige der gleichen Dinge immer wieder verwenden möchten.

Komponenten sind Embers Lösung für dieses Problem. Erstellen wir eine Komponente, die unseren Snack auf eine schönere Art anzeigt.

Eine neue Komponente erstellen

Komponenten müssen einen Bindestrich in ihrem Namen haben. Ich werde fancy-snack als Namen für diese wählen. Erstellen wir unsere Vorlage:

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>

Um unsere Komponente zu verwenden, ersetzen wir nun unsere bestehende admin/snack-Vorlage durch folgende:

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

{{fancy-snack snack=model}}

Wir können unsere fancy-snack-Komponente nun in jeder anderen Vorlage wiederverwenden, indem wir einfach das erforderliche Modell übergeben.

Benutzerdefinierten JavaScript-Code hinzufügen

Neben der Wiederverwendbarkeit sind Komponenten in Ember großartig, um benutzerdefinierten JavaScript-, jQuery- und anderen externen Code sicher hinzuzufügen. Sie geben Ihnen die Kontrolle darüber, wann die Komponente in die Seite eingefügt und wann sie entfernt wird. Dazu definieren wir eine Ember.Component mit etwas Code:

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();
  },
});

Wenn Sie den obigen Code hinzufügen und die Seite aktualisieren, sehen Sie, dass unser Snack eine Animation mit einem langsam verblassenden gelben Hintergrund hat.

Erklären wir, was hier vor sich geht:

  1. Wenn die Komponente auf der Seite gerendert wird, wird didInsertElement aufgerufen.

  2. Die erste Zeile von didInsertElement (und willDestroyElement) ist this._super(), was notwendig ist, da wir Ember.Component unterklassifizieren.

  3. Die Animation wird mit der jQuery-Funktion animate durchgeführt.

  4. Schließlich wird die Animation im Hook willDestroyElement abgebrochen, der aufgerufen wird, wenn die Komponente von der Seite entfernt wird.

Sie fragen sich vielleicht, warum uns willDestroyElement überhaupt interessiert; der Grund liegt darin, dass in einer langlebigen JavaScript-Anwendung wie Discourse es wichtig ist, nach sich selbst aufzuräumen, um Speicherlecks zu vermeiden oder Prozesse am Laufen zu lassen. In diesem Fall stoppen wir die Animation, was allen jQuery-Timer mitteilt, dass sie nicht mehr feuern müssen, da die Komponente nicht mehr auf der Seite sichtbar ist.

Wo es weitergeht

Das letzte Tutorial dieser Reihe behandelt automatisierte Tests.


Dieses Dokument ist versioniert – schlagen Sie Änderungen auf GitHub vor.

18 „Gefällt mir“

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

1 „Gefällt mir“

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 „Gefällt mir“

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 „Gefällt mir“

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 „Gefällt mir“

Es wäre schön, hier eine aktualisierte Dokumentation zu sehen, die auf die Dokumentation der Glimmer-Komponenten verweisen könnte.

3 „Gefällt mir“