Ajouter des composants Ember à Discourse

Dans le tutoriel précédent, j’ai montré comment configurer les parties serveur et client de Discourse pour répondre à une requête.

Nous vous recommandons désormais de lire la documentation des composants Ember : Introducing Components - Components - Ember Guides

Avant d’écrire un composant, consultez le kit d’interface utilisateur qui regroupe les composants, les helpers et les modificateurs partagés ; la plupart des contrôles courants y sont déjà disponibles.

Ancien tutoriel

Dans ce tutoriel, je vais créer un nouveau Composant Ember afin d’encapsuler du JavaScript tiers. Ce sera similaire à une vidéo YouTube que j’ai réalisée il y a quelque temps, que vous trouverez peut-être informative, mais cette fois-ci, elle sera spécifique à Discourse et à la manière dont nous organisons les fichiers dans notre projet.

Pourquoi les composants ?

Handlebars est un langage assez simple et séduisant. Il s’agit simplement de HTML classique avec quelques parties dynamiques. C’est facile à apprendre et idéal pour la productivité, mais moins adapté à la réutilisation du code. Si vous développez une grande application comme Discourse, vous constaterez que vous souhaitez réutiliser certains éléments à plusieurs reprises.

Les composants sont la solution apportée par Ember à ce problème. Créons un composant qui affichera notre collation de manière plus élégante.

Création d’un nouveau composant

Les composants doivent contenir un tiret dans leur nom. J’ai choisi fancy-snack comme nom pour celui-ci. Créons notre gabarit :

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>

Maintenant, pour utiliser notre composant, nous allons remplacer notre gabarit existant admin/snack par celui-ci :

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

{{fancy-snack snack=model}}

Nous pouvons désormais réutiliser notre composant fancy-snack dans n’importe quel autre gabarit, en passant simplement le modèle requis.

Ajout de code JavaScript personnalisé

Outre la réutilisabilité, les composants dans Ember sont excellents pour ajouter en toute sécurité du JavaScript personnalisé, du jQuery et d’autres codes externes. Ils vous donnent le contrôle sur le moment où le composant est inséré dans la page et sur le moment où il est retiré. Pour ce faire, nous définissons un Ember.Component avec du 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();
  },
});

Si vous ajoutez le code ci-dessus et rechargez la page, vous verrez que notre collation a une animation avec un fond jaune qui s’estompe lentement.

Expliquons ce qui se passe ici :

  1. Lorsque le composant est rendu sur la page, il appelle didInsertElement

  2. La première ligne de didInsertElement (et de willDestroyElement) est this._super(), ce qui est nécessaire car nous sous-classons Ember.Component.

  3. L’animation est réalisée à l’aide de la fonction animate de jQuery.

  4. Enfin, l’animation est annulée dans le hook willDestroyElement, qui est appelé lorsque le composant est retiré de la page.

Vous vous demandez peut-être pourquoi nous nous soucions de willDestroyElement ; la raison est que dans une application JavaScript longue durée comme Discourse, il est important de nettoyer après soi, afin d’éviter les fuites de mémoire ou de laisser des processus en cours d’exécution. Dans ce cas, nous arrêtons l’animation, ce qui indique aux minuteurs jQuery qu’ils n’ont plus besoin de se déclencher puisque le composant n’est plus visible sur la page.

Où aller à partir d’ici

Le tutoriel final de cette série couvre les tests automatisés.


Ce document est versionné - suggérez des modifications sur github.

18 « J'aime »

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

1 « J'aime »

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 « J'aime »

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 « J'aime »

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 « J'aime »

Il serait agréable de voir une documentation mise à jour ici, qui pourrait pointer vers la documentation des composants Glimmer.

3 « J'aime »