CODEX

I ❤ Ember.js — Templates

Writing presentational code separately in Ember is incredibly powerful, here’s why.

Evan Martinez
CodeX

--

https://cdn-images-1.medium.com/max/2600/1*xEOLl2-qU5fQCzkzEybNag.jpeg
Photo by Paul Skorupskas on Unsplash

I ❤ Ember.js is a series where I talk all about how to use Ember and why you should be using it in your projects. I’ve been working with Ember for a few years, and it’s become my favorite tool for creating powerful web apps, and for doing it easily!

When I’m working on software, it’s easy for me to get overwhelmed by holding too many things in my head at once. That’s because building a front-end application is a complex task! All at once, developers need to write code to render visual elements, bind those elements to data, and make it all interactive to execute business/application logic. One reason I ❤ Ember.js is because it separates your presentational code into template files, such that when you’re working on a template you can focus on the presentational aspects of your application. In addition, Handlebars allows us to introduce logic without compromising on keeping our code semantic.

Quick Recap

Templates have access to data coming from a backing class, such as a controller. Any properties defined in that class can be rendered in the corresponding template. Given a controller:

class MyController extends Controller {
favoriteAnimal = 'dog'
}

We could use the property in a template like so:

<div>
<p>My favorite animal: {{this.favoriteAnimal}}</p>
</div>

We haven’t covered components in-depth yet, but if this were a component’s template, the only difference would be that if favoriteAnimal had been passed in, it would be accessed with an @ symbol:

<div>
<p>My favorite animal: {{@favoriteAnimal}}</p>
</div>

Pretty simple right? It’s a lot like JSX in React, except we can’t write Javascript in those squiggly braces, we have to use already-defined variables.

Helpers

Even though we can’t write straight Javascript in templates, we do have access to helpers. Helpers allow us to implement logic in templates in such a way that our template code stays

  • uncluttered,
  • presentational, and
  • semantic

Imagine we have to iterate over a users array, and each user has a catch phrase that we want to conditionally render if they’re famous (I know, it’s a weird scenario). Here’s how we might do it in a React render function:

render() {
const { users } = this.props;
return (
<div>
{
users.map(user => {
if (user.isFamous) {
return <h1>{user.catchPhrase}</h1>;
}

return <p>Hello!</p>;
})
}
</div>
);
}

And that’s not too bad! It’s got decent spacing, and it’s decently easy to understand what this function will render. Now let’s compare it to the template we’d write in Ember:

<div>
{{#each @users as |user|}}
{{#if user.isFamous}}
<h1>{{user.catchPhrase}}</h1>
{{else}}
<p>Hello!</p>
{{/if}}
{{/each}}
</div>

Now I might be biased, but I think the Ember template code is easier to understand (and it was easier to write)! Here’s why:

  • Helpers condense logic into simple operators like each, so we don’t need to clutter the code to perform common operations like iterating over an array.
  • The only logic in the template has to do with what we’ll present to the user. There’s nothing here about how we got the @users property. That keeps us focused.
  • The template file is just easier to read. There is definitely a small context switch that happens when you have to jump between parsing HTML and Javascript algorithms within the same space. The language used in Handlebars is natural and keeps us in the presentational frame of mind.

Even though Handlebars limits the logic we can implement, there’s plenty of cool things we can still do.

Photo by Josh Rakower on Unsplash

Loop & Loop

We’ve seen how to iterate over an array, but the each helper can do a couple more things for us! Maybe you need to render the index of each entry:

<div>
<h1>Guest List</h1>
{{#each @guests as |guest index|}}
<p>{{guest.fullName}} is number {{index}} in the list.</p>
{{/each}}
</div>

Or maybe you want to render different content if the array is empty with else:

<div>
{{#each @blogPosts as |post|}}
<p>{{post.content}}</p>
{{else}}
<h1>You haven't written anything yet!</h1>
{{/each}}
</div>

Do Something!

Your templates will most likely need to be interactive, and you can easily call functions defined in the component or controller:

<!-- template.hbs --><div>
{{#each @artists as |artist|}}
<button {{on 'click' this.likeArtist artist}}>Like</button>
{{/each}}
</div>

Where likeArtist is a function defined in the component like so:

// component.jsclass ArtistList extends Component {
@action
likeArtist(artist) {
// perform the 'like' functionality
}
}

Custom Helpers

You can even write your own helpers! You can use ember-cli to create a new helper that you can then use in templates. For example, after running

ember g helper hotdog

You’ll get a new helper file you can edit:

// helpers/hotdog.jsfunction hotdog(testString) {
if (testString === 'hot dog') {
return 'hot dog';
} else {
return 'not hot dog';
}
}

Then you can start using your new helper in templates!

<div>
{{#each testSubjects as |subject|}}
<p>Subject Status: {{hotdog subject}}</p>
{{/each}}
</div>

Sub-Components

I saved a super cool thing you can do for last. Let’s say that you have an article component that you’ve split up into sub-components for rendering things like the header, body, and footer. You might use them in a template like so:

<div>
<ArticleHeader @title="Isn't Ember Great?" />
<ArticleBody @content="Yes it is." /> <ArticleFooter @author="Evan Martinez" />
</div>

That’s perfectly fine, but Ember offers a neat shortcut. If you rearrange your files such that your sub-components are all in the same folder like so:

Then Ember will let you access them in a more intuitive way:

<div>
<Article::Header @title="Isn't Ember Great?" />
<Article::Body @content="Yes it is." /> <Article::Footer @author="Evan Martinez" />
</div>

And I think that’s just awesome.

Templates are the Way

It’s so easy to implement an application’s presentational layer in Ember. This article was a bit code-heavy, but hopefully the simplicity of Handlebars made it easy to follow. Also, we’ve only scratched the surface on all the built-in helpers that Ember comes with out of the box! What they all have in common is natural, uncluttered language, with a focus on presentational logic.

Photo by Josh Rakower on Unsplash

Just to kick it up a notch, here’s a more complex example of a component:

<!-- the parent controller template --><div>
<UserTable
@users={{this.users}}
@columns={{this.columns}}
/>
</div>

And here’s the UserTable component:

<!-- component template, UserTable.hbs --><table>
<tr>
{{#each @columns as |column|}}
<td>{{column.displayName}}</td>
{{/each}}
</tr>
{{#each @users as |user|}}
<tr>
{{#each @columns as |column|}}
<td>{{get user column.propertyKey}}</td>
{{/each}}
</tr>
{{/each}}
</table>

In case the component name hasn’t given it away, can you tell what the component template will render? It’s a genuine question for any devs out there that are new to Ember, so please leave a comment. Don’t feel bad if it’s still gibberish. See you next time!

This page/product/etc is unaffiliated with the Ember project. Ember is a trademark of Tilde Inc.

--

--