Add Ember Components to Discourse

In the previous tutorial I showed how to configure both the server and the client side parts of Discourse to respond to a request.

In this tutorial, I’m going to create a new Ember Component as a way to wrap third party Javascript. This is going to be similar to a YouTube video I made a while back, which you may find informative, only this time it’s specific to Discourse and how we lay out files in our project.

Why Components?

Handlebars is quite a simple tempting language. It’s just regular HTML along with some dynamic parts. This is simple to learn and great for productivity, but not so great for code re-use. If you’re developing a large application like Discourse, you’ll find that you want to re-use some of the same things over and over.

Components are Ember’s solution to this problem. Let’s create a component that will display our snack in a nicer way.

Creating a new Component

Components need to have a dash in their name. I’m going to choose fancy-snack as the name for this one. Let’s create our template:


<div class='fancy-snack-title'>

<div class=‘fancy-snack-description’>

Now, to use our component, we will replace our existing admin/snack template with this:


{{fancy-snack snack=model}}

We can now re-use our fancy-snack component in any other template, just passing in the model as required.

Adding Custom Javascript Code

Besides re-usability, Components in Ember are great for safely adding custom Javascript, jQuery and other external code. It gives you control of when the component is inserted into the page, and when it is removed. To do this, we define an Ember.Component with some code:


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

willDestroyElement() {

If you add the above code and refresh the page, you’ll see that our snack has an animation of a slowly fading yellow background.

Let’s explain what’s going on here:

  1. When the component is rendered on the page it will call didInsertElement

  2. The first line of didInsertElement (and willDestroyElement) is this._super() which is necessary because we’re subclassing Ember.Component.

  3. The animation is done using jQuery’s animate function.

  4. Finally, the animation is cancelled in the willDestroyElement hook, which is called when the component is removed from the page.

You might wonder why we care about willDestroyElement at all; the reason is in a long lived Javascript application like Discourse it’s important to clean up after ourselves, lest we leak memory or leave things running. In this case we stop the animation, which tells any jQuery timers that they needn’t fire any more as the component is no longer visible on the page.

Where to go from here

The final tutorial in this series covers automated testing.