Ember Components zu Discourse hinzufügen

Im vorherigen Tutorial habe ich gezeigt, wie man sowohl die Server- als auch die Client-Seite von Discourse konfiguriert, um auf eine Anfrage zu antworten.

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

Altes Tutorial

In diesem Tutorial werde ich eine neue Ember-Komponente erstellen, um Drittanbieter-Javascript einzubinden. Dies wird ähnlich einem YouTube-Video sein, das ich vor einiger Zeit erstellt habe und das Sie möglicherweise informativ finden, nur dass dieses Mal spezifisch für Discourse und die Anordnung von Dateien in unserem Projekt ist.

Warum Komponenten?

Handlebars ist eine recht einfache Vorlagensprache. Es ist nur reguläres HTML zusammen mit einigen dynamischen Teilen. Dies ist einfach zu erlernen und gut für die Produktivität, aber nicht so gut für die Wiederverwendung 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 die Lösung von Ember für dieses Problem. Erstellen wir eine Komponente, die unseren Snack auf schönere Weise anzeigt.

Erstellen einer neuen Komponente

Komponenten müssen einen Bindestrich im 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 nun zu verwenden, ersetzen wir unsere bestehende admin/snack-Vorlage durch diese:

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 ihr einfach das Modell übergeben, wie erforderlich.

Hinzufügen von benutzerdefiniertem Javascript-Code

Abgesehen von der Wiederverwendbarkeit eignen sich Komponenten in Ember hervorragend, um sicher benutzerdefiniertes Javascript, jQuery und anderen externen Code hinzuzufügen. Sie erhalten 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 eines langsam verblassenden gelben Hintergrunds aufweist.

Lassen Sie uns erklären, was hier vor sich geht:

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

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

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

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

Sie fragen sich vielleicht, warum wir uns überhaupt um willDestroyElement kümmern; der Grund ist, dass es in einer langlebigen Javascript-Anwendung wie Discourse wichtig ist, aufzuräumen, um Speicherlecks oder laufende Prozesse zu vermeiden. In diesem Fall stoppen wir die Animation, was allen jQuery-Timern mitteilt, dass sie nicht mehr feuern müssen, da die Komponente nicht mehr auf der Seite sichtbar ist.

Wie geht es weiter?

Das letzte Tutorial in dieser Reihe behandelt das automatisierte Testen.


Dieses Dokument wird versioniert – Änderungen vorschlagen auf github.

17 „Gefällt mir“

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

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“