Concepts

Core Concept

To get started with Ember.js, there are a few core concepts you should understand.

Ember.js is designed to help developers build ambitiously large web applications that are competitive with native apps. Doing so requires both new tools and a new vocabulary of concepts. We’ve spent a lot of time borrowing ideas pioneered by native application frameworks like Cocoa and Smalltalk.

However, it’s important to remember what makes the web special. Many people think that something is a web application because it uses technologies like HTML, CSS and JavaScript. In reality, these are just implementation details.

Instead, the web derives its power from the ability to bookmark and share URLs. URLs are the key feature that give web applications superior shareability and collaboration. Today, most JavaScript frameworks treat the URL as an afterthought, instead of the primary reason for the web’s success.

Ember.js, therefore, marries the tools and concepts of native GUI frameworks with support for the feature that makes the web so powerful: the URL.

Concepts

Templates

A template, written in the Handlebars templating language, describes the user interface of your application. Each template is backed by a model, and the template automatically updates itself if the model changes.

In addition to plain HTML, templates can contain:

  • Expressions, like {{firstName}}, which take information from the template’s model and put it into HTML.
  • Outlets, which are placeholders for other templates. As users move around your app, different templates can be plugged into the outlet by the router. You can put outlets into your template using the {{outlet}} helper.
  • Components, custom HTML elements that you can use to clean up repetitive templates or create reusable controls.
Router

The router translates a URL into a series of nested templates, each backed by a model. As the templates or models being shown to the user change, Ember automatically keeps the URL in the browser’s address bar up-to-date.

This means that, at any point, users are able to share the URL of your app. When someone clicks the link, they reliably see the same content as the original user.

Components

A component is a custom HTML tag whose behavior you implement using JavaScript and whose appearance you describe using Handlebars templates. They allow you to create reusable controls that can simplify your application’s templates.

Models

A model is an object that stores persistent state. Templates are responsible for displaying the model to the user by turning it into HTML. In many applications, models are loaded via an HTTP JSON API, although Ember is agnostic to the backend that you choose.

Route

A route is an object that tells the template which model it should display.

Controllers

A controller is an object that stores application state. A template can optionally have a controller in addition to a model, and can retrieve properties from both.


These are the core concepts you’ll need to understand as you develop your Ember.js app. They are designed to scale up in complexity, so that adding new functionality doesn’t force you to go back and refactor major parts of your app.

Now that you understand the roles of these objects, you’re equipped to dive deep into Ember.js and learn the details of how each of these individual pieces work.

Naming Conventions

Ember.js uses naming conventions to wire up your objects without a lot of boilerplate. You will want to use these conventional names for your routes, controllers and templates.

You can usually guess the names, but this guide outlines, in one place, all of the naming conventions. In the following examples ‘App’ is a name that we chose to namespace or represent our Ember application when it was created, but you can choose any name you want for your application. We will show you later how to create an Ember application, but for now we will focus on conventions.

The Application

When your application boots, Ember will look for these objects:

  • App.ApplicationRoute
  • App.ApplicationController
  • the application template

Ember.js will render the application template as the main template. If App.ApplicationController is provided, Ember.js will set an instance of App.ApplicationController as the controller for the template. This means that the template will get its properties from the controller.

If your app provides an App.ApplicationRoute, Ember.js will invoke the router’s hooks first, before rendering the application template. Hooks are implemented as methods and provide you access points within an Ember object’s lifecycle to intercept and execute code to modify the default behavior at these points to meet your needs. Ember provides several hooks for you to utilize for various purposes (e.g. model, setupController, etc). In the example below App.ApplicationRoute, which is a Ember.Route object, implements the setupController hook.

Here’s a simple example that uses a route, controller, and template:

 1 App.ApplicationRoute = Ember.Route.extend({
 2   setupController: function(controller) {
 3     // `controller` is the instance of ApplicationController
 4     controller.set('title', "Hello world!");
 5   }
 6 });
 7 
 8 App.ApplicationController = Ember.Controller.extend({
 9   appName: 'My First Example'
10 });
1 <!-- application template -->
2 <h1>{{appName}}</h1>
3 
4 <h2>{{title}}</h2>

In Ember.js applications, you will always specify your controllers as classes, and the framework is responsible for instantiating them and providing them to your templates.

This makes it super-simple to test your controllers, and ensures that your entire application shares a single instance of each controller.

Simple Routes

Each of your routes will have a controller, and a template with the same name as the route.

Let’s start with a simple router:

1 App.Router.map(function() {
2   this.route('favorites');
3 });

If your user navigates to /favorites, Ember.js will look for these objects:

  • App.FavoritesRoute
  • App.FavoritesController
  • the favorites template

Ember.js will render the favorites template into the {{outlet}} in the application template. It will set an instance of the App.FavoritesController as the controller for the template.

If your app provides an App.FavoritesRoute, the framework will invoke it before rendering the template. Yes, this is a bit repetitive.

For a route like App.FavoritesRoute, you will probably implement the model hook to specify what model your controller will present to the template.

Here’s an example:

1 App.FavoritesRoute = Ember.Route.extend({
2   model: function() {
3     // the model is an Array of all of the posts
4     return this.store.find('post');
5   }
6 });

In this example, we didn’t provide a FavoritesController. Because the model is an Array, Ember.js will automatically supply an instance of Ember.ArrayController, which will present the backing Array as its model.

You can treat the ArrayController as if it was the model itself. This has two major benefits:

  • You can replace the controller’s model at any time without having to directly notify the view of the change.
  • The controller can provide additional computed properties or view-specific state that do not belong in the model layer. This allows a clean separation of concerns between the view, the controller and the model.

The template can iterate over the elements of the controller:

1 <ul>
2 {{#each post}}
3   <li>{{title}}</li>
4 {{/each}}
5 </ul>

Dynamic Segments

If a route uses a dynamic segment, the route’s model will be based on the value of that segment provided by the user.

Consider this router definition:

1 App.Router.map(function() {
2   this.resource('post', { path: '/posts/:post_id' });
3 });

In this case, the route’s name is post, so Ember.js will look for these objects:

  • App.PostRoute
  • App.PostController
  • the post template

Your route handler’s model hook converts the dynamic :post_id parameter into a model. The serialize hook converts a model object back into the URL parameters for this route (for example, when generating a link for a model object).

1 App.PostRoute = Ember.Route.extend({
2   model: function(params) {
3     return this.store.find('post', params.post_id);
4   },
5 
6   serialize: function(post) {
7     return { post_id: post.get('id') };
8   }
9 });

Because this pattern is so common, it is the default for route handlers.

  • If your dynamic segment ends in _id, the default model hook will convert the first part into a model class on the application’s namespace (post becomes App.Post). It will then call find on that class with the value of the dynamic segment.
  • The default serialize hook will pull the dynamic segment with the id property of the model object.

Route, Controller and Template Defaults

If you don’t specify a route handler for the post route (App.PostRoute), Ember.js will still render the post template with the app’s instance of App.PostController.

If you don’t specify the controller (App.PostController), Ember will automatically make one for you based on the return value of the route’s model hook. If the model is an Array, you get an ArrayController. Otherwise, you get an ObjectController.

If you don’t specify a post template, Ember.js won’t render anything!

Nesting

You can nest routes under a resource.

1 App.Router.map(function() {
2   this.resource('posts', function() { // the `posts` route
3     this.route('favorites');          // the `posts.favorites` route
4     this.resource('post');            // the `post` route
5   });
6 });

A resource is the beginning of a route, controller, or template name. Even though the post resource is nested, its route is named App.PostRoute, its controller is named App.PostController and its template is post.

When you nest a route inside a resource, the route name is added to the resource name, after a ..

Here are the naming conventions for each of the routes defined in this router:

The rule of thumb is to use resources for nouns, and routes for adjectives (favorites) or verbs (edit). This ensures that nesting does not create ridiculously long names, but avoids collisions with common adjectives and verbs.

The Index Route

At every level of nesting (including the top level), Ember.js automatically provides a route for the / path named index.

For example, if you write a simple router like this:

1 App.Router.map(function() {
2   this.route('favorites');
3 });

It is the equivalent of:

1 App.Router.map(function() {
2   this.route('index', { path: '/' });
3   this.route('favorites');
4 });

If the user visits /, Ember.js will look for these objects:

  • App.IndexRoute
  • App.IndexController
  • the index template

The index template will be rendered into the {{outlet}} in the application template. If the user navigates to /favorites, Ember.js will replace the index template with the favorites template.

A nested router like this:

1 App.Router.map(function() {
2   this.resource('posts', function() {
3     this.route('favorites');
4   });
5 });

Is the equivalent of:

1 App.Router.map(function() {
2   this.route('index', { path: '/' });
3   this.resource('posts', function() {
4     this.route('index', { path: '/' });
5     this.route('favorites');
6   });
7 });

If the user navigates to /posts, the current route will be posts.index. Ember.js will look for objects named:

  • App.PostsIndexRoute
  • App.PostsIndexController
  • The posts/index template

First, the posts template will be rendered into the {{outlet}} in the application template. Then, the posts/index template will be rendered into the {{outlet}} in the posts template.

If the user then navigates to /posts/favorites, Ember.js will replace the {{outlet}} in the posts template with the posts/favorites template.