Skip to content

Instantly share code, notes, and snippets.

@pinyin
Created March 19, 2014 09:42
Show Gist options
  • Save pinyin/9638549 to your computer and use it in GitHub Desktop.
Save pinyin/9638549 to your computer and use it in GitHub Desktop.
ember_guides_combined
# Guides and Tutorials
Welcome to the Ember.js guides! This documentation will take you from
total beginner to Ember expert. It is designed to start from the basics,
and slowly increase to more sophisticated concepts until you know
everything there is to know about building awesome web applications.
To help you get started, we've also made a 30-minute screencast that
will guide you through building a full-featured Ember.js application:
Source code for the app we build in the video is available at <a href="https://github.com/tildeio/bloggr-client">https://github.com/tildeio/bloggr-client</a>
Most of these guides are designed to help you start building apps right
away. If you'd like to know more about the thinking behind Ember.js,
you'll find what you're looking for in the _Understanding Ember.js_
section.
These guides are written in Markdown and are [available on
GitHub](https://github.com/emberjs/website/), inside the `source/guides`
directory. If there is something missing, or you find a typo or
mistake, please help us by filing an issue or submitting a pull
request. Thanks!
We're excited for all of the great apps you're going to build with
Ember.js. To get started, select a topic from the left. They are
presented in the order that we think will be most useful to you as
you're learning Ember.js, but you can also jump to whatever seems
most interesting.
Good luck!
# Getting Started
Welcome to Ember.js! This guide will take you through creating a simple application using Ember.js and briefly explain the core concepts behind the framework. This guide assumes you are already familiar with basic web technologies like JavaScript, HTML, and CSS and development technologies like your browser's [web inspector](https://developers.google.com/chrome-developer-tools/).
In this guide we will walk through the steps of building the popular [TodoMVC demo application](http://todomvc.com).
## Planning The Application
TodoMVC, despite its small size, contains most of the behaviors typical in modern single page applications. Before continuing, take a moment to understand how TodoMVC works from the user's perspective.
TodoMVC has the following main features:
<img src="http://emberjs.com/guides/getting-started/images/todo-mvc.png" width="680">
1. It displays a list of todos for a user to see. This list will grow and shrink as the user adds and removes todos.
1. It accepts text in an `<input>` for entry of new todos. Hitting the `<enter>` key creates the new item and displays it in the list below.
1. It provides a checkbox to toggle between complete and incomplete states for each todo. New todos start as incomplete.
1. It displays the number of incomplete todos and keeps this count updated as new todos are added and existing todos are completed.
1. It provides links for the user to navigate between lists showing all, incomplete, and completed todos.
1. It provides a button to remove all completed todos and informs the user of the number of completed todos. This button will not be visible if there are no completed todos.
1. It provides a button to remove a single specific todo. This button displays as a user hovers over a todo and takes the form of a red X.
1. It provides a checkbox to toggle all existing todos between complete and incomplete states. Further, when all todos are completed this checkbox becomes checked without user interaction.
1. It allows a user to double click to show a textfield for editing a single todo. Hitting the `<enter>` key or moving focus outside of this textfield will persist the changed text.
1. It retains a user's todos between application loads by using the browser's `localstorage` mechanism.
You can interact with a completed version of the application by visiting the [TodoMVC site](http://todomvc.com/architecture-examples/emberjs/).
## Creating a Static Mockup
Before adding any code, we can roughly sketch out the layout of our application. In your text editor, create a new file and name it `index.html`. This file will contain the HTML templates of our completed application and trigger requests for the additional image, stylesheet, and JavaScript resources.
To start, add the following text to `index.html`:
```html
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Ember.js • TodoMVC</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<section id="todoapp">
<header id="header">
<h1>todos</h1>
<input type="text" id="new-todo" placeholder="What needs to be done?" />
</header>
<section id="main">
<ul id="todo-list">
<li class="completed">
<input type="checkbox" class="toggle">
<label>Learn Ember.js</label><button class="destroy"></button>
</li>
<li>
<input type="checkbox" class="toggle">
<label>...</label><button class="destroy"></button>
</li>
<li>
<input type="checkbox" class="toggle">
<label>Profit!</label><button class="destroy"></button>
</li>
</ul>
<input type="checkbox" id="toggle-all">
</section>
<footer id="footer">
<span id="todo-count">
<strong>2</strong> todos left
</span>
<ul id="filters">
<li>
<a href="all" class="selected">All</a>
</li>
<li>
<a href="active">Active</a>
</li>
<li>
<a href="completed">Completed</a>
</li>
</ul>
<button id="clear-completed">
Clear completed (1)
</button>
</footer>
</section>
<footer id="info">
<p>Double-click to edit a todo</p>
</footer>
</body>
</html>
```
The associated [stylesheet](http://emberjs.com.s3.amazonaws.com/getting-started/style.css) and [background image](http://emberjs.com.s3.amazonaws.com/getting-started/bg.png) for this project should be downloaded and placed in the same directory as `index.html`
Open `index.html` in your web browser to ensure that all assets are loading correctly. You should see the TodoMVC application with three hard-coded `<li>` elements where the text of each todo will appear.
### Additional Resources
* [Changes in this step in `diff` format](https://github.com/emberjs/quickstart-code-sample/commit/4d91f9fa1f6be4f4675b54babd3074550095c930)
* [TodoMVC stylesheet](http://emberjs.com.s3.amazonaws.com/getting-started/style.css)
* [TodoMVC background image](http://emberjs.com.s3.amazonaws.com/getting-started/bg.png)
## Obtaining Ember.js and Dependencies
TodoMVC has a few dependencies:
* [jQuery](http://code.jquery.com/jquery-1.10.2.min.js)
* [Handlebars](http://builds.handlebarsjs.com.s3.amazonaws.com/handlebars-1.0.0.js)
* [Ember.js 1.3](http://builds.emberjs.com/tags/v1.3.0/ember.js)
* [Ember Data 1.0 beta](http://builds.emberjs.com/tags/v1.0.0-beta.5/ember-data.js)
For this example, all of these resources should be stored in the folder `js/libs` located in the same location as `index.html`. Update your `index.html` to load these files by placing `<script>` tags just before your closing `</body>` tag in the following order:
```html
<!-- ... additional lines truncated for brevity ... -->
<script src="js/libs/jquery-1.10.2.min.js"></script>
<script src="js/libs/handlebars-1.0.0.js"></script>
<script src="js/libs/ember.js"></script>
<script src="js/libs/ember-data.js"></script>
</body>
<!-- ... additional lines truncated for brevity ... -->
```
Reload your web browser to ensure that all files have been referenced correctly and no errors occur.
If you are using a package manager, such as [bower](http://bower.io), make sure to checkout the [Getting Ember](/guides/getting-ember) guide for info on other ways to get Ember.js.
### Additional Resources
* [Changes in this step in `diff` format](https://github.com/emberjs/quickstart-code-sample/commit/0880d6e21b83d916a02fd17163f58686a37b5b2c)
## Adding the First Route and Template
Next, we will create an Ember.js application, a route ('`/`'), and convert our static mockup into a Handlebars template.
Inside your `js` directory, add a file for the application at `js/application.js` and a file for the router at `js/router.js`. You may place these files anywhere you like (even just putting all code into the same file), but this guide will assume you have separated them into their own files and named them as indicated.
Inside `js/application.js` add the following code:
```javascript
window.Todos = Ember.Application.create();
```
This will create a new instance of `Ember.Application` and make it available as a variable within your browser's JavaScript environment.
Inside `js/router.js` add the following code:
```javascript
Todos.Router.map(function() {
this.resource('todos', { path: '/' });
});
```
This will tell Ember.js to detect when the application's URL matches `'/'` and to render the `todos` template.
Next, update your `index.html` to wrap the inner contents of `<body>` in a Handlebars script tag and include `js/application.js` and `js/router.js` after Ember.js and other javascript dependencies:
```html
<!-- ... additional lines truncated for brevity ... -->
<body>
<script type="text/x-handlebars" data-template-name="todos">
<section id="todoapp">
... additional lines truncated for brevity ...
</section>
<footer id="info">
<p>Double-click to edit a todo</p>
</footer>
</script>
<!-- ... Ember.js and other javascript dependencies ... -->
<script src="js/application.js"></script>
<script src="js/router.js"></script>
</body>
<!-- ... additional lines truncated for brevity ... -->
```
Reload your web browser to ensure that all files have been referenced correctly and no errors occur.
### Additional Resources
* [Changes in this step in `diff` format](https://github.com/emberjs/quickstart-code-sample/commit/8775d1bf4c05eb82adf178be4429e5b868ac145b)
* [Handlebars Guide](/guides/templates/handlebars-basics)
* [Ember.Application Guide](/guides/application)
* [Ember.Application API Documentation](/api/classes/Ember.Application.html)
## Modeling Data
Next we will create a model class to describe todo items.
Create a file at `js/models/todo.js` and put the following code inside:
```javascript
Todos.Todo = DS.Model.extend({
title: DS.attr('string'),
isCompleted: DS.attr('boolean')
});
```
This code creates a new class `Todo` and places it within your application's namespace. Each todo will have two attributes: `title` and `isCompleted`.
You may place this file anywhere you like (even just putting all code into the same file), but this guide will assume you have created a file and named it as indicated.
Finally, update your `index.html` to include a reference to this new file:
```html
<!-- ... additional lines truncated for brevity ... -->
<script src="js/models/todo.js"></script>
</body>
<!-- ... additional lines truncated for brevity ... -->
```
Reload your web browser to ensure that all files have been referenced correctly and no errors occur.
### Additional Resources
* [Changes in this step in `diff` format](https://github.com/emberjs/quickstart-code-sample/commit/a1ccdb43df29d316a7729321764c00b8d850fcd1)
* [Models Guide](/guides/models)
## Using Fixtures
Now we'll add fixture data. Fixtures are a way to put sample data into an application before connecting the application to long-term persistence.
First, update `js/application.js` to indicate that your application's `ApplicationAdapter`
is an extension of the `DS.FixtureAdapter`. Adapters are responsible for communicating with a source of data for your application. Typically this will be a web service API, but in this case we are using an adapter designed to load fixture data:
```javascript
window.Todos = Ember.Application.create();
Todos.ApplicationAdapter = DS.FixtureAdapter.extend();
```
Next, update the file at `js/models/todo.js` to include the following fixture data:
```javascript
// ... additional lines truncated for brevity ...
Todos.Todo.FIXTURES = [
{
id: 1,
title: 'Learn Ember.js',
isCompleted: true
},
{
id: 2,
title: '...',
isCompleted: false
},
{
id: 3,
title: 'Profit!',
isCompleted: false
}
];
```
Reload your web browser to ensure that all files have been referenced correctly and no errors occur.
### Additional Resources
* [Changes in this step in `diff` format](https://github.com/emberjs/quickstart-code-sample/commit/a586fc9de92cad626ea816e9bb29445525678098)
## Displaying Model Data
Next we'll update our application to display dynamic todos, replacing our hard coded section in the `todos` template.
Inside the file `js/router.js` implement a `TodosRoute` class with a `model` function that returns all the existing todos:
```javascript
// ... additional lines truncated for brevity ...
Todos.TodosRoute = Ember.Route.extend({
model: function() {
return this.store.find('todo');
}
});
```
Because we hadn't implemented this class before, Ember.js provided a `Route` for us with the default behavior of rendering a matching template named `todos` using its [naming conventions for object creation](/guides/concepts/naming-conventions/).
Now that we need custom behavior (returning a specific set of models), we implement the class and add the desired behavior.
Update `index.html` to replace the static `<li>` elements with a Handlebars `{{each}}` helper and a dynamic `{{title}}` for each item.
```handlebars
<!--- ... additional lines truncated for brevity ... -->
<ul id="todo-list">
{{#each}}
<li>
<input type="checkbox" class="toggle">
<label>{{title}}</label><button class="destroy"></button>
</li>
{{/each}}
</ul>
<!--- ... additional lines truncated for brevity ... -->
```
The template loops over the content of its controller. This controller is an instance of `ArrayController` that Ember.js has provided for us as the container for our models. Because we don't need custom behavior for this object yet, we can use the default object provided by the framework.
Reload your web browser to ensure that all files have been referenced correctly and no errors occur.
### Additional Resources
* [Changes in this step in `diff` format](https://github.com/emberjs/quickstart-code-sample/commit/87bd57700110d9dd0b351c4d4855edf90baac3a8)
* [Templates Guide](/guides/templates/handlebars-basics)
* [Controllers Guide](/guides/controllers)
* [Naming Conventions Guide](/guides/concepts/naming-conventions)
## Displaying a Model's Complete State
TodoMVC strikes through completed todos by applying a CSS class `completed` to the `<li>` element. Update `index.html` to apply a CSS class to this element when a todo's `isCompleted` property is true:
```handlebars
<!--- ... additional lines truncated for brevity ... -->
<li {{bind-attr class="isCompleted:completed"}}>
<input type="checkbox" class="toggle">
<label>{{title}}</label><button class="destroy"></button>
</li>
<!--- ... additional lines truncated for brevity ... -->
```
This code will apply the CSS class `completed` when the todo's `isCompleted` property is `true` and remove it when the property becomes `false`.
The first fixture todo in our application has an `isCompleted` property of `true`. Reload the application to see the first todo is now decorated with a strike-through to visually indicate it has been completed.
### Additional Resources
* [Changes in this step in `diff` format](https://github.com/emberjs/quickstart-code-sample/commit/b15e5deffc41cf5ba4161808c7f46a283dc2277f)
* [bind-attr API documentation](/api/classes/Ember.Handlebars.helpers.html#method_bind-attr)
* [bind and bind-attr article by Peter Wagenet](http://www.emberist.com/2012/04/06/bind-and-bindattr.html)
## Creating a New Model Instance
Next we'll update our static HTML `<input>` to an Ember view that can expose more complex behaviors. Update `index.html` to replace the new todo `<input>` with a `{{input}}` helper:
```handlebars
<!--- ... additional lines truncated for brevity ... -->
<h1>todos</h1>
{{input type="text" id="new-todo" placeholder="What needs to be done?"
value=newTitle action="createTodo"}}
<!--- ... additional lines truncated for brevity ... -->
```
This will render an `<input>` element at this location with the same `id` and `placeholder` attributes applied. It will also connect the `newTitle` property of this template's controller to the `value` attribute of the `<input>`. When one changes, the other will automatically update to remain synchronized.
Additionally, we connect user interaction (pressing the `<enter>` key) to a method `createTodo` on this template's controller.
Because we have not needed a custom controller behavior until this point, Ember.js provided a default controller object for this template. To handle our new behavior, we can implement the controller class Ember.js expects to find [according to its naming conventions](/guides/concepts/naming-conventions) and add our custom behavior. This new controller class will automatically be associated with this template for us.
Add a `js/controllers/todos_controller.js` file. You may place this file anywhere you like (even just putting all code into the same file), but this guide will assume you have created the file and named it as indicated.
Inside `js/controllers/todos_controller.js` implement the controller Ember.js expects to find [according to its naming conventions](/guides/concepts/naming-conventions):
```javascript
Todos.TodosController = Ember.ArrayController.extend({
actions: {
createTodo: function() {
// Get the todo title set by the "New Todo" text field
var title = this.get('newTitle');
if (!title.trim()) { return; }
// Create the new Todo model
var todo = this.store.createRecord('todo', {
title: title,
isCompleted: false
});
// Clear the "New Todo" text field
this.set('newTitle', '');
// Save the new model
todo.save();
}
}
});
```
This controller will now respond to user action by using its `newTitle` property as the title of a new todo whose `isCompleted` property is false. Then it will clear its `newTitle` property which will synchronize to the template and reset the textfield. Finally, it persists any unsaved changes on the todo.
In `index.html` include `js/controllers/todos_controller.js` as a dependency:
```html
<!--- ... additional lines truncated for brevity ... -->
<script src="js/models/todo.js"></script>
<script src="js/controllers/todos_controller.js"></script>
</body>
<!--- ... additional lines truncated for brevity ... -->
```
Reload your web browser to ensure that all files have been referenced correctly and no errors occur. You should now be able to add additional todos by entering a title in the `<input>` and hitting the `<enter>` key.
### Additional Resources
* [Changes in this step in `diff` format](https://github.com/emberjs/quickstart-code-sample/commit/60feb5f369c8eecd9df3f561fbd01595353ce803)
* [Ember.TextField API documention](/api/classes/Ember.TextField.html)
* [Ember Controller Guide](/guides/controllers)
* [Naming Conventions Guide](/guides/concepts/naming-conventions)
## Marking a Model as Complete or Incomplete
In this step we'll update our application to allow a user to mark a todo as complete or incomplete and persist the updated information.
In `index.html` update your template to wrap each todo in its own controller by adding an `itemController` argument to the `{{each}}` Handlebars helper. Then convert our static `<input type="checkbox">` into a `{{input}}` helper:
```handlebars
<!--- ... additional lines truncated for brevity ... -->
{{#each itemController="todo"}}
<li {{bind-attr class="isCompleted:completed"}}>
{{input type="checkbox" checked=isCompleted class="toggle"}}
<label>{{title}}</label><button class="destroy"></button>
</li>
{{/each}}
<!--- ... additional lines truncated for brevity ... -->
```
When this `{{input}}` is rendered it will ask for the current value of the controller's `isCompleted` property. When a user clicks this input, it will set the value of the controller's `isCompleted` property to either `true` or `false` depending on the new checked value of the input.
Implement the controller for each todo by matching the name used as the `itemController` value to a class in your application `Todos.TodoController`. Create a new file at `js/controllers/todo_controller.js` for this code. You may place this file anywhere you like (even just putting all code into the same file), but this guide will assume you have created the file and named it as indicated.
Inside `js/controllers/todo_controller.js` add code for `Todos.TodoController` and its `isCompleted` property:
```javascript
Todos.TodoController = Ember.ObjectController.extend({
isCompleted: function(key, value){
var model = this.get('model');
if (value === undefined) {
// property being used as a getter
return model.get('isCompleted');
} else {
// property being used as a setter
model.set('isCompleted', value);
model.save();
return value;
}
}.property('model.isCompleted')
});
```
When called from the template to display the current `isCompleted` state of the todo, this property will proxy that question to its underlying `model`. When called with a value because a user has toggled the checkbox in the template, this property will set the `isCompleted` property of its `model` to the passed value (`true` or `false`), persist the model update, and return the passed value so the checkbox will display correctly.
The `isCompleted` function is marked a [computed property](/guides/object-model/computed-properties/) whose value is dependent on the value of `model.isCompleted`.
In `index.html` include `js/controllers/todo_controller.js` as a dependency:
```html
<!--- ... additional lines truncated for brevity ... -->
<script src="js/models/todo.js"></script>
<script src="js/controllers/todos_controller.js"></script>
<script src="js/controllers/todo_controller.js"></script>
</body>
<!--- ... additional lines truncated for brevity ... -->
```
Reload your web browser to ensure that all files have been referenced correctly and no errors occur. You should now be able to change the `isCompleted` property of a todo.
### Additional Resources
* [Changes in this step in `diff` format](https://github.com/emberjs/quickstart-code-sample/commit/8d469c04c237f39a58903a3856409a2592cc18a9)
* [Ember.Checkbox API documentation](/api/classes/Ember.Checkbox.html)
* [Ember Controller Guide](/guides/controllers)
* [Computed Properties Guide](/guides/object-model/computed-properties/)
* [Naming Conventions Guide](/guides/concepts/naming-conventions)
## Displaying the Number of Incomplete Todos
Next we'll update our template's hard-coded count of completed todos to reflect the actual number of completed todos. Update `index.html` to use two properties:
```handlebars
<!--- ... additional lines truncated for brevity ... -->
<span id="todo-count">
<strong>{{remaining}}</strong> {{inflection}} left
</span>
<!--- ... additional lines truncated for brevity ... -->
```
Implement these properties as part of this template's controller, the `Todos.TodosController`:
```javascript
// ... additional lines truncated for brevity ...
actions: {
// ... additional lines truncated for brevity ...
},
remaining: function() {
return this.filterBy('isCompleted', false).get('length');
}.property('@each.isCompleted'),
inflection: function() {
var remaining = this.get('remaining');
return remaining === 1 ? 'item' : 'items';
}.property('remaining')
// ... additional lines truncated for brevity ...
```
The `remaining` property will return the number of todos whose `isCompleted` property is false. If the `isCompleted` value of any todo changes, this property will be recomputed. If the value has changed, the section of the template displaying the count will be automatically updated to reflect the new value.
The `inflection` property will return either a plural or singular version of the word "item" depending on how many todos are currently in the list. The section of the template displaying the count will be automatically updated to reflect the new value.
Reload your web browser to ensure that no errors occur. You should now see an accurate number for remaining todos.
### Additional Resources
* [Changes in this step in `diff` format](https://github.com/emberjs/quickstart-code-sample/commit/b418407ed9666714c82d894d6b70f785674f7a45)
* [Computed Properties Guide](/guides/object-model/computed-properties/)
## Toggling between Showing and Editing States
TodoMVC allows users to double click each todo to display a text `<input>` element where the todo's title can be updated. Additionally the `<li>` element for each todo obtains the CSS class `editing` for style and positioning.
We'll update the application to allow users to toggle into this editing state for a todo. In `index.html` update the contents of the `{{each}}` Handlebars helper to:
```handlebars
<!--- ... additional lines truncated for brevity ... -->
{{#each itemController="todo"}}
<li {{bind-attr class="isCompleted:completed isEditing:editing"}}>
{{#if isEditing}}
<input class="edit">
{{else}}
{{input type="checkbox" checked=isCompleted class="toggle"}}
<label {{action "editTodo" on="doubleClick"}}>{{title}}</label><button class="destroy"></button>
{{/if}}
</li>
{{/each}}
<!--- ... additional lines truncated for brevity ... -->
```
The above code applies three new behaviors to our application: it applies the CSS class `editing` when the controller's `isEditing` property is true and removes it when the `isEditing` property is false. We add a new `{{action}}` helper to the `<label>` so double-clicks will call `editTodo` on
this todo's controller. Finally, we wrap our todo in a Handlebars `{{if}}` helper so a text `<input>` will display when we are editing and the todos title will display when we are not editing.
Inside `js/controllers/todo_controller.js` we'll implement the matching logic for this template behavior:
```javascript
// ... additional lines truncated for brevity ...
actions: {
editTodo: function() {
this.set('isEditing', true);
}
},
isEditing: false,
// ... additional lines truncated for brevity ...
```
Above we defined an initial `isEditing` value of `false` for controllers of this type and said that when the `editTodo` action is called it should set the `isEditing` property of this controller to `true`. This will automatically trigger the sections of template that use `isEditing` to update their rendered content.
Reload your web browser to ensure that no errors occur. You can now double-click a todo to edit it.
### Additional Resources
* [Changes in this step in `diff` format](https://github.com/emberjs/quickstart-code-sample/commit/616bc4f22900bbaa2bf9bdb8de53ba41209d8cc0)
* [Handlebars Conditionals Guide](/guides/templates/conditionals)
* [bind-attr API documentation](/api/classes/Ember.Handlebars.helpers.html#method_bind-attr)
* [action API documentation](/api/classes/Ember.Handlebars.helpers.html#method_action)
* [bind and bindAttr article by Peter Wagenet](http://www.emberist.com/2012/04/06/bind-and-bindattr.html)
## Accepting Edits
In the previous step we updated TodoMVC to allow a user to toggle the display of a text `<input>` for editing a todo's title. Next, we'll add the behavior that immediately focuses the `<input>` when it appears, accepts user input and, when the user presses the `<enter>` key or moves focus away from the editing `<input>` element, persists these changes, then redisplays the todo with its newly updated text.
To accomplish this, we'll create a new custom component and register it with Handlebars to make it available to our templates.
Create a new file `js/views/edit_todo_view.js`. You may place this file anywhere you like (even just putting all code into the same file), but this guide will assume you have created the file and named it as indicated.
In `js/views/edit_todo_view.js` create an extension of `Ember.TextField`:
```javascript
Todos.EditTodoView = Ember.TextField.extend({
didInsertElement: function() {
this.$().focus();
}
});
Ember.Handlebars.helper('edit-todo', Todos.EditTodoView);
```
In `index.html` require this new file:
```html
<!--- ... additional lines truncated for brevity ... -->
<script src="js/controllers/todo_controller.js"></script>
<script src="js/views/edit_todo_view.js"></script>
</body>
<!--- ... additional lines truncated for brevity ... -->
```
In `index.html` replace the static `<input>` element with our custom `{{edit-todo}}` component, connecting the `value` property, and actions:
```handlebars
<!--- ... additional lines truncated for brevity ... -->
{{#if isEditing}}
{{edit-todo class="edit" value=title focus-out="acceptChanges"
insert-newline="acceptChanges"}}
{{else}}
<!--- ... additional lines truncated for brevity ... -->
```
Pressing the `<enter>` key will trigger the `acceptChanges` event on the instance of `TodoController`. Moving focus away from the `<input>` will trigger the `focus-out` event, calling a method `acceptChanges` on this view's instance of `TodoController`.
Additionally, we connect the `value` property of this `<input>` to the `title` property of this instance of `TodoController`. We will not implement a `title` property on the controller so it will retain the default behavior of [proxying all requests](../controllers/#toc_representing-models) to its `model`.
A CSS class `edit` is applied for styling.
In `js/controllers/todo_controller.js`, add the method `acceptChanges` that we called from `EditTodoView`:
```javascript
// ... additional lines truncated for brevity ...
actions: {
editTodo: function() {
this.set('isEditing', true);
},
acceptChanges: function() {
this.set('isEditing', false);
if (Ember.isEmpty(this.get('model.title'))) {
this.send('removeTodo');
} else {
this.get('model').save();
}
}
},
// ... additional lines truncated for brevity ...
```
This method will set the controller's `isEditing` property to false and commit all changes made to the todo.
### Additional Resources
* [Changes in this step in `diff` format](https://github.com/emberjs/quickstart-code-sample/commit/a7e2f40da4d75342358acdfcbda7a05ccc90f348)
* [Controller Guide](/guides/controllers)
* [Ember.TextField API documentation](/api/classes/Ember.TextField.html)
## Deleting a Model
TodoMVC displays a button for removing todos next to each todo when its `<li>` is hovered. Clicking this button will remove the todo and update the display of remaining incomplete todos and remaining completed todos appropriately.
In `index.html` update the static `<button>` element to include an `{{action}}` Handlebars helper:
```handlebars
<!--- ... additional lines truncated for brevity ... -->
<button {{action "removeTodo"}} class="destroy"></button>
<!--- ... additional lines truncated for brevity ... -->
```
In `js/controllers/todo_controller.js` implement the `removeTodo` method referenced in the template's `{{action}}` Handlebars helper:
```javascript
// ... additional lines truncated for brevity ...
actions: {
// ... additional lines truncated for brevity ...
removeTodo: function() {
var todo = this.get('model');
todo.deleteRecord();
todo.save();
},
}
// ... additional lines truncated for brevity ...
```
This method will delete the todo locally and then persist this data change.
Because the todo is no longer part of the collection of all todos, its `<li>` element in the page will be automatically removed for us. If the deleted todo was incomplete, the count of remaining todos will be decreased by one and the display of this number will be automatically re-rendered. If the new count results in an inflection change between "item" and "items" this area of the page will be automatically re-rendered.
Reload your web browser to ensure that there are no errors and the behaviors described above occurs.
### Additional Resources
* [Changes in this step in `diff` format](https://github.com/emberjs/quickstart-code-sample/commit/14e1f129f76bae8f8ea6a73de1e24d810678a8fe)
* [action API documention](/api/classes/Ember.Handlebars.helpers.html#method_action)
## Adding Child Routes
Next we will split our single template into a set of nested templates so we can transition between different lists of todos in reaction to user interaction.
In `index.html` move the entire `<ul>` of todos into a new template named `todos/index` by adding a new Handlebars template `<script>` tag inside the `<body>` of the document:
```html
<!--- ... additional lines truncated for brevity ... -->
<script type="text/x-handlebars" data-template-name="todos/index">
<ul id="todo-list">
{{#each itemController="todo"}}
<li {{bind-attr class="isCompleted:completed isEditing:editing"}}>
{{#if isEditing}}
{{edit-todo class="edit" value=title focus-out="acceptChanges" insert-newline="acceptChanges"}}
{{else}}
{{input type="checkbox" checked=isCompleted class="toggle"}}
<label {{action "editTodo" on="doubleClick"}}>{{title}}</label><button {{action "removeTodo"}} class="destroy"></button>
{{/if}}
</li>
{{/each}}
</ul>
</script>
<!--- ... additional lines truncated for brevity ... -->
```
Still within `index.html` place a Handlebars `{{outlet}}` helper where the `<ul>` was previously:
```handlebars
<!--- ... additional lines truncated for brevity ... -->
<section id="main">
{{outlet}}
<input type="checkbox" id="toggle-all">
</section>
<!--- ... additional lines truncated for brevity ... -->
```
The `{{outlet}}` Handlebars helper designates an area of a template that will dynamically update as we transition between routes. Our first new child route will fill this area with the list of all todos in the application.
In `js/router.js` update the router to change the `todos` mapping, with an additional empty function parameter so it can accept child routes, and add this first `index` route:
```javascript
Todos.Router.map(function () {
this.resource('todos', { path: '/' }, function () {
// additional child routes will go here later
});
});
// ... additional lines truncated for brevity ...
Todos.TodosIndexRoute = Ember.Route.extend({
model: function() {
return this.modelFor('todos');
}
});
```
When the application loads at the url `'/'` Ember.js will enter the `todos` route and render the `todos` template as before. It will also transition into the `todos.index` route and fill the `{{outlet}}` in the `todos` template with the `todos/index` template. The model data for this template is the result of the `model` method of `TodosIndexRoute`, which indicates that the
model for this route is the same model as for the `TodosRoute`.
This mapping is described in more detail in the [Naming Conventions Guide](/guides/concepts/naming-conventions).
### Additional Resources
* [Changes in this step in `diff` format](https://github.com/emberjs/quickstart-code-sample/commit/3bab8f1519ffc1ca2d5a12d1de35e4c764c91f05)
* [Ember Router Guide](/guides/routing)
* [Ember Controller Guide](/guides/controllers)
* [outlet API documentation](/api/classes/Ember.Handlebars.helpers.html#method_outlet)
## Transitioning to Show Only Incomplete Todos
Next we'll update the application so a user can navigate to a url where only todos that are not complete are displayed.
In `index.html` convert the `<a>` tag for 'Active' todos into a Handlebars `{{link-to}}` helper:
```handlebars
<!--- ... additional lines truncated for brevity ... -->
<li>
<a href="all">All</a>
</li>
<li>
{{#link-to "todos.active" activeClass="selected"}}Active{{/link-to}}
</li>
<li>
<a href="completed">Completed</a>
</li>
<!--- ... additional lines truncated for brevity ... -->
```
In `js/router.js` update the router to recognize this new path and implement a matching route:
```javascript
Todos.Router.map(function() {
this.resource('todos', { path: '/' }, function() {
// additional child routes
this.route('active');
});
});
// ... additional lines truncated for brevity ...
Todos.TodosActiveRoute = Ember.Route.extend({
model: function(){
return this.store.filter('todo', function(todo) {
return !todo.get('isCompleted');
});
},
renderTemplate: function(controller) {
this.render('todos/index', {controller: controller});
}
});
```
The model data for this route is the collection of todos whose `isCompleted` property is `false`. When a todo's `isCompleted` property changes this collection will automatically update to add or remove the todo appropriately.
Normally transitioning into a new route changes the template rendered into the parent `{{outlet}}`, but in this case we'd like to reuse the existing `todos/index` template. We can accomplish this by implementing the `renderTemplate` method and calling `render` ourselves with the specific template and controller options.
Reload your web browser to ensure that there are no errors and the behavior described above occurs.
### Additional Resources
* [Changes in this step in `diff` format](https://github.com/emberjs/quickstart-code-sample/commit/2a1d35293a52e40d0125f552a1a8b2c01f759313)
* [link-to API documentation](/api/classes/Ember.Handlebars.helpers.html#method_link-to)
* [Route#renderTemplate API documentation](/api/classes/Ember.Route.html#method_renderTemplate)
* [Route#render API documentation](/api/classes/Ember.Route.html#method_render)
* [Ember Router Guide](/guides/routing)
## Transitioning to Show Only Complete Todos
Next we'll update the application so a user can navigate to a url where only todos that have already been completed are displayed.
In `index.html` convert the `<a>` tag for 'Completed' todos into a Handlebars `{{link-to}}` helper:
```handlebars
<!--- ... additional lines truncated for brevity ... -->
<li>
<a href="all">All</a>
</li>
<li>
{{#link-to "todos.active" activeClass="selected"}}Active{{/link-to}}
</li>
<li>
{{#link-to "todos.completed" activeClass="selected"}}Completed{{/link-to}}
</li>
<!--- ... additional lines truncated for brevity ... -->
```
In `js/router.js` update the router to recognize this new path and implement a matching route:
```javascript
Todos.Router.map(function() {
this.resource('todos', { path: '/' }, function() {
// additional child routes
this.route('active');
this.route('completed');
});
});
// ... additional lines truncated for brevity ...
Todos.TodosCompletedRoute = Ember.Route.extend({
model: function() {
return this.store.filter('todo', function(todo) {
return todo.get('isCompleted');
});
},
renderTemplate: function(controller) {
this.render('todos/index', {controller: controller});
}
});
```
The model data for this route is the collection of todos whose `isCompleted` property is `true`. When a todo's `isCompleted` property changes this collection will automatically update to add or remove the todo appropriately.
Normally transitioning into a new route changes the template rendered into the parent `{{outlet}}`, but in this case we'd like to reuse the existing `todos/index` template. We can accomplish this by implementing the `renderTemplate` method and calling `render` ourselves with the specific template and controller options.
Reload your web browser to ensure that there are no errors and the behavior described above occurs.
### Additional Resources
* [Changes in this step in `diff` format](https://github.com/emberjs/quickstart-code-sample/commit/bba939a11197552e3a927bcb3a3adb9430e4f331)
* [link-to API documentation](/api/classes/Ember.Handlebars.helpers.html#method_link-to)
* [Route#renderTemplate API documentation](/api/classes/Ember.Route.html#method_renderTemplate)
* [Route#render API documentation](/api/classes/Ember.Route.html#method_render)
* [Ember Router Guide](/guides/routing)
## Transitioning back to Show All Todos
Next we can update the application to allow navigating back to the list of all todos.
In `index.html` convert the `<a>` tag for 'All' todos into a Handlebars `{{link-to}}` helper:
```handlebars
<!--- ... additional lines truncated for brevity ... -->
<li>
{{#link-to "todos.index" activeClass="selected"}}All{{/link-to}}
</li>
<li>
{{#link-to "todos.active" activeClass="selected"}}Active{{/link-to}}
</li>
<li>
{{#link-to "todos.completed" activeClass="selected"}}Completed{{/link-to}}
</li>
<!--- ... additional lines truncated for brevity ... -->
```
Reload your web browser to ensure that there are no errors. You should be able to navigate between urls for all, active, and completed todos.
### Additional Resources
* [Changes in this step in `diff` format](https://github.com/emberjs/quickstart-code-sample/commit/843ff914873081560e4ba97df0237b8595b6ae51)
* [link-to API documentation](/api/classes/Ember.Handlebars.helpers.html#method_link-to)
## Displaying a Button to Remove All Completed Todos
TodoMVC allows users to delete all completed todos at once by clicking a button. This button is visible only when there are any completed todos, displays the number of completed todos, and removes all completed todos from the application when clicked.
In this step, we'll implement that behavior. In `index.html` update the static `<button>` for clearing all completed todos:
```handlebars
<!--- ... additional lines truncated for brevity ... -->
{{#if hasCompleted}}
<button id="clear-completed" {{action "clearCompleted"}}>
Clear completed ({{completed}})
</button>
{{/if}}
<!--- ... additional lines truncated for brevity ... -->
```
In `js/controllers/todos_controller.js` implement the matching properties and a method that will clear completed todos and persist these changes when the button is clicked:
```javascript
// ... additional lines truncated for brevity ...
actions: {
clearCompleted: function() {
var completed = this.filterBy('isCompleted', true);
completed.invoke('deleteRecord');
completed.invoke('save');
},
// ... additional lines truncated for brevity ...
},
hasCompleted: function() {
return this.get('completed') > 0;
}.property('completed'),
completed: function() {
return this.filterBy('isCompleted', true).get('length');
}.property('@each.isCompleted'),
// ... additional lines truncated for brevity ...
```
The `completed` and `clearCompleted` methods both invoke the `filterBy` method, which is part of the [ArrayController](http://emberjs.com/api/classes/Ember.ArrayController.html#method_filterProperty) API and returns an instance of [EmberArray](http://emberjs.com/api/classes/Ember.Array.html) which contains only the items for which the callback returns true. The `clearCompleted` method also invokes the `invoke` method which is part of the [EmberArray](http://emberjs.com/api/classes/Ember.Array.html#method_invoke) API. `invoke` will execute a method on each object in the Array if the method exists on that object.
Reload your web browser to ensure that there are no errors and the behavior described above occurs.
### Additional Resources
* [Changes in this step in `diff` format](https://github.com/emberjs/quickstart-code-sample/commit/1da450a8d693f083873a086d0d21e031ee3c129e)
* [Handlebars Conditionals Guide](/guides/templates/conditionals)
* [Enumerables Guide](/guides/enumerables)
## Indicating When All Todos Are Complete
Next we'll update our template to indicate when all todos have been completed. In `index.html` replace the static checkbox `<input>` with an `{{input}}`:
```handlebars
<!--- ... additional lines truncated for brevity ... -->
<section id="main">
{{outlet}}
{{input type="checkbox" id="toggle-all" checked=allAreDone}}
</section>
<!--- ... additional lines truncated for brevity ... -->
```
This checkbox will be checked when the controller property `allAreDone` is `true` and unchecked when the property `allAreDone` is `false`.
In `js/controllers/todos_controller.js` implement the matching `allAreDone` property:
```javascript
// ... additional lines truncated for brevity ...
allAreDone: function(key, value) {
return !!this.get('length') && this.everyProperty('isCompleted', true);
}.property('@each.isCompleted')
// ... additional lines truncated for brevity ...
```
This property will be `true` if the controller has any todos and every todo's `isCompleted` property is true. If the `isCompleted` property of any todo changes, this property will be recomputed. If the return value has changed, sections of the template that need to update will be automatically updated for us.
Reload your web browser to ensure that there are no errors and the behavior described above occurs.
### Additional Resources
* [Changes in this step in `diff` format](https://github.com/emberjs/quickstart-code-sample/commit/9bf8a430bc4afb06f31be55f63f1d9806e6ab01c)
* [Ember.Checkbox API documentation](/api/classes/Ember.Checkbox.html)
## Toggling All Todos Between Complete and Incomplete
TodoMVC allows users to toggle all existing todos into either a complete or incomplete state. It uses the same checkbox that becomes checked when all todos are completed and unchecked when one or more todos remain incomplete.
To implement this behavior update the `allAreDone` property in `js/controllers/todos_controller.js` to handle both getting and setting behavior:
```javascript
// ... additional lines truncated for brevity ...
allAreDone: function(key, value) {
if (value === undefined) {
return !!this.get('length') && this.everyProperty('isCompleted', true);
} else {
this.setEach('isCompleted', value);
this.invoke('save');
return value;
}
}.property('@each.isCompleted')
// ... additional lines truncated for brevity ...
```
If no `value` argument is passed this property is being used to populate the current value of the checkbox. If a `value` is passed it indicates the checkbox was used by a user and we should set the `isCompleted` property of each todo to this new value.
The count of remaining todos and completed todos used elsewhere in the template automatically re-render for us if necessary.
Reload your web browser to ensure that there are no errors and the behavior described above occurs.
### Additional Resources
* [Changes in this step in `diff` format](https://github.com/emberjs/quickstart-code-sample/commit/47b289bb9f669edaa39abd971f5e884142988663)
* [Ember.Checkbox API documentation](/api/classes/Ember.Checkbox.html)
* [Computed Properties Guide](/guides/object-model/computed-properties/)
## Replacing the Fixture Adapter with Another Adapter
Finally we'll replace our fixture data with real persistence so todos will remain between application loads by replacing the fixture adapter with a `localstorage`-aware adapter instead.
Change `js/application.js` to:
```javascript
window.Todos = Ember.Application.create();
Todos.ApplicationAdapter = DS.LSAdapter.extend({
namespace: 'todos-emberjs'
});
```
The local storage adapter, written by Ryan Florence, can be downloaded [from its source](https://raw.github.com/rpflorence/ember-localstorage-adapter/master/localstorage_adapter.js). Add it to your project as `js/libs/localstorage_adapter.js`. You may place this file anywhere you like (even just putting all code into the same file), but this guide will assume you have created the file and named it as indicated.
In `index.html` include `js/libs/localstorage_adapter.js` as a dependency:
```html
<!--- ... additional lines truncated for brevity ... -->
<script src="js/libs/ember-data.js"></script>
<script src="js/libs/localstorage_adapter.js"></script>
<script src="js/application.js"></script>
<!--- ... additional lines truncated for brevity ... -->
```
Reload your application. Todos you manage will now persist after the application has been closed.
### Additional Resources
* [Changes in this step in `diff` format](https://github.com/emberjs/quickstart-code-sample/commit/81801d87da42d0c83685ff946c46de68589ce38f)
* [LocalStorage Adapter on GitHub](https://github.com/rpflorence/ember-localstorage-adapter)
# Getting Ember
##Ember Builds
The Ember Release Management Team maintains a variety of ways to get Ember and Ember Data builds.
###Channels
The latest [Release](/builds#/release), [Beta](/builds#/beta), and [Canary](/builds#/canary) builds of Ember and Ember data can be found [here](/builds). For each channel a development, minified, and production version is available. For more on the different channels read the [Post 1.0 Release Cycle](http://emberjs.com/blog/2013/09/06/new-ember-release-process.html) blog post.
###Tagged Releases
Past release and beta builds of Ember and Ember Data are available at [Tagged Releases](/builds#/tagged). These builds can be useful to track down regressions in your application, but it is recommended to use the latest stable release in production.
##Bower
Bower is a package manager for the web. Bower makes it easy to manage dependencies in your application including Ember and Ember Data. To learn more about Bower vist [http://bower.io/](http://bower.io/).
Adding Ember to your application with Bower is easy simply run `bower install ember --save`. For Ember Data run `bower install ember-data --save`. You can also add `ember` or `ember-data` to your `bower.json` file as follows.
```json
{
"name": "your-app",
"dependencies": {
"ember": "~1.2",
"ember-data": "~1.0.0-beta.4"
}
}
```
##RubyGems
If your application uses a Ruby based build system you can use the [ember-source](http://rubygems.org/gems/ember-source) and [ember-data-source](http://rubygems.org/gems/ember-data-source) RubyGems to access ember and ember data sources from Ruby.
If your application is built in rails the [ember-rails](http://rubygems.org/gems/ember-rails) RubyGem makes it easy to integrate Ember into your Ruby on Rails application.
# Concepts
## Core Concepts
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][1] [router's][2] [hooks][3] 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.
[1]: /guides/routing/specifying-a-routes-model
[2]: /guides/routing/setting-up-a-controller
[3]: /guides/routing/rendering-a-template
Here's a simple example that uses a route, controller, and template:
```javascript
App.ApplicationRoute = Ember.Route.extend({
setupController: function(controller) {
// `controller` is the instance of ApplicationController
controller.set('title', "Hello world!");
}
});
App.ApplicationController = Ember.Controller.extend({
appName: 'My First Example'
});
```
```handlebars
<!-- application template -->
<h1>{{appName}}</h1>
<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:
```javascript
App.Router.map(function() {
this.route('favorites');
});
```
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:
```javascript
App.FavoritesRoute = Ember.Route.extend({
model: function() {
// the model is an Array of all of the posts
return this.store.find('post');
}
});
```
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:
```handlebars
<ul>
{{#each controller}}
<li>{{title}}</li>
{{/each}}
</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:
```javascript
App.Router.map(function() {
this.resource('post', { path: '/posts/:post_id' });
});
```
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).
```javascript
App.PostRoute = Ember.Route.extend({
model: function(params) {
return this.store.find('post', params.post_id);
},
serialize: function(post) {
return { post_id: post.get('id') };
}
});
```
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`.
```javascript
App.Router.map(function() {
this.resource('posts', function() { // the `posts` route
this.route('favorites'); // the `posts.favorites` route
this.resource('post'); // the `post` route
});
});
```
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:
<table>
<thead>
<tr>
<th>Route Name</th>
<th>Controller</th>
<th>Route</th>
<th>Template</th>
</tr>
</thead>
<tr>
<td><code>posts</code></td>
<td><code>PostsController</code></td>
<td><code>PostsRoute</code></td>
<td><code>posts</code></td>
</tr>
<tr>
<td><code>posts.favorites</code></td>
<td><code>PostsFavoritesController</code></td>
<td><code>PostsFavoritesRoute</code></td>
<td><code>posts/favorites</code></td>
</tr>
<tr>
<td><code>post</code></td>
<td><code>PostController</code></td>
<td><code>PostRoute</code></td>
<td><code>post</code></td>
</tr>
</table>
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:
```javascript
App.Router.map(function() {
this.route('favorites');
});
```
It is the equivalent of:
```javascript
App.Router.map(function() {
this.route('index', { path: '/' });
this.route('favorites');
});
```
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:
```javascript
App.Router.map(function() {
this.resource('posts', function() {
this.route('favorites');
});
});
```
Is the equivalent of:
```javascript
App.Router.map(function() {
this.route('index', { path: '/' });
this.resource('posts', function() {
this.route('index', { path: '/' });
this.route('favorites');
});
});
```
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.
# The Object Model
## Classes and Instances
To define a new Ember _class_, call the `extend()` method on
`Ember.Object`:
```javascript
App.Person = Ember.Object.extend({
say: function(thing) {
alert(thing);
}
});
```
This defines a new `App.Person` class with a `say()` method.
You can also create a _subclass_ from any existing class by calling
its `extend()` method. For example, you might want to create a subclass
of Ember's built-in `Ember.View` class:
```js
App.PersonView = Ember.View.extend({
tagName: 'li',
classNameBindings: ['isAdministrator']
});
```
When defining a subclass, you can override methods but still access the
implementation of your parent class by calling the special `_super()`
method:
```javascript
App.Person = Ember.Object.extend({
say: function(thing) {
var name = this.get('name');
alert(name + " says: " + thing);
}
});
App.Soldier = App.Person.extend({
say: function(thing) {
this._super(thing + ", sir!");
}
});
var yehuda = App.Soldier.create({
name: "Yehuda Katz"
});
yehuda.say("Yes"); // alerts "Yehuda Katz says: Yes, sir!"
```
### Creating Instances
Once you have defined a class, you can create new _instances_ of that
class by calling its `create()` method. Any methods, properties and
computed properties you defined on the class will be available to
instances:
```javascript
var person = App.Person.create();
person.say("Hello"); // alerts " says: Hello"
```
When creating an instance, you can initialize the value of its properties
by passing an optional hash to the `create()` method:
```javascript
App.Person = Ember.Object.extend({
helloWorld: function() {
alert("Hi, my name is " + this.get('name'));
}
});
var tom = App.Person.create({
name: "Tom Dale"
});
tom.helloWorld(); // alerts "Hi my name is Tom Dale"
```
For performance reasons, note that you cannot redefine an instance's
computed properties or methods when calling `create()`, nor can you
define new ones. You should only set simple properties when calling
`create()`. If you need to define or redefine methods or computed
properties, create a new subclass and instantiate that.
By convention, properties or variables that hold classes are
PascalCased, while instances are not. So, for example, the variable
`App.Person` would point to a class, while `person` would point to an instance
(usually of the `App.Person` class). You should stick to these naming
conventions in your Ember applications.
### Initializing Instances
When a new instance is created, its `init` method is invoked
automatically. This is the ideal place to do setup required on new
instances:
```js
App.Person = Ember.Object.extend({
init: function() {
var name = this.get('name');
alert(name + ", reporting for duty!");
}
});
App.Person.create({
name: "Stefan Penner"
});
// alerts "Stefan Penner, reporting for duty!"
```
If you are subclassing a framework class, like `Ember.View` or
`Ember.ArrayController`, and you override the `init` method, make sure
you call `this._super()`! If you don't, the system may not have an
opportunity to do important setup work, and you'll see strange behavior
in your application.
When accessing the properties of an object, use the `get`
and `set` accessor methods:
```js
var person = App.Person.create();
var name = person.get('name');
person.set('name', "Tobias Fünke");
```
Make sure to use these accessor methods; otherwise, computed properties won't
recalculate, observers won't fire, and templates won't update.
## Computed Properties
## What are Computed Properties?
In a nutshell, computed properties let you declare functions as properties. You create one by defining a computed property as a function, which Ember will automatically call when you ask for the property. You can then use it the same way you would any normal, static property.
It's super handy for taking one or more normal properties and transforming or manipulating their data to create a new value.
### Computed properties in action
We'll start with a simple example:
```javascript
App.Person = Ember.Object.extend({
// these will be supplied by `create`
firstName: null,
lastName: null,
fullName: function() {
return this.get('firstName') + ' ' + this.get('lastName');
}.property('firstName', 'lastName')
});
var ironMan = App.Person.create({
firstName: "Tony",
lastName: "Stark"
});
ironMan.get('fullName') // "Tony Stark"
```
Notice that the `fullName` function calls `property`. This declares the function to be a computed property, and the arguments tell Ember that it depends on the `firstName` and `lastName` attributes.
Whenever you access the `fullName` property, this function gets called, and it returns the value of the function, which simply calls `firstName` + `lastName`.
### Chaining computed properties
You can use computed properties as values to create new computed properties. Let's add a `description` computed property to the previous example, and use the existing `fullName` property and add in some other properties:
```javascript
App.Person = Ember.Object.extend({
firstName: null,
lastName: null,
age: null,
country: null,
fullName: function() {
return this.get('firstName') + ' ' + this.get('lastName');
}.property('firstName', 'lastName'),
description: function() {
return this.get('fullName') + '; Age: ' + this.get('age') + '; Country: ' + this.get('country');
}.property('fullName', 'age', 'country')
});
var captainAmerica = App.Person.create({
firstName: 'Steve',
lastName: 'Rogers',
age: 80,
country: 'USA'
});
captainAmerica.get('description'); // "Steve Rogers; Age: 80; Country: USA"
```
### Dynamic updating
Computed properties, by default, observe any changes made to the properties they depend on and are dynamically updated when they're called. Let's use computed properties to dynamically update.
```javascript
captainAmerica.set('firstName', 'William');
captainAmerica.get('description'); // "William Rogers; Age: 80; Country: USA"
```
So this change to `firstName` was observed by `fullName` computed property, which was itself observed by the `description` property.
Setting any dependent property will propagate changes through any computed properties that depend on them, all the way down the chain of computed properties you've created.
### Setting Computed Properties
You can also define what Ember should do when setting a computed property. If you try to set a computed property, it will be invoked with the key (property name), the value you want to set it to, and the previous value.
```javascript
App.Person = Ember.Object.extend({
firstName: null,
lastName: null,
fullName: function(key, value) {
// setter
if (arguments.length > 1) {
var nameParts = value.split(/\s+/);
this.set('firstName', nameParts[0]);
this.set('lastName', nameParts[1]);
}
// getter
return this.get('firstName') + ' ' + this.get('lastName');
}.property('firstName', 'lastName')
});
var captainAmerica = App.Person.create();
captainAmerica.set('fullName', "William Burnside");
captainAmerica.get('firstName'); // William
captainAmerica.get('lastName'); // Burnside
```
Ember will call the computed property for both setters and getters, so if you want to use a computed property as a setter, you'll need to check the number of arguments to determine whether it is being called as a getter or a setter. Note that if a value is returned from the setter, it will be cached as the property’s value.
## Computed Properties and Aggregate Data with @each
Often, you may have a computed property that relies on all of the items in an
array to determine its value. For example, you may want to count all of the
todo items in a controller to determine how many of them are completed.
Here's what that computed property might look like:
```javascript
App.TodosController = Ember.Controller.extend({
todos: [
Ember.Object.create({ isDone: false })
],
remaining: function() {
var todos = this.get('todos');
return todos.filterBy('isDone', false).get('length');
}.property('[email protected]')
});
```
Note here that the dependent key (`[email protected]`) contains the special
key `@each`. This instructs Ember.js to update bindings and fire observers for
this computed property when one of the following four events occurs:
1. The `isDone` property of any of the objects in the `todos` array changes.
2. An item is added to the `todos` array.
3. An item is removed from the `todos` array.
4. The `todos` property of the controller is changed to a different array.
In the example above, the `remaining` count is `1`:
```javascript
App.todosController = App.TodosController.create();
App.todosController.get('remaining');
// 1
```
If we change the todo's `isDone` property, the `remaining` property is updated
automatically:
```javascript
var todos = App.todosController.get('todos');
var todo = todos.objectAt(0);
todo.set('isDone', true);
App.todosController.get('remaining');
// 0
todo = Ember.Object.create({ isDone: false });
todos.pushObject(todo);
App.todosController.get('remaining');
// 1
```
Note that `@each` only works one level deep. You cannot use nested forms like
`[email protected]` or `[email protected][email protected]`.
## Observers
Ember supports observing any property, including computed properties.
You can set up an observer on an object by using the `observes`
method on a function:
```javascript
Person = Ember.Object.extend({
// these will be supplied by `create`
firstName: null,
lastName: null,
fullName: function() {
var firstName = this.get('firstName');
var lastName = this.get('lastName');
return firstName + ' ' + lastName;
}.property('firstName', 'lastName'),
fullNameChanged: function() {
// deal with the change
}.observes('fullName').on('init')
});
var person = Person.create({
firstName: 'Yehuda',
lastName: 'Katz'
});
person.set('firstName', 'Brohuda'); // observer will fire
```
Because the `fullName` computed property depends on `firstName`,
updating `firstName` will fire observers on `fullName` as well.
### Observers and asynchrony
Observers in Ember are currently synchronous. This means that they will fire
as soon as one of the properties they observe changes. Because of this, it
is easy to introduce bugs where properties are not yet synchronized:
```javascript
Person.reopen({
lastNameChanged: function() {
// The observer depends on lastName and so does fullName. Because observers
// are synchronous, when this function is called the value of fullName is
// not updated yet so this will log the old value of fullName
console.log(this.get('fullName'));
}.observes('lastName')
});
```
This synchronous behaviour can also lead to observers being fired multiple
times when observing multiple properties:
```javascript
Person.reopen({
partOfNameChanged: function() {
// Because both firstName and lastName were set, this observer will fire twice.
}.observes('firstName', 'lastName')
});
person.set('firstName', 'John');
person.set('lastName', 'Smith');
```
To get around these problems, you should make use of `Ember.run.once`. This will
ensure that any processing you need to do only happens once, and happens in the
next run loop once all bindings are synchronized:
```javascript
Person.reopen({
partOfNameChanged: function() {
Ember.run.once(this, 'processFullName');
}.observes('firstName', 'lastName'),
processFullName: function() {
// This will only fire once if you set two properties at the same time, and
// will also happen in the next run loop once all properties are synchronized
console.log(this.get('fullName'));
}
});
person.set('firstName', 'John');
person.set('lastName', 'Smith');
```
### Observers and object initialization
Observers never fire until after the initialization of an object is complete.
If you need an observer to fire as part of the initialization process, you
cannot rely on the side effect of set. Instead, specify that the observer
should also run after init by using `.on('init')`:
```javascript
App.Person = Ember.Object.extend({
init: function() {
this.set('salutation', "Mr/Ms");
},
salutationDidChange: function() {
// some side effect of salutation changing
}.observes('salutation').on('init')
});
```
### Unconsumed Computed Properties Do Not Trigger Observers
If you never `get` a computed property, its observers will not fire even if
its dependent keys change. You can think of the value changing from one unknown
value to another.
This doesn't usually affect application code because computed properties are
almost always observed at the same time as they are fetched. For example, you get
the value of a computed property, put it in DOM (or draw it with D3), and then
observe it so you can update the DOM once the property changes.
If you need to observe a computed property but aren't currently retrieving it,
just get it in your init method.
### Without prototype extensions
You can define inline observers by using the `Ember.observer` method if you
are using Ember without prototype extensions:
```javascript
Person.reopen({
fullNameChanged: Ember.observer('fullName', function() {
// deal with the change
})
});
```
### Outside of class definitions
You can also add observers to an object outside of a class definition
using addObserver:
```javascript
person.addObserver('fullName', function() {
// deal with the change
});
```
## Bindings
A binding creates a link between two properties such that when one changes, the
other one is updated to the new value automatically. Bindings can connect
properties on the same object, or across two different objects. Unlike most other
frameworks that include some sort of binding implementation, bindings in
Ember.js can be used with any object, not just between views and models.
The easiest way to create a two-way binding is by creating a new property
with the string `Binding` at the end, then specifying a path from the global scope:
```javascript
App.wife = Ember.Object.create({
householdIncome: 80000
});
App.husband = Ember.Object.create({
householdIncomeBinding: 'App.wife.householdIncome'
});
App.husband.get('householdIncome'); // 80000
// Someone gets raise.
App.husband.set('householdIncome', 90000);
App.wife.get('householdIncome'); // 90000
```
Note that bindings don't update immediately. Ember waits until all of your
application code has finished running before synchronizing changes, so you can
change a bound property as many times as you'd like without worrying about the
overhead of syncing bindings when values are transient.
## One-Way Bindings
A one-way binding only propagates changes in one direction. Usually, one-way
bindings are just a performance optimization and you can safely use
the more concise two-way binding syntax (as, of course, two-way bindings are
de facto one-way bindings if you only ever change one side).
```javascript
App.user = Ember.Object.create({
fullName: "Kara Gates"
});
App.userView = Ember.View.create({
userNameBinding: Ember.Binding.oneWay('App.user.fullName')
});
// Changing the name of the user object changes
// the value on the view.
App.user.set('fullName', "Krang Gates");
// App.userView.userName will become "Krang Gates"
// ...but changes to the view don't make it back to
// the object.
App.userView.set('userName', "Truckasaurus Gates");
App.user.get('fullName'); // "Krang Gates"
```
## Reopening Classes and Instances
You don't need to define a class all at once. You can reopen a class and
define new properties using the `reopen` method.
```javascript
Person.reopen({
isPerson: true
});
Person.create().get('isPerson') // true
```
When using `reopen`, you can also override existing methods and
call `this._super`.
```javascript
Person.reopen({
// override `say` to add an ! at the end
say: function(thing) {
this._super(thing + "!");
}
});
```
`reopen` is used to add instance methods and properties that are shared across all instances of a class. It does not add
methods and properties to a particular instance of a class as in vanilla JavaScript (without using prototype).
But when you need to create class methods or add properties to the class itself you can use `reopenClass`.
```javascript
Person.reopenClass({
createMan: function() {
return Person.create({isMan: true})
}
});
Person.createMan().get('isMan') // true
```
## Bindings, Observers, Computed Properties: What Do I Use When?
Sometimes new users are confused about when to use computed properties,
bindings and observers. Here are some guidelines to help:
1. Use *computed properties* to build a new property by synthesizing other
properties. Computed properties should not contain application behavior, and
should generally not cause any side-effects when called. Except in rare cases,
multiple calls to the same computed property should always return the same
value (unless the properties it depends on have changed, of course.)
2. *Observers* should contain behavior that reacts to changes in another
property. Observers are especially useful when you need to perform some
behavior after a binding has finished synchronizing.
3. *Bindings* are most often used to ensure objects in two different layers
are always in sync. For example, you bind your views to your controller using
Handlebars.
# Application
## Creating an Application
The first step to creating an Ember.js application is to make an
instance of `Ember.Application` and assign it to a global variable.
```javascript
window.App = Ember.Application.create();
```
Most people call their application `App`, but you can call it whatever
makes the most sense to you. Just make sure it starts with a capital
letter.
What does creating an `Ember.Application` instance get you?
1. It is your application's namespace. All of the classes in your
application will be defined as properties on this object (e.g.,
`App.PostsView` and `App.PostsController`). This helps to prevent
polluting the global scope.
2. It adds event listeners to the document and is responsible for
delegating events to your views. (See [The View
Layer](/guides/understanding-ember/the-view-layer)
for a detailed description.)
3. It automatically renders the [application
template](/guides/templates/the-application-template).
4. It automatically creates a router and begins routing, choosing which
template and model to display based on the current URL.
# Templates
## The Application Template
The `application` template is the default template that is rendered when
your application starts.
You should put your header, footer, and any other decorative content
here. Additionally, you should have at least one `{{outlet}}`:
a placeholder that the router will fill in with the appropriate template,
based on the current URL.
Here's an example template:
```handlebars
<header>
<h1>Igor's Blog</h1>
</header>
<div>
{{outlet}}
</div>
<footer>
&copy;2013 Igor's Publishing, Inc.
</footer>
```
The header and footer will always be displayed on screen, but the
contents of the `<div>` will change depending on if the user is
currently at `/posts` or `/posts/15`, for example.
For more information about how outlets are filled in by the router, see
[Routing](/guides/routing).
If you are keeping your templates in HTML, create a `<script>` tag
without a template name. Ember will use the template without a name as the application template and it will automatically be compiled and appended
to the screen.
```html
<script type="text/x-handlebars">
<div>
{{outlet}}
</div>
</script>
```
If you're using build tools to load your templates, make sure you name
the template `application`.
## Handlebars Basics
Ember.js uses the [Handlebars templating library](http://www.handlebarsjs.com)
to power your app's user interface. Handlebars templates are just like
regular HTML, but also give you the ability to embed expressions that
change what is displayed.
We take Handlebars and extend it with many powerful features. It may
help to think of your Handlebars templates as an HTML-like DSL for
describing the user interface of your app. And, once you've told
Ember.js to render a given template on the screen, you don't need to
write any additional code to make sure it keeps up-to-date.
If you'd prefer an indentation-based alternative to Handlebars syntax,
try [Emblem.js](http://www.emblemjs.com), but make sure you're comfortable
with Handlebars first!
### Defining Templates
If you're not using build tools, you can define your application's main
template inside your HTML by putting it inside a `<script>` tag, like so:
```html
<html>
<body>
<script type="text/x-handlebars">
Hello, <strong>{{firstName}} {{lastName}}</strong>!
</script>
</body>
</html>
```
This template will be compiled automatically and become your
[application template](/guides/templates/the-application-template),
which will be displayed on the page when your app loads.
You can also define templates by name that can be used later. For
example, you may want to define a reusable control that is used in many
different places in your user interface. To tell Ember.js to save the
template for later, instead of displaying it immediately, you can add
the `data-template-name` attribute:
```html
<html>
<head>
<script type="text/x-handlebars" data-template-name="say-hello">
<div class="my-cool-control">{{name}}</div>
</script>
</head>
</html>
```
If you are using build tools to manage your application's assets, most
will know how to precompile Handlebars templates and make them available
to Ember.js.
### Handlebars Expressions
Each template has an associated _controller_: this is where the template
finds the properties that it displays.
You can display a property from your controller by wrapping the property
name in curly braces, like this:
```handlebars
Hello, <strong>{{firstName}} {{lastName}}</strong>!
```
This would look up the `firstName` and `lastName` properties from the
controller, insert them into the HTML described in the template, then
put them into the DOM.
By default, your top-most application template is bound to your `ApplicationController`:
```javascript
App.ApplicationController = Ember.Controller.extend({
firstName: "Trek",
lastName: "Glowacki"
});
```
The above template and controller would combine to display the following
rendered HTML:
```html
Hello, <strong>Trek Glowacki</strong>!
```
These expressions (and the other Handlebars features you will learn
about next) are _bindings aware_. That means that if the values used
by your templates ever change, your HTML will be updated automatically.
As your application grows in size, it will have many templates, each
bound to different controllers.
## Conditionals
Sometimes you may only want to display part of your template if a property
exists.
We can use the `{{#if}}` helper to conditionally render a block:
```handlebars
{{#if person}}
Welcome back, <b>{{person.firstName}} {{person.lastName}}</b>!
{{/if}}
```
Handlebars will not render the block if the argument passed evaluates to
`false`, `undefined`, `null` or `[]` (i.e., any "falsy" value).
If the expression evaluates to falsy, we can also display an alternate template
using `{{else}}`:
```handlebars
{{#if person}}
Welcome back, <b>{{person.firstName}} {{person.lastName}}</b>!
{{else}}
Please log in.
{{/if}}
```
To only render a block if a value is falsy, use `{{#unless}}`:
```handlebars
{{#unless hasPaid}}
You owe: ${{total}}
{{/unless}}
```
`{{#if}}` and `{{#unless}}` are examples of block expressions. These allow you
to invoke a helper with a portion of your template. Block expressions look like
normal expressions except that they contain a hash (#) before the helper name,
and require a closing expression.
## Displaying a List of Items
If you need to enumerate over a list of objects, use Handlebars' `{{#each}}` helper:
```handlebars
<ul>
{{#each people}}
<li>Hello, {{name}}!</li>
{{/each}}
</ul>
```
The template inside of the `{{#each}}` block will be repeated once for
each item in the array, with the context of the template set to the
current item.
The above example will print a list like this:
```html
<ul>
<li>Hello, Yehuda!</li>
<li>Hello, Tom!</li>
<li>Hello, Trek!</li>
</ul>
```
Like everything in Handlebars, the `{{#each}}` helper is bindings-aware.
If your application adds a new item to the array, or removes an item,
the DOM will be updated without having to write any code.
There is an alternative form of `{{#each}}` that does not change the
scope of its inner template. This is useful for cases where you need to
access a property from the outer scope within the loop.
```handlebars
{{name}}'s Friends
<ul>
{{#each friend in friends}}
<li>{{name}}'s friend {{friend.name}}</li>
{{/each}}
</ul>
```
This would print a list like this:
```html
Trek's Friends
<ul>
<li>Trek's friend Yehuda</li>
<li>Trek's friend Tom!</li>
</ul>
```
The `{{#each}}` helper can have a matching `{{else}}`.
The contents of this block will render if the collection is empty:
```handlebars
{{#each people}}
Hello, {{name}}!
{{else}}
Sorry, nobody is here.
{{/each}}
```
## Changing Scope
Sometimes you may want to invoke a section of your template with a
different context.
For example, instead of repeating a long path, like in this example:
```handlebars
Welcome back, <b>{{person.firstName}} {{person.lastName}}</b>!
```
We can use the `{{#with}}` helper to clean it up:
```handlebars
{{#with person}}
Welcome back, <b>{{firstName}} {{lastName}}</b>!
{{/with}}
```
`{{#with}}` changes the _context_ of the block you pass to it. The
context, by default, is the template's controller. By using the `{{#with}}`
helper, you can change the context of all of the Handlebars expressions
contained inside the block.
Note: it's possible to store the context within a variable for nested
usage using the "as" keyword:
```handlebars
{{#with person as user}}
{{#each book in books}}
{{user.firstName}} has read {{book.name}}!
{{/each}}
{{/with}}
```
## Binding Element Attributes
In addition to normal text, you may also want to have your templates
contain HTML elements whose attributes are bound to the controller.
For example, imagine your controller has a property that contains a URL
to an image:
```handlebars
<div id="logo">
<img {{bind-attr src=logoUrl}} alt="Logo">
</div>
```
This generates the following HTML:
```html
<div id="logo">
<img src="http://www.example.com/images/logo.png" alt="Logo">
</div>
```
If you use `{{bind-attr}}` with a Boolean value, it will add or remove
the specified attribute. For example, given this template:
```handlebars
<input type="checkbox" {{bind-attr disabled=isAdministrator}}>
```
If `isAdministrator` is `true`, Handlebars will produce the following
HTML element:
```html
<input type="checkbox" disabled>
```
If `isAdministrator` is `false`, Handlebars will produce the following:
```html
<input type="checkbox">
```
### Adding data attributes
By default, view helpers do not accept *data attributes*. For example
```handlebars
{{#link-to "photos" data-toggle="dropdown"}}Photos{{/link-to}}
{{input type="text" data-toggle="tooltip" data-placement="bottom" title="Name"}}
```
renders the following HTML:
```html
<a id="ember239" class="ember-view" href="#/photos">Photos</a>
<input id="ember257" class="ember-view ember-text-field" type="text">
```
There are two ways to enable support for data attributes. One way would be to add an
attribute binding on the view, e.g. `Ember.LinkView` or `Ember.TextField` for the specific attribute:
```javascript
Ember.LinkView.reopen({
attributeBindings: ['data-toggle']
});
Ember.TextField.reopen({
attributeBindings: ['data-toggle', 'data-placement']
});
```
Now the same handlebars code above renders the following HTML:
```html
<a id="ember240" class="ember-view" href="#/photos" data-toggle="dropdown">Photos</a>
<input id="ember259" class="ember-view ember-text-field"
type="text" data-toggle="tooltip" data-placement="bottom">
```
You can also automatically bind data attributes on the base view with the
following:
```javascript
Ember.View.reopen({
init: function() {
this._super();
var self = this;
// bind attributes beginning with 'data-'
Em.keys(this).forEach(function(key) {
if (key.substr(0, 5) === 'data-') {
self.get('attributeBindings').pushObject(key);
}
});
}
});
```
Now you can add as many data-attributes as you want without having to specify them by name.
## Binding Element Class Names
An HTML element's `class` attribute can be bound like any other
attribute:
```handlebars
<div {{bind-attr class="priority"}}>
Warning!
</div>
```
If the controller's `priority` property is `"p4"`, this template will emit the following HTML:
```html
<div class="p4">
Warning!
</div>
```
### Binding to Boolean Values
If the value to which you bind is a Boolean, Ember.js will apply the
dasherized version of the property name as a class:
```handlebars
<div {{bind-attr class="isUrgent"}}>
Warning!
</div>
```
If `isUrgent` is true, this emits the following HTML:
```html
<div class="is-urgent">
Warning!
</div>
```
If `isUrgent` is false, no class name is added:
```html
<div>
Warning!
</div>
```
If you want to explicitly provide a class name (instead of Ember.js
dasherizing the property name), use the following syntax:
```handlebars
<div {{bind-attr class="isUrgent:urgent"}}>
Warning!
</div>
```
Instead of the dasherized name, this will produce:
```html
<div class="urgent">
Warning!
</div>
```
You can also specify a class name to add when the property is `false`:
```handlebars
<div {{bind-attr class="isEnabled:enabled:disabled"}}>
Warning!
</div>
```
In this case, if the `isEnabled` property is `true`, the `enabled`
class will be added. If the property is `false`, the class `disabled`
will be added.
This syntax can also be used to add a class if a property is `false`
and remove it if the property is `true`, so this:
```handlebars
<div {{bind-attr class="isEnabled::disabled"}}>
Warning!
</div>
```
Will add the class `disabled` when `isEnabled` is `false` and add no
class if `isEnabled` is `true`.
### Static Classes
If you need an element to have a combination of static and bound
classes, you should include the static class in the list of bound
properties, prefixed by a colon:
```handlebars
<div {{bind-attr class=":high-priority isUrgent"}}>
Warning!
</div>
```
This will add the literal `high-priority` class to the element:
```html
<div class="high-priority is-urgent">
Warning!
</div>
```
Bound class names and static class names cannot be combined. The
following example **will not work**:
```handlebars
<div class="high-priority" {{bind-attr class="isUrgent"}}>
Warning!
</div>
```
### Binding Multiple Classes
Unlike other element attributes, you can bind multiple classes:
```handlebars
<div {{bind-attr class="isUrgent priority"}}>
Warning!
</div>
```
This works how you would expect, applying the rules described above in
order:
```html
<div class="is-urgent p4">
Warning!
</div>
```
## Links
## The `{{link-to}}` Helper
You create a link to a route using the `{{link-to}}` helper.
```js
App.Router.map(function() {
this.resource("photos", function(){
this.route("edit", { path: "/:photo_id" });
});
});
```
```handlebars
{{! photos.handlebars }}
<ul>
{{#each photo in photos}}
<li>{{#link-to 'photos.edit' photo}}{{photo.title}}{{/link-to}}</li>
{{/each}}
</ul>
```
If the model for the `photos` template is a list of three photos, the
rendered HTML would look something like this:
```html
<ul>
<li><a href="/photos/1">Happy Kittens</a></li>
<li><a href="/photos/2">Puppy Running</a></li>
<li><a href="/photos/3">Mountain Landscape</a></li>
</ul>
```
When the rendered link matches the current route, and the same
object instance is passed into the helper, then the link is given
`class="active"`.
The `{{link-to}}` helper takes:
* The name of a route. In this example, it would be `index`, `photos`, or
`photos.edit`.
* At most one model for each [dynamic segment](/guides/routing/defining-your-routes/#toc_dynamic-segments).
By default, Ember.js will replace each segment with the value of the corresponding object's `id` property.
If there is no model to pass to the helper, you can provide an explicit identifier value instead.
The value will be filled into the [dynamic segment](/guides/routing/defining-your-routes/#toc_dynamic-segments)
of the route, and will make sure that the `model` hook is triggered.
* An optional title which will be bound to the `a` title attribute
```handlebars
{{! photos.handlebars }}
{{#link-to 'photo.edit' 1}}
First Photo Ever
{{/link-to}}
```
### Example for Multiple Segments
If the route is nested, you can supply a model or an identifier for each dynamic
segment.
```js
App.Router.map(function() {
this.resource("photos", function(){
this.resource("photo", { path: "/:photo_id" }, function(){
this.route("comments");
this.route("comment", { path: "/comments/:comment_id" });
});
});
});
```
```handlebars
<!-- photoIndex.handlebars -->
<div class="photo">
{{body}}
</div>
<p>{{#link-to 'photo.comment' primaryComment}}Main Comment{{/link-to}}</p>
```
If you specify only one model, it will represent the innermost dynamic segment `:comment_id`.
The `:photo_id` segment will use the current photo.
Alternatively, you could pass both a photo and a comment to the helper:
```handlebars
<p>
{{#link-to 'photo.comment' 5 primaryComment}}
Main Comment for the Next Photo
{{/link-to}}
</p>
```
In the above example, the model hook for `PhotoRoute` will run with `params.photo_id = 5`. The `model` hook for
`CommentRoute` _won't_ run since you supplied a model object for the `comment` segment. The comment's id will
populate the url according to `CommentRoute`'s `serialize` hook.
### Adding additional attributes on a link
When generating a link you might want to set additional attributes for it. You can do this with additional
arguments to the `link-to` helper:
```handlebars
<p>
{{link-to 'photo.edit' photo class="btn btn-primary"}}
</p>
```
Many of the common HTML properties you would want to use like `class`, and `rel` will work. When
adding class names, Ember will also apply the standard `ember-view` and possibly `active` class names.
## Actions
## The `{{action}}` Helper
Your app will often need a way to let users interact with controls that
change application state. For example, imagine that you have a template
that shows a blog post, and supports expanding the post with additional
information.
You can use the `{{action}}` helper to make an HTML element clickable.
When a user clicks the element, the named event will be sent to your
application.
```handlebars
<!-- post.handlebars -->
<div class='intro'>
{{intro}}
</div>
{{#if isExpanded}}
<div class='body'>{{body}}</div>
<button {{action 'contract'}}>Contract</button>
{{else}}
<button {{action 'expand'}}>Show More...</button>
{{/if}}
```
```js
App.PostController = Ember.ObjectController.extend({
// initial value
isExpanded: false,
actions: {
expand: function() {
this.set('isExpanded', true);
},
contract: function() {
this.set('isExpanded', false);
}
}
});
```
### Action Bubbling
By default, the `{{action}}` helper triggers a method on the template's
controller, as illustrated above.
If the controller does not implement a method with the same name as the
action in its actions object, the action will be sent to the router, where
the currently active leaf route will be given a chance to handle the action.
Routes and controllers that handle actions **must place action handlers
inside an `actions` hash**. Even if a route has a method with the same name
as the actions, it will not be triggered unless it is inside an `actions` hash.
In the case of a controller, while there is deprecated support for triggering
a method directly on the controller, it is strongly recommended that you
put your action handling methods inside an `actions` hash for forward
compatibility.
```js
App.PostRoute = Ember.Route.extend({
actions: {
expand: function() {
this.controller.set('isExpanded', true);
},
contract: function() {
this.controller.set('isExpanded', false);
}
}
});
```
As you can see in this example, the action handlers are called such
that when executed, `this` is the route, not the `actions` hash.
To continue bubbling the action, you must return true from the handler:
```js
App.PostRoute = Ember.Route.extend({
actions: {
expand: function() {
this.controller.set('isExpanded', true);
},
contract: function() {
// ...
if (actionShouldAlsoBeTriggeredOnParentRoute) {
return true;
}
}
});
```
If neither the template's controller nor the currently active route
implements a handler, the action will continue to bubble to any parent
routes. Ultimately, if an `ApplicationRoute` is defined, it will have an
opportunity to handle the action.
When an action is triggered, but no matching action handler is
implemented on the controller, the current route, or any of the
current route's ancestors, an error will be thrown.
![Action Bubbling](/images/template-guide/action-bubbling.png)
This allows you to create a button that has different behavior based on
where you are in the application. For example, you might want to have a
button in a sidebar that does one thing if you are somewhere inside of
the `/posts` route, and another thing if you are inside of the `/about`
route.
### Action Parameters
You can optionally pass arguments to the action handler. Any values
passed to the `{{action}}` helper after the action name will be passed to
the handler as arguments.
For example, if the `post` argument was passed:
```handlebars
<p><button {{action "select" post}}>✓</button> {{post.title}}</p>
```
The route's `select` action handler would be called with a single argument
containing the post model:
```js
App.PostController = Ember.ObjectController.extend({
actions: {
select: function(post) {
console.log(post.get('title'));
}
}
});
```
### Specifying the Type of Event
By default, the `{{action}}` helper listens for click events and triggers
the action when the user clicks on the element.
You can specify an alternative event by using the `on` option.
```handlebars
<p>
<button {{action "select" post on="mouseUp"}}>✓</button>
{{post.title}}
</p>
```
You should use the normalized event names [listed in the View guide][1].
In general, two-word event names (like `keypress`) become `keyPress`.
[1]: /guides/understanding-ember/the-view-layer/#toc_adding-new-events
### Specifying Whitelisted Modifier Keys
By default the `{{action}}` helper will ignore click events with
pressed modifier keys. You can supply an `allowedKeys` option
to specify which keys should not be ignored.
```handlebars
<script type="text/x-handlebars" data-template-name='a-template'>
<div {{action 'anActionName' allowedKeys="alt"}}>
click me
</div>
</script>
```
This way the `{{action}}` will fire when clicking with the alt key
pressed down.
### Stopping Event Propagation
By default, the `{{action}}` helper allows events it handles to bubble
up to parent DOM nodes. If you want to stop propagation, you can disable
propagation to the parent node.
For example, if you have a **✗** button inside of a link, you will want
to ensure that if the user clicks on the **✗**, that the link is not
clicked.
```handlebars
{{#link-to 'post'}}
Post
<button {{action 'close' bubbles=false}}>✗</button>
{{/link-to}}
```
Without `bubbles=false`, if the user clicked on the button, Ember.js
will trigger the action, and then the browser will propagate the click
to the link.
With `bubbles=false`, Ember.js will stop the browser from propagating
the event.
### Specifying a Target
By default, the `{{action}}` helper will send the action to the view's
target, which is generally the view's controller. (Note: in the case of
an Ember.Component, the default target is the component itself.)
You can specify an alternative target by using the `target` option. This
is most commonly used to send actions to a view instead of a controller.
```handlebars
<p>
<button {{action "select" post target="view"}}>✓</button>
{{post.title}}
</p>
```
You would handle this in an `actions` hash on your view.
```javascript
App.PostsIndexView = Ember.View.extend({
actions: {
select: function(post) {
// do your business.
}
}
});
```
## Input Helpers
## Input Helpers
The `{{input}}` and `{{textarea}}` helpers in Ember.js are the easiest way to
create common form controls. The `{{input}}` helper wraps the built-in
[Ember.TextField][1] and [Ember.Checkbox][2] views, while `{{textarea}}` wraps
[Ember.TextArea][3]. Using these helpers, you can create these views with
declarations almost identical to how you'd create a traditional `<input>` or
`<textarea>` element.
[1]: /api/classes/Ember.TextField.html
[2]: /api/classes/Ember.Checkbox.html
[3]: /api/classes/Ember.TextArea.html
### Text fields
```handlebars
{{input value="http://www.facebook.com"}}
```
Will become:
```html
<input type="text" value="http://www.facebook.com"/>
```
You can pass the following standard `<input>` attributes within the input
helper:
* `value`
* `size`
* `name`
* `pattern`
* `placeholder`
* `disabled`
* `maxlength`
* `tabindex`
If these attributes are set to a quoted string, their values will be set
directly on the element, as in the previous example. However, when left
unquoted, these values will be bound to a property on the template's current
rendering context. For example:
```handlebars
{{input type="text" value=firstName disabled=entryNotAllowed size="50"}}
```
Will bind the `disabled` attribute to the value of `entryNotAllowed` in the
current context.
### Checkboxes
You can also use the `{{input}}` helper to create a checkbox by setting its
`type`:
```handlebars
{{input type="checkbox" name="isAdmin" checked=isAdmin}}
```
Checkboxes support the following properties:
* `checked`
* `disabled`
* `tabindex`
* `indeterminate`
* `name`
Which can be bound or set as described in the previous section.
### Text Areas
```handlebars
{{textarea value=name cols="80" rows="6"}}
```
Will bind the value of the text area to `name` on the current context.
`{{textarea}}` supports binding and/or setting the following properties:
* `rows`
* `cols`
* `placeholder`
* `disabled`
* `maxlength`
* `tabindex`
### Extending Built-In Controls
See the [Built-in Views][4] section of these guides to learn how to further
extend these views.
[4]: /guides/views/built-in-views
## Development Helpers
## Development Helpers
Handlebars and Ember come with a few helpers that can make developing your
templates a bit easier. These helpers make it simple to output variables into
your browser's console, or activate the debugger from your templates.
### Logging
The `{{log}}` helper makes it easy to output variables or expressions in the
current rendering context into your browser's console:
```handlebars
{{log 'Name is:', name}}
```
The `{{log}}` helper also accepts primitive types such as strings or numbers.
### Adding a breakpoint
The ``{{debugger}}`` helper provides a handlebars equivalent to JavaScript's
`debugger` keyword. It will halt execution inside the debugger helper and give
you the ability to inspect the current rendering context:
```handlebars
{{debugger}}
```
Just before the helper is invoked two useful variables are defined:
* `templateContext` The current context that variables are fetched from. This
is likely a controller.
* `typeOfTemplateContext` A string describing what the templateContext is.
For example, if you are wondering why a specific variable isn't displaying in
your template, you could use the `{{debugger}}` helper. When the breakpoint is
hit, you can use the `templateContext` in your console to lookup properties:
```
> templateContext.get('name')
"Bruce Lee"
```
## Rendering with Helpers
Ember.js provides several helpers that allow you to render other views and templates in different ways.
### The `{{partial}}` Helper
`{{partial}}` takes the template to be rendered as an argument, and renders that template in place.
`{{partial}}` does not change context or scope. It simply drops the given template into place with the current scope.
```handlebars
<script type="text/x-handlebars" data-template-name='_author'>
Written by {{author.firstName}} {{author.lastName}}
</script>
<script type="text/x-handlebars" data-template-name='post'>
<h1>{{title}}</h1>
<div>{{body}}</div>
{{partial "author"}}
</script>
```
```html
<div>
<h1>Why You Should Use Ember.JS</h1>
<div>Because it's awesome!</div>
Written by Yehuda Katz
</div>
```
The partial's `data-template-name` must start with an underscore (e.g. `data-template-name='_author'` or `data-template-name='foo/_bar'`)
### The `{{view}}` Helper
This helper works like the partial helper, except instead of providing a template to be rendered within the current template, you provide a view class. The view controls what template is rendered.
```javascript
App.AuthorView = Ember.View.extend({
// We are setting templateName manually here to the default value
templateName: "author",
// A fullName property should probably go on App.Author,
// but we're doing it here for the example
fullName: (function() {
return this.get("author").get("firstName") + " " + this.get("author").get("lastName");
}).property("firstName","lastName")
})
```
```handlebars
<script type="text/x-handlebars" data-template-name='author'>
Written by {{view.fullName}}
</script>
<script type="text/x-handlebars" data-template-name='post'>
<h1>{{title}}</h1>
<div>{{body}}</div>
{{view App.AuthorView}}
</script>
```
```html
<div>
<h1>Why You Should Use Ember.JS</h1>
<div>Because it's awesome!</div>
Written by Yehuda Katz
</div>
```
When using `{{partial "author"}}`:
* No instance of App.AuthorView will be created
* The given template will be rendered
When using `{{view App.AuthorView}}`:
* An instance of App.AuthorView will be created
* It will be rendered here, using the template associated with that view (the default template being "author")
For more information, see [Inserting Views in Templates](/guides/views/inserting-views-in-templates)
### The `{{render}}` Helper
`{{render}}` takes two parameters:
* The first parameter describes the context to be setup
* The optional second parameter is a model, which will be passed to the controller if provided
`{{render}}` does several things:
* When no model is provided it gets the singleton instance of the corresponding controller
* When a model is provided it gets a unique instance of the corresponding controller
* Renders the named template using this controller
* Sets the model of the corresponding controller
Modifying the post / author example slightly:
```handlebars
<script type="text/x-handlebars" data-template-name='author'>
Written by {{firstName}} {{lastName}}.
Total Posts: {{postCount}}
</script>
<script type="text/x-handlebars" data-template-name='post'>
<h1>{{title}}</h1>
<div>{{body}}</div>
{{render "author" author}}
</script>
```
```javascript
App.AuthorController = Ember.ObjectController.extend({
postCount: function() {
return App.Post.countForAuthor(this.get("model"));
}.property("model","[email protected]")
})
```
In this example, render will:
* Get an instance of App.AuthorView if that class exists, otherwise uses a default generated view
* Use the corresponding template (in this case the default of "author")
* Get (or generate) the singleton instance of AuthorController
* Set the AuthorController's model to the 2nd argument passed to render, here the author field on the post
* Render the template in place, with the context created in the previous steps.
`{{render}}` does not require the presence of a matching route.
`{{render}}` is similar to `{{outlet}}`. Both tell Ember.js to devote this portion of the page to something.
`{{outlet}}`: The router determines the route and sets up the appropriate controllers/views/models.
`{{render}}`: You specify (directly and indirectly) the appropriate controllers/views/models.
Note: `{{render}}` cannot be called multiple times for the same route when not specifying a model.
### Comparison Table
#### General
<table>
<thead>
<tr>
<th>Helper</th>
<th>Template</th>
<th>Model</th>
<th>View</th>
<th>Controller</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>{{partial}}</code></td>
<td>Specified Template</td>
<td>Current Model</td>
<td>Current View</td>
<td>Current Controller</td>
</tr>
<tr>
<td><code>{{view}}</code></td>
<td>View's Template</td>
<td>Current Model</td>
<td>Specified View</td>
<td>Current Controller</td>
</tr>
<tr>
<td><code>{{render}}</code></td>
<td>View's Template</td>
<td>Specified Model</td>
<td>Specified View</td>
<td>Specified Controller</td>
</tr>
</tbody>
</table>
#### Specific
<table>
<thead>
<tr>
<th>Helper</th>
<th>Template</th>
<th>Model</th>
<th>View</th>
<th>Controller</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>{{partial "author"}}</code></td>
<td><code>author.hbs</code></td>
<td>Post</td>
<td><code>App.PostView</code></td>
<td><code>App.PostController</code></td>
</tr>
<tr>
<td><code>{{view App.AuthorView}}</code></td>
<td><code>author.hbs</code></td>
<td>Post</td>
<td><code>App.AuthorView</code></td>
<td><code>App.PostController</code></td>
</tr>
<tr>
<td><code>{{render "author" author}}</code></td>
<td><code>author.hbs</code></td>
<td>Author</td>
<td><code>App.AuthorView</code></td>
<td><code>App.AuthorController</code></td>
</tr>
</tbody>
</table>
## Writing Helpers
Sometimes, you may use the same HTML in your application multiple times. In those cases, you can register a custom helper that can be invoked from any Handlebars template.
For example, imagine you are frequently wrapping certain values in a `<span>` tag with a custom class. You can register a helper from your JavaScript like this:
```javascript
Ember.Handlebars.helper('highlight', function(value, options) {
var escaped = Handlebars.Utils.escapeExpression(value);
return new Handlebars.SafeString('<span class="highlight">' + escaped + '</span>');
});
```
If you return HTML from a helper, and you don't want it to be escaped,
make sure to return a new `SafeString`. Make sure you first escape any
user data!
Anywhere in your Handlebars templates, you can now invoke this helper:
```handlebars
{{highlight name}}
```
and it will output the following:
```html
<span class="highlight">Peter</span>
```
If the `name` property on the current context changes, Ember.js will
automatically execute the helper again and update the DOM with the new
value.
### Dependencies
Imagine you want to render the full name of an `App.Person`. In this
case, you will want to update the output if the person itself changes,
or if the `firstName` or `lastName` properties change.
```js
Ember.Handlebars.helper('fullName', function(person) {
return person.get('firstName') + ' ' + person.get('lastName');
}, 'firstName', 'lastName');
```
You would use the helper like this:
```handlebars
{{fullName person}}
```
Now, whenever the context's person changes, or when any of the
_dependent keys_ change, the output will automatically update.
Both the path passed to the `fullName` helper and its dependent keys may
be full _property paths_ (e.g. `person.address.country`).
### Custom View Helpers
You may also find yourself rendering your view classes in multiple
places using the `{{view}}` helper. In this case, you can save yourself
some typing by registering a custom view helper.
For example, let’s say you have a view called `App.CalendarView`.
You can register a helper like this:
```javascript
Ember.Handlebars.helper('calendar', App.CalendarView);
```
Using `App.CalendarView` in a template then becomes as simple as:
```handlebars
{{calendar}}
```
Which is functionally equivalent to, and accepts all the same
arguments as:
```handlebars
{{view App.CalendarView}}
```
# Routing
## Routing
As users interact with your application, it moves through many
different states. Ember.js gives you helpful tools for managing
that state in a way that scales with your application.
To understand why this is important, imagine we are writing a web app
for managing a blog. At any given time, we should be able to answer
questions like: _Is the user currently logged in? Are they an admin
user? What post are they looking at? Is the settings screen open? Are
they editing the current post?_
In Ember.js, each of the possible states in your application is
represented by a URL. Because all of the questions we asked above—
_Are we logged in? What post are we looking at?_ —are encapsulated by
route handlers for the URLs, answering them is both simple and accurate.
At any given time, your application has one or more _active route
handlers_. The active handlers can change for one of two reasons:
1. The user interacted with a view, which generated an event that caused
the URL to change.
2. The user changed the URL manually (e.g., via the back button), or the
page was loaded for the first time.
When the current URL changes, the newly active route handlers may do one
or more of the following:
1. Conditionally redirect to a new URL.
2. Update a controller so that it represents a particular model.
3. Change the template on screen, or place a new template into an
existing outlet.
###Logging Route Changes
As your application increases in complexity, it can be helpful to see exactly what is going on with the router. To have Ember write out transition events to the log, simply modify your `Ember.Application`:
```javascript
App = Ember.Application.create({
LOG_TRANSITIONS: true
});
```
###Specifying a Root URL
If your Ember application is one of multiple web applications served from the same domain, it may be necessary to indicate to the router what the root URL for your Ember application is. By default, Ember will assume it is served from the root of your domain.
If for example, you wanted to serve your blogging application from www.emberjs.com/blog/, it would be necessary to specify a root URL of `/blog/`.
This can be achieved by setting the rootURL on the router:
```js
App.Router.reopen({
rootURL: '/blog/'
});
```
## Defining Your Routes
When your application starts, the router is responsible for displaying
templates, loading data, and otherwise setting up application state.
It does so by matching the current URL to the _routes_ that you've
defined.
```js
App.Router.map(function() {
this.route("about", { path: "/about" });
this.route("favorites", { path: "/favs" });
});
```
Now, when the user visits `/about`, Ember.js will render the `about`
template. Visiting `/favs` will render the `favorites` template.
<aside>
**Heads up!** You get a few routes for free: the `ApplicationRoute` and
the `IndexRoute` (corresponding to the `/` path).
[See below](#toc_initial-routes) for more details.
</aside>
Note that you can leave off the path if it is the same as the route
name. In this case, the following is equivalent to the above example:
```js
App.Router.map(function() {
this.route("about");
this.route("favorites", { path: "/favs" });
});
```
Inside your templates, you can use `{{link-to}}` to navigate between
routes, using the name that you provided to the `route` method (or, in
the case of `/`, the name `index`).
```handlebars
{{#link-to 'index'}}<img class="logo">{{/link-to}}
<nav>
{{#link-to 'about'}}About{{/link-to}}
{{#link-to 'favorites'}}Favorites{{/link-to}}
</nav>
```
The `{{link-to}}` helper will also add an `active` class to the link that
points to the currently active route.
You can customize the behavior of a route by creating an `Ember.Route`
subclass. For example, to customize what happens when your user visits
`/`, create an `App.IndexRoute`:
```javascript
App.IndexRoute = Ember.Route.extend({
setupController: function(controller) {
// Set the IndexController's `title`
controller.set('title', "My App");
}
});
```
The `IndexController` is the starting context for the `index` template.
Now that you've set `title`, you can use it in the template:
```handlebars
<!-- get the title from the IndexController -->
<h1>{{title}}</h1>
```
(If you don't explicitly define an `App.IndexController`, Ember.js will
automatically generate one for you.)
Ember.js automatically figures out the names of the routes and controllers based on
the name you pass to `this.route`.
<table>
<thead>
<tr>
<th>URL</th>
<th>Route Name</th>
<th>Controller</th>
<th>Route</th>
<th>Template</th>
</tr>
</thead>
<tr>
<td><code>/</code></td>
<td><code>index</code></td>
<td><code>IndexController</code></td>
<td><code>IndexRoute</code></td>
<td><code>index</code></td>
</tr>
<tr>
<td><code>/about</code></td>
<td><code>about</code></td>
<td><code>AboutController</code></td>
<td><code>AboutRoute</code></td>
<td><code>about</code></td>
</tr>
<tr>
<td><code>/favs</code></td>
<td><code>favorites</code></td>
<td><code>FavoritesController</code></td>
<td><code>FavoritesRoute</code></td>
<td><code>favorites</code></td>
</tr>
</table>
### Resources
You can define groups of routes that work with a resource:
```javascript
App.Router.map(function() {
this.resource('posts', { path: '/posts' }, function() {
this.route('new');
});
});
```
As with `this.route`, you can leave off the path if it's the same as the
name of the route, so the following router is equivalent:
```javascript
App.Router.map(function() {
this.resource('posts', function() {
this.route('new');
});
});
```
This router creates three routes:
<table>
<thead>
<tr>
<th>URL</th>
<th>Route Name</th>
<th>Controller</th>
<th>Route</th>
<th>Template</th>
</tr>
</thead>
<tr>
<td><code>/</code></td>
<td><code>index</code></td>
<td><code>IndexController</code></td>
<td><code>IndexRoute</code></td>
<td><code>index</code></td>
</tr>
<tr>
<td>N/A</td>
<td><code>posts</code><sup>1</sup></td>
<td><code>PostsController</code></td>
<td><code>PostsRoute</code></td>
<td><code>posts</code></td>
</tr>
<tr>
<td><code>/posts</code></td>
<td><code>posts.index</code></code></td>
<td><code>PostsController</code><br>↳<code>PostsIndexController</code></td>
<td><code>PostsRoute</code><br>↳<code>PostsIndexRoute</code></td>
<td><code>posts</code><br>↳<code>posts/index</code></td>
</tr>
<tr>
<td><code>/posts/new</code></td>
<td><code>posts.new</code></td>
<td><code>PostsController</code><br>↳<code>PostsNewController</code></td>
<td><code>PostsRoute</code><br>↳<code>PostsNewRoute</code></td>
<td><code>posts</code><br>↳<code>posts/new</code></td>
</tr>
</table>
<small><sup>1</sup> Transitioning to `posts` or creating a link to
`posts` is equivalent to transitioning to `posts.index` or linking to
`posts.index`</small>
NOTE: If you define a resource using `this.resource` and **do not** supply
a function, then the implicit `resource.index` route is **not** created. In
that case, `/resource` will only use the `ResourceRoute`, `ResourceController`,
and `resource` template.
Routes nested under a resource take the name of the resource plus their
name as their route name. If you want to transition to a route (either
via `transitionTo` or `{{#link-to}}`), make sure to use the full route
name (`posts.new`, not `new`).
Visiting `/` renders the `index` template, as you would expect.
Visiting `/posts` is slightly different. It will first render the
`posts` template. Then, it will render the `posts/index` template into the
`posts` template's outlet.
Finally, visiting `/posts/new` will first render the `posts` template,
then render the `posts/new` template into its outlet.
NOTE: You should use `this.resource` for URLs that represent a **noun**,
and `this.route` for URLs that represent **adjectives** or **verbs**
modifying those nouns. For example, in the code sample above, when
specifying URLs for posts (a noun), the route was defined with
`this.resource('posts')`. However, when defining the `new` action
(a verb), the route was defined with `this.route('new')`.
### Dynamic Segments
One of the responsibilities of a resource's route handler is to convert a URL
into a model.
For example, if we have the resource `this.resource('posts');`, our
route handler might look like this:
```js
App.PostsRoute = Ember.Route.extend({
model: function() {
return this.store.find('posts');
}
});
```
The `posts` template will then receive a list of all available posts as
its context.
Because `/posts` represents a fixed model, we don't need any
additional information to know what to retrieve. However, if we want a route
to represent a single post, we would not want to have to hardcode every
possible post into the router.
Enter _dynamic segments_.
A dynamic segment is a portion of a URL that starts with a `:` and is
followed by an identifier.
```js
App.Router.map(function() {
this.resource('posts');
this.resource('post', { path: '/post/:post_id' });
});
App.PostRoute = Ember.Route.extend({
model: function(params) {
return this.store.find('post', params.post_id);
}
});
```
Because this pattern is so common, the above `model` hook is the
default behavior.
For example, if the dynamic segment is `:post_id`, Ember.js is smart
enough to know that it should use the model `App.Post` (with the ID
provided in the URL). Specifically, unless you override `model`, the route will
return `this.store.find('post', params.post_id)` automatically.
Not coincidentally, this is exactly what Ember Data expects. So if you
use the Ember router with Ember Data, your dynamic segments will work
as expected out of the box.
If your model does not use the `id` property in the URL, you should
define a serialize method on your route:
```javascript
App.Router.map(function() {
this.resource('post', {path: '/posts/:post_slug'});
});
App.PostRoute = Ember.Route.extend({
model: function(params) {
// the server returns `{ slug: 'foo-post' }`
return jQuery.getJSON("/posts/" + params.post_slug);
},
serialize: function(model) {
// this will make the URL `/posts/foo-post`
return { post_slug: model.get('slug') };
}
});
```
The default `serialize` method inserts the model's `id` into the route's
dynamic segment (in this case, `:post_id`).
### Nested Resources
You cannot nest routes, but you can nest resources:
```javascript
App.Router.map(function() {
this.resource('post', { path: '/post/:post_id' }, function() {
this.route('edit');
this.resource('comments', function() {
this.route('new');
});
});
});
```
This router creates five routes:
<div style="overflow: auto">
<table>
<thead>
<tr>
<th>URL</th>
<th>Route Name</th>
<th>Controller</th>
<th>Route</th>
<th>Template</th>
</tr>
</thead>
<tr>
<td><code>/</code></td>
<td><code>index</code></td>
<td><code>App.IndexController</code></td>
<td><code>App.IndexRoute</code></td>
<td><code>index</code></td>
</tr>
<tr>
<td>N/A</td>
<td><code>post</code></td>
<td><code>App.PostController</code></td>
<td><code>App.PostRoute</code></td>
<td><code>post</code></td>
</tr>
<tr>
<td><code>/post/:post_id<sup>2</sup></code></td>
<td><code>post.index</code></td>
<td><code>App.PostIndexController</code></td>
<td><code>App.PostIndexRoute</code></td>
<td><code>post/index</code></td>
</tr>
<tr>
<td><code>/post/:post_id/edit</code></td>
<td><code>post.edit</code></td>
<td><code>App.PostEditController</code></td>
<td><code>App.PostEditRoute</code></td>
<td><code>post/edit</code></td>
</tr>
<tr>
<td>N/A</td>
<td><code>comments</code></td>
<td><code>App.CommentsController</code></td>
<td><code>App.CommentsRoute</code></td>
<td><code>comments</code></td>
</tr>
<tr>
<td><code>/post/:post_id/comments</code></td>
<td><code>comments.index</code></td>
<td><code>App.CommentsIndexController</code></td>
<td><code>App.CommentsIndexRoute</code></td>
<td><code>comments/index</code></td>
</tr>
<tr>
<td><code>/post/:post_id/comments/new</code></td>
<td><code>comments.new</code></td>
<td><code>App.CommentsNewController</code></td>
<td><code>App.CommentsNewRoute</code></td>
<td><code>comments/new</code></td>
</tr>
</table>
</div>
<small><sup>2</sup> `:post_id` is the post's id. For a post with id = 1, the route will be:
`/post/1`</small>
The `comments` template will be rendered in the `post` outlet.
All templates under `comments` (`comments/index` and `comments/new`) will be rendered in the `comments` outlet.
You are also able to create deeply nested resources in order to preserve the namespace on your routes:
```javascript
App.Router.map(function() {
this.resource('foo', function() {
this.resource('foo.bar', { path: '/bar' }, function() {
this.route('baz'); // This will be foo.bar.baz
});
});
});
```
This router creates the following routes:
<div style="overflow: auto">
<table>
<thead>
<tr>
<th>URL</th>
<th>Route Name</th>
<th>Controller</th>
<th>Route</th>
<th>Template</th>
</tr>
</thead>
<tr>
<td><code>/</code></td>
<td><code>index</code></td>
<td><code>App.IndexController</code></td>
<td><code>App.IndexRoute</code></td>
<td><code>index</code></td>
</tr>
<tr>
<td><code>/foo</code></td>
<td><code>foo.index</code></td>
<td><code>App.FooIndexController</code></td>
<td><code>App.FooIndexRoute</code></td>
<td><code>foo/index</code></td>
</tr>
<tr>
<td><code>/foo/bar</code></td>
<td><code>foo.bar.index</code></td>
<td><code>App.FooBarIndexController</code></td>
<td><code>App.FooBarIndexRoute</code></td>
<td><code>foo/bar/index</code></td>
</tr>
<tr>
<td><code>/foo/bar/baz</code></td>
<td><code>foo.bar.baz</code></td>
<td><code>App.FooBarBazController</code></td>
<td><code>App.FooBarBazRoute</code></td>
<td><code>foo/bar/baz</code></td>
</tr>
</table>
</div>
### Initial routes
A few routes are immediately available within your application:
- `App.ApplicationRoute` is entered when your app first boots up. It renders
the `application` template.
- `App.IndexRoute` is the default route, and will render the `index` template
when the user visits `/` (unless `/` has been overridden by your own
custom route).
Remember, these routes are part of every application, so you don't need to
specify them in `App.Router.map`.
## Generated Objects
As explained in the [routing guide][1], whenever you define a new route,
Ember.js attempts to find corresponding Route, Controller, View, and Template
classes named according to naming conventions. If an implementation of any of
these objects is not found, appropriate objects will be generated in memory for you.
[1]: /guides/routing/defining-your-routes
#### Generated routes
Given you have the following route:
```javascript
App.Router.map(function() {
this.route('posts');
});
```
When you navigate to `/posts`, Ember.js looks for `App.PostsRoute`.
If it doesn't find it, it will automatically generate an `App.PostsRoute` for you.
##### Custom Generated Routes
You can have all your generated routes extend a custom route. If you define `App.Route`,
all generated routes will be instances of that route.
#### Generated Controllers
If you navigate to route `posts`, Ember.js looks for a controller called `App.PostsController`.
If you did not define it, one will be generated for you.
Ember.js can generate three types of controllers:
`Ember.ObjectController`, `Ember.ArrayController`, and `Ember.Controller`.
The type of controller Ember.js chooses to generate for you depends on your route's
`model` hook:
- If it returns an object (such as a single record), an [ObjectController][2] will be generated.
- If it returns an array, an [ArrayController][3] will be generated.
- If it does not return anything, an instance of `Ember.Controller` will be generated.
[2]: /guides/controllers/representing-a-single-model-with-objectcontroller
[3]: /guides/controllers/representing-multiple-models-with-arraycontroller
##### Custom Generated Controllers
If you want to customize generated controllers, you can define your own `App.Controller`, `App.ObjectController`
and `App.ArrayController`. Generated controllers will extend one of these three (depending on the conditions above).
#### Generated Views and Templates
A route also expects a view and a template. If you don't define a view,
a view will be generated for you.
A generated template is empty.
If it's a resource template, the template will simply act
as an `outlet` so that nested routes can be seamlessly inserted. It is equivalent to:
```handlebars
{{outlet}}
```
## Specifying a Route's Model
Templates in your application are backed by models. But how do templates
know which model they should display?
For example, if you have a `photos` template, how does it know which
model to render?
This is one of the jobs of an `Ember.Route`. You can tell a template
which model it should render by defining a route with the same name as
the template, and implementing its `model` hook.
For example, to provide some model data to the `photos` template, we
would define an `App.PhotosRoute` object:
```js
App.PhotosRoute = Ember.Route.extend({
model: function() {
return [{
title: "Tomster",
url: "http://emberjs.com/images/about/ember-productivity-sm.png"
}, {
title: "Eiffel Tower",
url: "http://emberjs.com/images/about/ember-structure-sm.png"
}];
}
});
```
### Asynchronously Loading Models
In the above example, the model data was returned synchronously from the
`model` hook. This means that the data was available immediately and
your application did not need to wait for it to load, in this case
because we immediately returned an array of hardcoded data.
Of course, this is not always realistic. Usually, the data will not be
available synchronously, but instead must be loaded asynchronously over
the network. For example, we may want to retrieve the list of photos
from a JSON API available on our server.
In cases where data is available asynchronously, you can just return a
promise from the `model` hook, and Ember will wait until that promise is
resolved before rendering the template.
If you're unfamiliar with promises, the basic idea is that they are
objects that represent eventual values. For example, if you use jQuery's
`getJSON()` method, it will return a promise for the JSON that is
eventually returned over the network. Ember uses this promise object to
know when it has enough data to continue rendering.
For more about promises, see [A Word on
Promises](/guides/routing/asynchronous-routing/#toc_a-word-on-promises)
in the Asynchronous Routing guide.
Let's look at an example in action. Here's a route that loads the most
recent pull requests sent to Ember.js on GitHub:
```js
App.PullRequestsRoute = Ember.Route.extend({
model: function() {
return Ember.$.getJSON('https://api.github.com/repos/emberjs/ember.js/pulls');
}
});
```
While this example looks like it's synchronous, making it easy to read
and reason about, it's actually completely asynchronous. That's because
jQuery's `getJSON()` method returns a promise. Ember will detect the
fact that you've returned a promise from the `model` hook, and wait
until that promise resolves to render the `pullRequests` template.
(For more information on jQuery's XHR functionality, see
[jQuery.ajax](http://api.jquery.com/jQuery.ajax/) in the jQuery
documentation.)
Because Ember supports promises, it can work with any persistence
library that uses them as part of its public API. You can also use many
of the conveniences built in to promises to make your code even nicer.
For example, imagine if we wanted to modify the above example so that
the template only displayed the three most recent pull requests. We can
rely on promise chaining to modify the data returned from the JSON
request before it gets passed to the template:
```js
App.PullRequestsRoute = Ember.Route.extend({
model: function() {
var url = 'https://api.github.com/repos/emberjs/ember.js/pulls';
return Ember.$.getJSON(url).then(function(data) {
return data.splice(0, 3);
});
}
});
```
### Setting Up Controllers with the Model
So what actually happens with the value you return from the `model`
hook?
By default, the value returned from your `model` hook will be assigned
to the `model` property of the associated controller. For example, if your
`App.PostsRoute` returns an object from its `model` hook, that object
will be set as the `model` property of the `App.PostsController`.
(This, under the hood, is how templates know which model to render: they
look at their associated controller's `model` property. For example, the
`photos` template will render whatever the `App.PhotosController`'s
`model` property is set to.)
See the [Setting Up a Controller guide][1] to learn how to change this
default behavior. Note that if you override the default behavior and do
not set the `model` property on a controller, your template will not
have any data to render!
[1]: /guides/routing/setting-up-a-controller
### Dynamic Models
Some routes always display the same model. For example, the `/photos`
route will always display the same list of photos available in the
application. If your user leaves this route and comes back later, the
model does not change.
However, you will often have a route whose model will change depending
on user interaction. For example, imagine a photo viewer app. The
`/photos` route will render the `photos` template with the list of
photos as the model, which never changes. But when the user clicks on a
particular photo, we want to display that model with the `photo`
template. If the user goes back and clicks on a different photo, we want
to display the `photo` template again, this time with a different model.
In cases like this, it's important that we include some information in
the URL about not only which template to display, but also which model.
In Ember, this is accomplished by defining routes with _dynamic segments_.
A dynamic segment is a part of the URL that is filled in by the current
model's ID. Dynamic segments always start with a colon (`:`). Our photo
example might have its `photo` route defined like this:
```js
App.Router.map(function() {
this.resource('photo', { path: '/photos/:photo_id' });
});
```
In this example, the `photo` route has a dynamic segment `:photo_id`.
When the user goes to the `photo` route to display a particular photo
model (usually via the `{{link-to}}` helper), that model's ID will be
placed into the URL automatically.
See [Links](/guides/templates/links) for more information about linking
to a route with a model using the `{{link-to}}` helper.
For example, if you transitioned to the `photo` route with a model whose
`id` property was `47`, the URL in the user's browser would be updated
to:
```
/photos/47
```
What happens if the user visits your application directly with a URL
that contains a dynamic segment? For example, they might reload the
page, or send the link to a friend, who clicks on it. At that point,
because we are starting the application up from scratch, the actual
JavaScript model object to display has been lost; all we have is the ID
from the URL.
Luckily, Ember will extract any dynamic segments from the URL for
you and pass them as a hash to the `model` hook as the first argument:
```js
App.Router.map(function() {
this.resource('photo', { path: '/photos/:photo_id' });
});
App.PhotoRoute = Ember.Route.extend({
model: function(params) {
return Ember.$.getJSON('/photos/'+params.photo_id);
}
});
```
In the `model` hook for routes with dynamic segments, it's your job to
turn the ID (something like `47` or `post-slug`) into a model that can
be rendered by the route's template. In the above example, we use the
photo's ID (`params.photo_id`) to construct a URL for the JSON
representation of that photo. Once we have the URL, we use jQuery to
return a promise for the JSON model data.
Note: A route with a dynamic segment will only have its `model` hook called
when it is entered via the URL. If the route is entered through a transition
(e.g. when using the [link-to][2] Handlebars helper), then a model context is
already provided and the hook is not executed. Routes without dynamic segments
will always execute the model hook.
[2]: /guides/templates/links
### Ember Data
Many Ember developers use a model library to make finding and saving
records easier than manually managing Ajax calls. In particular, using a
model library allows you to cache records that have been loaded,
significantly improving the performance of your application.
One popular model library built for Ember is Ember Data. To learn more
about using Ember Data to manage your models, see the
[Models](/guides/models) guide.
## Setting Up a Controller
Changing the URL may also change which template is displayed on
screen. Templates, however, are usually only useful if they have some
source of information to display.
In Ember.js, a template retrieves information to display from a
controller.
Two built-in controllers—`Ember.ObjectController` and
`Ember.ArrayController`—make it easy for a controller to present a
model's properties to a template, along with any additional
display-specific properties.
To tell one of these controllers which model to present, set its
`model` property in the route handler's `setupController` hook.
```js
App.Router.map(function() {
this.resource('post', { path: '/posts/:post_id' });
});
App.PostRoute = Ember.Route.extend({
// The code below is the default behavior, so if this is all you
// need, you do not need to provide a setupController implementation
// at all.
setupController: function(controller, model) {
controller.set('model', model);
}
});
```
The `setupController` hook receives the route handler's associated
controller as its first argument. In this case, the `PostRoute`'s
`setupController` receives the application's instance of
`App.PostController`.
As a second argument, it receives the route handler's model. For more
information, see [Specifying a Route's Model][1].
[1]: /guides/routing/specifying-a-routes-model
The default `setupController` hook sets the `model` property of the
associated controller to the route handler's model.
If you want to configure a controller other than the controller
associated with the route handler, use the `controllerFor` method:
```js
App.PostRoute = Ember.Route.extend({
setupController: function(controller, model) {
this.controllerFor('topPost').set('model', model);
}
});
```
## Rendering a Template
One of the most important jobs of a route handler is rendering the
appropriate template to the screen.
By default, a route handler will render the template into the closest
parent with a template.
```js
App.Router.map(function() {
this.resource('posts');
});
App.PostsRoute = Ember.Route.extend();
```
If you want to render a template other than the one associated with the
route handler, implement the `renderTemplate` hook:
```js
App.PostsRoute = Ember.Route.extend({
renderTemplate: function() {
this.render('favoritePost');
}
});
```
If you want to use a different controller than the route handler's
controller, pass the controller's name in the `controller` option:
```js
App.PostsRoute = Ember.Route.extend({
renderTemplate: function() {
this.render({ controller: 'favoritePost' });
}
});
```
Ember allows you to name your outlets. For instance, this code allows
you to specify two outlets with distinct names:
```handlebars
<div class="toolbar">{{outlet toolbar}}</div>
<div class="sidebar">{{outlet sidebar}}</div>
```
So, if you want to render your posts into the `sidebar` outlet, use code
like this:
```js
App.PostsRoute = Ember.Route.extend({
renderTemplate: function() {
this.render({ outlet: 'sidebar' });
}
});
```
All of the options described above can be used together in whatever
combination you'd like:
```js
App.PostsRoute = Ember.Route.extend({
renderTemplate: function() {
var controller = this.controllerFor('favoritePost');
// Render the `favoritePost` template into
// the outlet `posts`, and display the `favoritePost`
// controller.
this.render('favoritePost', {
outlet: 'posts',
controller: controller
});
}
});
```
If you want to render two different templates into outlets of two different rendered templates of a route:
```js
App.PostRoute = App.Route.extend({
renderTemplate: function() {
this.render('favoritePost', { // the template to render
into: 'posts', // the route to render into
outlet: 'posts', // the name of the outlet in the route's template
controller: 'blogPost' // the controller to use for the template
});
this.render('comments', {
into: 'favoritePost',
outlet: 'comment',
controller: 'blogPost'
});
}
});
```
## Redirecting
### Transitioning and Redirecting
Calling `transitionTo` from a route or `transitionToRoute` from a controller
will stop any transition currently in progress and start a new one, functioning
as a redirect. `transitionTo` takes parameters and behaves exactly like the [link-to](/guides/templates/links) helper:
* If you transition into a route without dynamic segments that route's `model` hook
will always run.
* If the new route has dynamic segments, you need to pass either a _model_ or an _identifier_ for each segment.
Passing a model will skip that segment's `model` hook. Passing an identifier will run the `model` hook and you'll be able to access the identifier in the params. See [Links](/guides/templates/links) for more detail.
### Before the model is known
If you want to redirect from one route to another, you can do the transition in
the `beforeModel` hook of your route handler.
```javascript
App.Router.map(function() {
this.resource('posts');
});
App.IndexRoute = Ember.Route.extend({
beforeModel: function() {
this.transitionTo('posts');
}
});
```
### After the model is known
If you need some information about the current model in order to decide about
the redirection, you should either use the `afterModel` or the `redirect` hook. They
receive the resolved model as the first parameter and the transition as the second one,
and thus function as aliases. (In fact, the default implementation of `afterModel` just calls `redirect`.)
```javascript
App.Router.map(function() {
this.resource('posts');
this.resource('post', { path: '/post/:post_id' });
});
App.PostsRoute = Ember.Route.extend({
afterModel: function(posts, transition) {
if (posts.get('length') === 1) {
this.transitionTo('post', posts[0]);
}
}
});
```
When transitioning to the `PostsRoute` if it turns out that there is only one post,
the current transition will be aborted in favor of redirecting to the `PostRoute`
with the single post object being its model.
### Based on other application state
You can conditionally transition based on some other application state.
```javascript
App.Router.map(function() {
this.resource('topCharts', function() {
this.route('choose', { path: '/' });
this.route('albums');
this.route('songs');
this.route('artists');
this.route('playlists');
});
});
App.TopChartsChooseRoute = Ember.Route.extend({
beforeModel: function() {
var lastFilter = this.controllerFor('application').get('lastFilter');
this.transitionTo('topCharts.' + (lastFilter || 'songs'));
}
});
// Superclass to be used by all of the filter routes below
App.FilterRoute = Ember.Route.extend({
activate: function() {
var controller = this.controllerFor('application');
controller.set('lastFilter', this.templateName);
}
});
App.TopChartsSongsRoute = App.FilterRoute.extend();
App.TopChartsAlbumsRoute = App.FilterRoute.extend();
App.TopChartsArtistsRoute = App.FilterRoute.extend();
App.TopChartsPlaylistsRoute = App.FilterRoute.extend();
```
In this example, navigating to the `/` URL immediately transitions into
the last filter URL that the user was at. The first time, it transitions
to the `/songs` URL.
Your route can also choose to transition only in some cases. If the
`beforeModel` hook does not abort or transition to a new route, the remaining
hooks (`model`, `afterModel`, `setupController`, `renderTemplate`) will execute
as usual.
## Specifying the URL Type
By default the Router uses the browser's hash to load the starting state of your
application and will keep it in sync as you move around. At present, this relies
on a [hashchange](http://caniuse.com/hashchange) event existing in the browser.
Given the following router, entering `/#/posts/new` will take you to the `posts.new`
route.
```javascript
App.Router.map(function() {
this.resource('posts', function() {
this.route('new');
});
});
```
If you want `/posts/new` to work instead, you can tell the Router to use the browser's
[history](http://caniuse.com/history) API.
Keep in mind that your server must serve the Ember app at all the routes defined here.
```js
App.Router.reopen({
location: 'history'
});
```
Finally, if you don't want the browser's URL to interact with your application
at all, you can disable the location API entirely. This is useful for
testing, or when you need to manage state with your Router, but temporarily
don't want it to muck with the URL (for example when you embed your
application in a larger page).
```js
App.Router.reopen({
location: 'none'
});
```
## Query Parameters
In general, the dynamic segments of a URL are a serialized representation
of a model, commonly a model's ID. However, sometimes you
need to serialize other application state into the URL. This could be
further parameters that affect the loading of the model from the server,
e.g. what page of a result set you are viewing, or it could be
information about client side state, e.g. sort order when the records
are sorted on the client.
There can also be more global information that you want to serialize into
the url, for example if you want to store an auth token in the URL, or
filter all models in your application globally. It's also possible that
there are a lot of parameters that you want to serialize in the url that
are inconvenient to store in normal dynamic segments. This might apply
when you have a map view and need to store X, Y, and zoom coordinates
along with a set of visible layers on the map. Although this is possible
to do with dynamic segments, it can be inconvenient. For any of these use
cases, you can consider using query params instead.
### Query Parameters are Controller-Driven
Support for query parameters is built right into controllers, unlike
other aspects of the URL which are specified and managed entirely at
the router level. First class support for query params at the
controller level allows for a simple yet powerful API for updating and
responding to changes in query params without requiring the developer to
manually install and manage bindings/observers to keep the URL and
controller state in sync.
### Specifying Query Parameters
Query params can be specified by route-driven controllers. Recall that,
given a route specified by `this.route('articles');`, the value resolved
from the `ArticlesRoute`'s `model` hook will be loaded into
`ArticlesController` as its `model` property. While `ArticlesRoute` has
the option of loading data into different controllers in the
`setupController` hook, `ArticlesController` is considered to be the
"route-driven" controller in this case, and therefore has the ability to
specify query params.
<aside>
**Note:** The controller associated with a given route can be changed
by specifying the `controllerName` property on that route.
</aside>
Let's say we'd like to add a `category`
query parameter that will filter out all the articles that haven't
been categorized as popular. To do this, we specify `'category'`
as one of `ArticlesController`'s `queryParams`:
```js
App.ArticlesController = Ember.ArrayController.extend({
queryParams: ['category'],
category: null
});
```
This sets up a binding between the `category` query param in the URL,
and the `category` property on `ArticlesController`. In other words,
once the `articles` route has been entered, any changes to the
`category` query param in the URL will update the `category` property
on `ArticlesController`, and vice versa.
Now we just need to define a computed property of our category-filtered
array that `articles` template will render:
```js
App.ArticlesController = Ember.ArrayController.extend({
queryParams: ['category'],
category: null,
filteredArticles: function() {
var category = this.get('category');
var articles = this.get('model');
if (category) {
return articles.filterProperty('category', category);
} else {
return articles;
}
}.property('category', 'model')
});
```
With this code, we have established the following behaviors:
1. If the user navigates to `/articles`, `category` will be `null`, so
the articles won't be filtered.
2. If the user navigates to `/articles?articles[category]=recent`,
`category` will be set to `"recent"`, so articles will be filtered.
3. Once inside the `articles` route, any changes to the `category`
property on `ArticlesController` will cause the URL to update the
query param. By default, a query param property change won't cause a
full router transition (i.e. it won't call `model` hooks and
`setupController`, etc.); it will only update the URL.
### link-to Helper
The `link-to` helper supports specifying query params by way of the
`query-params` subexpression helper.
```handlebars
// Explicitly set target query para
{{#link-to 'posts' (query-params direction="asc")}}Sort{{/link-to}}
// Binding is also supported
{{#link-to 'posts' (query-params direction=otherDirection)}}Sort{{/link-to}}
```
In the above examples, `direction` is presumably a query param property
on `PostsController`, but it could also refer to a `direction` property
on any of the controllers associated with the `posts` route hierarchy,
matching the leaf-most controller with the supplied property name.
<aside>
**Note:** Subexpressions are only available in Handlebars 1.3
or later.
</aside>
The link-to helper takes into account query parameters when determining
its "active" state, and will set the class appropriately. The active state
is determined by working out if you clicked on the link, would the query
params end up the same? You don't have to supply all of the current,
active query params for this to be true.
### transitionTo
`Route#transitionTo` (and `Controller#transitionToRoute`) now
accepts a final argument, which is an object with
the key `queryParams`.
```javascript
this.transitionTo('post', object, {queryParams: {showDetails: true}});
this.transitionTo('posts', {queryParams: {sort: 'title'}});
// if you just want to transition the query parameters without changing the route
this.transitionTo({queryParams: {direction: 'asc'}});
```
You can also add query params to URL transitions:
```javascript
this.transitionTo("/posts/1?sort=date&showDetails=true");
```
### Opting into a full transition
Keep in mind that if the arguments provided to `transitionTo`
or `link-to` only correspond to a change in query param values,
and not a change in the route hierarchy, it is not considered a
full transition, which means that hooks like `model` and
`setupController` won't fire by default, but rather only
controller properties will be updated with new query param values, as
will the URL.
But some query param changes necessitate loading data from the server,
in which case it is desirable to opt into a full-on transition. To opt
into a full transition when a controller query param property changes,
you can use the optional `queryParams` configuration hash on the `Route`
associated with that controller, and set that query param's
`refreshModel` config property to `true`:
```js
App.ArticlesRoute = Ember.Route.extend({
queryParams: {
category: {
refreshModel: true
}
},
model: function(params) {
// This gets called upon entering 'articles' route
// for the first time, and we opt in refiring it
// upon query param changes via `queryParamsDidChange` action
// params has format of { category: "someValueOrJustNull" },
// which we can just forward to the server.
return this.store.findQuery('articles', params);
}
});
App.ArticlesController = Ember.ArrayController.extend({
queryParams: ['category'],
category: null
});
```
### Update URL with `replaceState` instead
By default, Ember will use `pushState` to update the URL in the
address bar in response to a controller query param property change, but
if you would like to use `replaceState` instead (which prevents an
additional item from being added to your browser's history), you can
specify this on the `Route`'s `queryParams` config hash, e.g. (continued
from the example above):
```js
App.ArticlesRoute = Ember.Route.extend({
queryParams: {
category: {
replace: true
}
}
});
```
Note that the name of this config property and its default value of
`false` is similar to the `link-to` helper's, which also lets
you opt into a `replaceState` transition via `replace=true`.
### Map a controller's property to a different query param key
By default, specifying `foo` as a controller query param property will
bind to a query param whose key is `foo`, e.g. `?foo=123`. You can also map
a controller property to a different query param key using an optional
colon syntax similar to the `classNameBindings` syntax
[demonstrated here](/guides/views/customizing-a-views-element/).
```js
App.ArticlesController = Ember.ArrayController.extend({
queryParams: ['category:articles_category'],
category: null
});
```
This will cause changes to the `ArticlesController`'s `category`
property to update the `articles_category` query param, and vice versa.
### Default values and deserialization
In the following example, the controller query param property `page` is
considered to have a default value of `1`.
```js
App.ArticlesController = Ember.ArrayController.extend({
queryParams: 'page',
page: 1
});
```
This affects query param behavior in two ways:
1. The type of the default value is used to cast changed query param
values in the URL before setting values on the controller. So, given
the above example, if the user clicks the back button to change from
`/?page=3` to `/?page=2`, Ember will update the `page` controller
property to the properly cast number `2` rather than the string `"2"`, which it
knows to do because the default value (`1`) is a number. This also
allows boolean default values to be correctly cast when deserializing
from URL changes.
2. When a controller's query param property is currently set to its
default value, this value won't be serialized into the URL. So in the
above example, if `page` is `1`, the URL might look like `/articles`,
but once someone sets the controller's `page` value to `2`, the URL
will become `/articles?page=2`.
## Examples
- [Search queries](http://emberjs.jsbin.com/ucanam/4059)
- [Sort: client-side, no refiring of model hook](http://emberjs.jsbin.com/ucanam/2937)
- [Sort: server-side, refire model hook](http://emberjs.jsbin.com/ucanam/4073)
- [Pagination + Sorting](http://emberjs.jsbin.com/ucanam/4075)
- [Boolean values](http://emberjs.jsbin.com/ucanam/4076/edit)
- [Global query params on app route](http://emberjs.jsbin.com/ucanam/4077/edit)
- [Opt-in to full transition via refreshModel:true](http://emberjs.jsbin.com/ucanam/4079/edit)
- [opt into replaceState via replace:true](http://emberjs.jsbin.com/ucanam/4080/edit)
- [w/ {{partial}} helper for easy tabbing](http://emberjs.jsbin.com/ucanam/4081)
- [link-to with no route name, only QP change](http://emberjs.jsbin.com/ucanam/4082#/about?showThing=true)
- [Complex: serializing textarea content into URL (and subexpressions))](http://emberjs.jsbin.com/ucanam/4083/edit)
- [Arrays](http://emberjs.jsbin.com/ucanam/4084)
- [Map to different URL key with colon syntax](http://emberjs.jsbin.com/ucanam/4090/edit)
## Asynchronous Routing
This section covers some more advanced features of the router and its
capability for handling complex async logic within your app.
### A Word on Promises...
Ember's approach to handling asynchronous logic in the router makes
heavy use of the concept of Promises. In short, promises are objects that
represent an eventual value. A promise can either _fulfill_
(successfully resolve the value) or _reject_ (fail to resolve the
value). The way to retrieve this eventual value, or handle the cases
when the promise rejects, is via the promise's `then` method, which
accepts two optional callbacks, one for fulfillment and one for
rejection. If the promise fulfills, the fulfillment handler gets called
with the fulfilled value as its sole argument, and if the promise rejects,
the rejection handler gets called with a reason for the rejection as its
sole argument. For example:
```js
var promise = fetchTheAnswer();
promise.then(fulfill, reject);
function fulfill(answer) {
console.log("The answer is " + answer);
}
function reject(reason) {
console.log("Couldn't get the answer! Reason: " + reason);
}
```
Much of the power of promises comes from the fact that they can be
chained together to perform sequential asynchronous operations:
```js
// Note: jQuery AJAX methods return promises
var usernamesPromise = Ember.$.getJSON('/usernames.json');
usernamesPromise.then(fetchPhotosOfUsers)
.then(applyInstagramFilters)
.then(uploadTrendyPhotoAlbum)
.then(displaySuccessMessage, handleErrors);
```
In the above example, if any of the methods
`fetchPhotosOfUsers`, `applyInstagramFilters`, or
`uploadTrendyPhotoAlbum` returns a promise that rejects,
`handleErrors` will be called with
the reason for the failure. In this manner, promises approximate an
asynchronous form of try-catch statements that prevent the rightward
flow of nested callback after nested callback and facilitate a saner
approach to managing complex asynchronous logic in your applications.
This guide doesn't intend to fully delve into all the different ways
promises can be used, but if you'd like a more thorough introduction,
take a look at the readme for [RSVP](https://github.com/tildeio/rsvp.js),
the promise library that Ember uses.
### The Router Pauses for Promises
When transitioning between routes, the Ember router collects all of the
models (via the `model` hook) that will be passed to the route's
controllers at the end of the transition. If the `model` hook (or the related
`beforeModel` or `afterModel` hooks) return normal (non-promise) objects or
arrays, the transition will complete immediately. But if the `model` hook
(or the related `beforeModel` or `afterModel` hooks) returns a promise (or
if a promise was provided as an argument to `transitionTo`), the transition
will pause until that promise fulfills or rejects.
<aside>
**Note:** The router considers any object with a `then` method
defined on it to be a promise.
</aside>
If the promise fulfills, the transition will pick up where it left off and
begin resolving the next (child) route's model, pausing if it too is a
promise, and so on, until all destination route models have been
resolved. The values passed to the `setupController` hook for each route
will be the fulfilled values from the promises.
A basic example:
```js
App.TardyRoute = Ember.Route.extend({
model: function() {
return new Ember.RSVP.Promise(function(resolve) {
Ember.run.later(function() {
resolve({ msg: "Hold Your Horses" });
}, 3000);
});
},
setupController: function(controller, model) {
console.log(model.msg); // "Hold Your Horses"
}
});
```
When transitioning into `TardyRoute`, the `model` hook will be called and
return a promise that won't resolve until 3 seconds later, during which time
the router will be paused in mid-transition. When the promise eventually
fulfills, the router will continue transitioning and eventually call
`TardyRoute`'s `setupController` hook with the resolved object.
This pause-on-promise behavior is extremely valuable for when you need
to guarantee that a route's data has fully loaded before displaying a
new template.
### When Promises Reject...
We've covered the case when a model promise fulfills, but what if it rejects?
By default, if a model promise rejects during a transition, the transition is
aborted, no new destination route templates are rendered, and an error
is logged to the console.
You can configure this error-handling logic via the `error` handler on
the route's `actions` hash. When a promise rejects, an `error` event
will be fired on that route and bubble up to `ApplicationRoute`'s
default error handler unless it is handled by a custom error handler
along the way, e.g.:
```js
App.GoodForNothingRoute = Ember.Route.extend({
model: function() {
return Ember.RSVP.reject("FAIL");
},
actions: {
error: function(reason) {
alert(reason); // "FAIL"
// Can transition to another route here, e.g.
// this.transitionTo('index');
// Uncomment the line below to bubble this error event:
// return true;
}
}
});
```
In the above example, the error event would stop right at
`GoodForNothingRoute`'s error handler and not continue to bubble. To
make the event continue bubbling up to `ApplicationRoute`, you can
return true from the error handler.
### Recovering from Rejection
Rejected model promises halt transitions, but because promises are chainable,
you can catch promise rejects within the `model` hook itself and convert
them into fulfills that won't halt the transition.
```js
App.FunkyRoute = Ember.Route.extend({
model: function() {
return iHopeThisWorks().then(null, function() {
// Promise rejected, fulfill with some default value to
// use as the route's model and continue on with the transition
return { msg: "Recovered from rejected promise" };
});
}
});
```
### beforeModel and afterModel
The `model` hook covers many use cases for pause-on-promise transitions,
but sometimes you'll need the help of the related hooks `beforeModel`
and `afterModel`. The most common reason for this is that if you're
transitioning into a route with a dynamic URL segment via `{{link-to}}` or
`transitionTo` (as opposed to a transition caused by a URL change),
the model for the route you're transitioning into will have already been
specified (e.g. `{{#link-to 'article' article}}` or
`this.transitionTo('article', article)`), in which case the `model` hook
won't get called. In these cases, you'll need to make use of either
the `beforeModel` or `afterModel` hook to house any logic while the
router is still gathering all of the route's models to perform a
transition.
#### `beforeModel`
Easily the more useful of the two, the `beforeModel` hook is called
before the router attempts to resolve the model for the given route. In
other words, it is called before the `model` hook gets called, or, if
`model` doesn't get called, it is called before the router attempts to
resolve any model promises passed in for that route.
Like `model`, returning a promise from `beforeModel` will pause the
transition until it resolves, or will fire an `error` if it rejects.
The following is a far-from-exhaustive list of use cases in which
`beforeModel` is very handy:
- Deciding whether to redirect to another route before performing a
potentially wasteful server query in `model`
- Ensuring that the user has an authentication token before proceeding
onward to `model`
- Loading application code required by this route
```js
App.SecretArticlesRoute = Ember.Route.extend({
beforeModel: function() {
if (!this.controllerFor('auth').get('isLoggedIn')) {
this.transitionTo('login');
}
}
});
```
[See the API Docs for `beforeModel`](/api/classes/Ember.Route.html#method_beforeModel)
#### `afterModel`
The `afterModel` hook is called after a route's model (which might be a
promise) is resolved, and follows the same pause-on-promise semantics as
`model` and `beforeModel`. It is passed the already-resolved model
and can therefore perform any additional logic that
depends on the fully resolved value of a model.
```js
App.ArticlesRoute = Ember.Route.extend({
model: function() {
// App.Article.find() returns a promise-like object
// (it has a `then` method that can be used like a promise)
return App.Article.find();
},
afterModel: function(articles) {
if (articles.get('length') === 1) {
this.transitionTo('article.show', articles.get('firstObject'));
}
}
});
```
You might be wondering why we can't just put the `afterModel` logic
into the fulfill handler of the promise returned from `model`; the
reason, as mentioned above, is that transitions initiated
via `{{link-to}}` or `transitionTo` likely already provided the
model for this route, so `model` wouldn't be called in these cases.
[See the API Docs for `afterModel`](/api/classes/Ember.Route.html#method_afterModel)
### More Resources
- [Embercasts: Client-side Authentication Part 2](http://www.embercasts.com/episodes/client-side-authentication-part-2)
- [RC6 Blog Post describing these new features](/blog/2013/06/23/ember-1-0-rc6.html)
## Loading / Error Substates
In addition to the techniques described in the
[Asynchronous Routing Guide](http://emberjs.com/guides/routing/asynchronous-routing/),
the Ember Router provides powerful yet overridable
conventions for customizing asynchronous transitions
between routes by making use of `error` and `loading`
substates.
## `loading` substates
Consider the following:
```js
App.Router.map(function() {
this.resource('articles', function() { // -> ArticlesRoute
this.route('overview'); // -> ArticlesOverviewRoute
});
});
```
If you navigate to `articles/overview`, and in `ArticlesRoute#model`,
you return an AJAX query promise to load all of
the articles that takes a long time to complete.
During this time, your UI isn't really giving you any feedback as to
what's happening; if you're entering this route after a full page
refresh, your UI will be entirely blank, as you have not actually
finished fully entering any route and haven't yet displayed any
templates; if you're navigating to `articles/overview` from another
route, you'll continue to see the templates from the previous route
until the articles finish loading, and then, boom, suddenly all the
templates for `articles/overview` load.
So, how can we provide some visual feedback during the transition?
### The `loading` event
Before going into detail about loading substates, it's important
to understand the behavior of the `loading` event.
The Ember Router allows you to return promises from the various
`beforeModel`/`model`/`afterModel` hooks in the course of a transition
(described [here](http://emberjs.com/guides/routing/asynchronous-routing/)).
These promises pause the transition until they fulfill, at which point
the transition will resume. If you return a promise from
one of these hooks, and it doesn't immediately resolve, a `loading`
event will be fired on that route and bubble upward to
`ApplicationRoute`. For example:
```js
App.Router.map(function() {
this.resource('foo', function() { // -> FooRoute
this.route('slowModel'); // -> FooSlowModelRoute
});
});
App.FooSlowModelRoute = Ember.Route.extend({
model: function() {
return somePromiseThatTakesAWhileToResolve();
},
actions: {
loading: function(transition, originRoute) {
// displayLoadingSpinner();
// Return true to bubble this event to `FooRoute`
// or `ApplicationRoute`.
return true;
}
}
});
```
If `FooRoute#model` had returned the slow promise, the `loading`
event would have fired on `FooRoute` (and not `FooSlowModelRoute`).
### The default implementation of the `loading` event
So already, you have a hook to allow you to configure loading
behavior in a hierarchical manner. But in addition to this, Ember
provides a default implementation of the `loading` handler that implements
the following loading substate behavior we've been alluding to.
```js
App.Router.map(function() {
this.resource('foo', function() { // -> FooRoute
this.resource('foo.bar', function() { // -> FooBarRoute
this.route('baz'); // -> FooBarBazRoute
});
});
});
```
If a route with the path `foo.bar.baz` returns a promise that doesn't immediately
resolve, Ember will try to find a `loading` route in the hierarchy
above `foo.bar.baz` that it can transition into, starting with
`foo.bar.baz`'s sibling:
1. `foo.bar.loading`
2. `foo.loading`
3. `loading`
Ember will find a loading route at the above location if either a) a
Route subclass has been defined for such a route, e.g.
1. `App.FooBarLoadingRoute`
2. `App.FooLoadingRoute`
3. `App.LoadingRoute`
or b) a properly-named loading template has been found, e.g.
1. `foo/bar/loading`
2. `foo/loading`
3. `loading`
During a slow asynchronous transition, Ember will transition into the
first loading sub-state/route that it finds, if one exists. The
intermediate transition into the loading substate happens immediately
(synchronously), the URL won't be updated, and, unlike other transitions
that happen while another asynchronous transition is active, the
currently active async transition won't be aborted.
After transitioning into a loading substate, the corresponding template
for that substate, if present, will be rendered into the main outlet of
the parent route, e.g. `foo.bar.loading`'s template would render into
`foo.bar`'s outlet. (This isn't particular to loading routes; all
routes behave this way by default.)
Once the main async transition into `foo.bar.baz` completes, the loading
substate will be exited, its template torn down, `foo.bar.baz` will be
entered, and its templates rendered.
### Eager vs. Lazy Async Transitions
Loading substates are optional, but if you provide one,
you are essentially telling Ember that you
want this async transition to be "eager"; in the absence of destination
route loading substates, the router will "lazily" remain on the pre-transition route
while all of the destination routes' promises resolve, and only fully
transition to the destination route (and renders its templates, etc.)
once the transition is complete. But once you provide a destination
route loading substate, you are opting into an "eager" transition, which
is to say that, unlike the "lazy" default, you will eagerly exit the
source routes (and tear down their templates, etc) in order to
transition into this substate.
This has implications on error handling, i.e. when a transition into
another route fails, a lazy transition will (by default) just remain on the
previous route, whereas an eager transition will have already left the
pre-transition route to enter a loading substate.
## `error` substates
Ember provides an analogous approach to `loading` events/substates in
the case of errors encountered during a transition.
```js
App.Router.map(function() {
this.resource('articles', function() { // -> ArticlesRoute
this.route('overview'); // -> ArticlesOverviewRoute
});
});
```
If `ArticlesOverviewRoute#model` returns a promise that rejects (because, for
instance, the server returned an error, or the user isn't logged in,
etc.), an `error` event will fire on `ArticlesOverviewRoute` and bubble upward.
This `error` event can be handled and used to display an error message,
redirect to a login page, etc., but similar to how the default `loading`
event handlers are implemented, the default `error` handlers
will look for an appropriate error substate to
enter, if one can be found.
For instance, an error thrown or rejecting promise returned from
`ArticlesOverviewRoute#model` (or `beforeModel` or `afterModel`)
will look for:
1. Either `ArticlesErrorRoute` or `articles/error` template
2. Either `ErrorRoute` or `error` template
If one of the above is found, the router will immediately transition into
that substate (without updating the URL). The "reason" for the error
(i.e. the exception thrown or the promise reject value) will be passed
to that error state as its `model`.
If no viable error substates can be found, an error message will be
logged.
The only way in which `loading`/`error` substate resolution differs is
that `error` events will continue to bubble above a transition's pivot
route.
## Legacy `LoadingRoute`
Previous versions of Ember (somewhat inadvertently) allowed you to define a global `LoadingRoute`
which would be activated whenever a slow promise was encountered during
a transition and exited upon completion of the transition. Because the
`loading` template rendered as a top-level view and not within an
outlet, it could be used for little more than displaying a loading
spinner during slow transitions. Loading events/substates give you far
more control, but if you'd like to emulate something similar to the legacy
`LoadingRoute` behavior, you could do as follows:
```js
App.LoadingView = Ember.View.extend({
templateName: 'global-loading',
elementId: 'global-loading'
});
App.ApplicationRoute = Ember.Route.extend({
actions: {
loading: function() {
var view = this.container.lookup('view:loading').append();
this.router.one('didTransition', view, 'destroy');
}
}
});
```
[Example JSBin](http://emberjs.jsbin.com/ucanam/3307)
This will, like the legacy `LoadingRoute`, append a top-level view when the
router goes into a loading state, and tear down the view once the
transition finishes.
## Preventing and Retrying Transitions
During a route transition, the Ember Router passes a transition
object to the various hooks on the routes involved in the transition.
Any hook that has access to this transition object has the ability
to immediately abort the transition by calling `transition.abort()`,
and if the transition object is stored, it can be re-attempted at a
later time by calling `transition.retry()`.
### Preventing Transitions via `willTransition`
When a transition is attempted, whether via `{{link-to}}`, `transitionTo`,
or a URL change, a `willTransition` action is fired on the currently
active routes. This gives each active route, starting with the leaf-most
route, the opportunity to decide whether or not the transition should occur.
Imagine your app is in a route that's displaying a complex form for the user
to fill out and the user accidentally navigates backwards. Unless the
transition is prevented, the user might lose all of the progress they
made on the form, which can make for a pretty frustrating user experience.
Here's one way this situation could be handled:
```js
App.FormRoute = Ember.Route.extend({
actions: {
willTransition: function(transition) {
if (this.controllerFor('form').get('userHasEnteredData') &&
!confirm("Are you sure you want to abandon progress?")) {
transition.abort();
} else {
// Bubble the `willTransition` action so that
// parent routes can decide whether or not to abort.
return true;
}
}
}
});
```
### Aborting Transitions Within `model`, `beforeModel`, `afterModel`
The `model`, `beforeModel`, and `afterModel` hooks described in
[Asynchronous Routing](/guides/routing/asynchronous-routing)
each get called with a transition object. This makes it possible for
destination routes to abort attempted transitions.
```js
App.DiscoRoute = Ember.Route.extend({
beforeModel: function(transition) {
if (new Date() < new Date("January 1, 1980")) {
alert("Sorry, you need a time machine to enter this route.");
transition.abort();
}
}
});
```
### Storing and Retrying a Transition
Aborted transitions can be retried at a later time. A common use case
for this is having an authenticated route redirect the user to a login
page, and then redirecting them back to the authenticated route once
they've logged in.
```js
App.SomeAuthenticatedRoute = Ember.Route.extend({
beforeModel: function(transition) {
if (!this.controllerFor('auth').get('userIsLoggedIn')) {
var loginController = this.controllerFor('login');
loginController.set('previousTransition', transition);
this.transitionTo('login');
}
}
});
App.LoginController = Ember.Controller.extend({
actions: {
login: function() {
// Log the user in, then reattempt previous transition if it exists.
var previousTransition = this.get('previousTransition');
if (previousTransition) {
this.set('previousTransition', null);
previousTransition.retry();
} else {
// Default back to homepage
this.transitionToRoute('index');
}
}
}
});
```
# Components
HTML was designed in a time when the browser was a simple document
viewer. Developers building great web apps need something more.
Instead of trying to replace HTML, however, Ember.js embraces it, then adds
powerful new features that modernize it for building web apps.
Currently, you are limited to the tags that are created for you by the
W3C. Wouldn't it be great if you could define your own,
application-specific HTML tags, then implement their behavior using
JavaScript?
That's exactly what components let you do. In fact, it's such a good
idea that the W3C is currently working on the [Custom
Elements](https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/custom/index.html)
spec.
Ember's implementation of components hews as closely to the Web
Components specification as possible. Once Custom Elements are widely
available in browsers, you should be able to easily migrate your Ember
components to the W3C standard and have them be usable by other
frameworks.
This is so important to us that we are working closely with the
standards bodies to ensure our implementation of components matches the
roadmap of the web platform.
To highlight the power of components, here is a short example of turning a blog post into a reusable
`blog-post` custom element that you could use again and again in your
application. Keep reading this section for more details on building
components.
## Defining a Component
To define a component, create a template whose name starts with
`components/`. To define a new component, `{{blog-post}}` for example,
create a `components/blog-post` template.
<aside>
**Note:** Components must have a dash in their name. So `blog-post` is an acceptable name,
but `post` is not. This prevents clashes with current or future HTML element names, and
ensures Ember picks up the components automatically.
</aside>
If you are including your Handlebars templates inside an HTML file via
`<script>` tags, it would look like this:
```handlebars
<script type="text/x-handlebars" id="components/blog-post">
<h1>Blog Post</h1>
<p>Lorem ipsum dolor sit amet.</p>
</script>
```
If you're using build tools, create a Handlebars file at
`templates/components/blog-post.handlebars`.
Having a template whose name starts with `components/` creates a
component of the same name. Given the above template, you can now use the
`{{blog-post}}` custom element:
```handlebars
<h1>My Blog</h1>
{{#each}}
{{blog-post}}
{{/each}}
```
Each component, under the hood, is backed by an element. By default
Ember will use a `<div>` element to contain your component's template.
To learn how to change the element Ember uses for your component, see
[Customizing a Component's
Element](/guides/components/customizing-a-components-element).
### Defining a Component Subclass
Often times, your components will just encapsulate certain snippets of
Handlebars templates that you find yourself using over and over. In
those cases, you do not need to write any JavaScript at all. Just define
the Handlebars template as described above and use the component that is
created.
If you need to customize the behavior of the component you'll
need to define a subclass of `Ember.Component`. For example, you would
need a custom subclass if you wanted to change a component's element,
respond to actions from the component's template, or manually make
changes to the component's element using JavaScript.
Ember knows which subclass powers a component based on its name. For
example, if you have a component called `blog-post`, you would create a
subclass called `App.BlogPostComponent`. If your component was called
`audio-player-controls`, the class name would be
`App.AudioPlayerControlsComponent`.
In other words, Ember will look for a class with the camelized name of
the component, followed by `Component`.
<table>
<thead>
<tr>
<th>Component Name</th>
<th>Component Class</th>
</tr>
</thead>
<tr>
<td><code>blog-post</code></td>
<td><code>App.BlogPostComponent</code></td>
</tr>
<tr>
<td><code>audio-player-controls</code></td>
<td><code>App.AudioPlayerControlsComponent</code></td>
</tr>
</table>
## Passing Properties to a Component
By default a component does not have access to properties in the
template scope in which it is used.
For example, imagine you have a `blog-post` component that is used to
display a blog post:
```handlebars
<script type="text/x-handlebars" id="components/blog-post">
<h1>Component: {{title}}</h1>
<p>Lorem ipsum dolor sit amet.</p>
</script>
```
You can see that it has a `{{title}}` Handlebars expression to print the
value of the `title` property inside the `<h1>`.
Now imagine we have the following template and route:
```js
App.IndexRoute = Ember.Route.extend({
model: function() {
return {
title: "Rails is omakase"
};
}
});
```
```handlebars
{{! index.handlebars }}
<h1>Template: {{title}}</h1>
{{blog-post}}
```
Running this code, you will see that the first `<h1>` (from the outer
template) displays the `title` property, but the second `<h1>` (from
inside the component) is empty.
We can fix this by making the `title` property available to the
component:
```handlebars
{{blog-post title=title}}
```
This will make the `title` property in the outer template scope
available inside the component's template using the same name, `title`.
<script src="http://static.jsbin.com/js/embed.js"></script>
If, in the above example, the model's `title` property was instead
called `name`, we would change the component usage to:
```
{{blog-post title=name}}
```
<script src="http://static.jsbin.com/js/embed.js"></script>
In other words, you are binding a named property from the outer scope to
a named property in the component scope, with the syntax
`componentProperty=outerProperty`.
It is important to note that the value of these properties is bound.
Whether you change the value on the model or inside the component, the
values stay in sync. In the following example, type some text in the
text field either in the outer template or inside the component and note
how they stay in sync.
<script src="http://static.jsbin.com/js/embed.js"></script>
You can also bind properties from inside an `{{#each}}` loop. This will
create a component for each item and bind it to each model in the loop.
```handlebars
{{#each}}
{{blog-post title=title}}
{{/each}}
```
<script src="http://static.jsbin.com/js/embed.js"></script>
## Wrapping Content in a Component
Sometimes, you may want to define a component that wraps content
provided by other templates.
For example, imagine we are building a `blog-post` component that we can
use in our application to display a blog post:
```handlebars
<script type="text/x-handlebars" id="components/blog-post">
<h1>{{title}}</h1>
<div class="body">{{body}}</div>
</script>
```
Now, we can use the `{{blog-post}}` component and pass it properties
in another template:
```handlebars
{{blog-post title=title body=body}}
```
(See [Passing Properties to a
Component](/guides/components/passing-properties-to-a-component/) for
more.)
In this case, the content we wanted to display came from the model. But
what if we want the developer using our component to be able to provide custom
HTML content?
In addition to the simple form you've learned so far, components also
support being used in **block form**. In block form, components can be
passed a Handlebars template that is rendered inside the component's
template wherever the `{{yield}}` expression appears.
To use the block form, add a `#` character to the
beginning of the component name, then make sure to add a closing tag.
(See the Handlebars documentation on [block expressions](http://handlebarsjs.com/#block-expressions) for more.)
In that case, we can use the `{{blog-post}}` component in **block form**
and tell Ember where the block content should be rendered using the
`{{yield}}` helper. To update the example above, we'll first change the component's
template:
```handlebars
<script type="text/x-handlebars" id="components/blog-post">
<h1>{{title}}</h1>
<div class="body">{{yield}}</div>
</script>
```
You can see that we've replaced `{{body}}` with `{{yield}}`. This tells
Ember that this content will be provided when the component is used.
Next, we'll update the template using the component to use the block
form:
```handlebars
{{#blog-post title=title}}
<p class="author">by {{author}}</p>
{{body}}
{{/blog-post}}
```
It's important to note that the template scope inside the component
block is the same as outside. If a property is available in the template
outside the component, it is also available inside the component block.
This JSBin illustrates the concept:
## Customizing a Component's Element
By default, each component is backed by a `<div>` element. If you were
to look at a rendered component in your developer tools, you would see
a DOM representation that looked something like:
```html
<div id="ember180" class="ember-view">
<h1>My Component</h1>
</div>
```
You can customize what type of element Ember generates for your
component, including its attributes and class names, by creating a
subclass of `Ember.Component` in your JavaScript.
### Customizing the Element
To use a tag other than `div`, subclass `Ember.Component` and assign it
a `tagName` property. This property can be any valid HTML5 tag name as a
string.
```js
App.NavigationBarComponent = Ember.Component.extend({
tagName: 'nav'
});
```
```handlebars
{{! templates/components/navigation-bar }}
<ul>
<li>{{#link-to 'home'}}Home{{/link-to}}</li>
<li>{{#link-to 'about'}}About{{/link-to}}</li>
</ul>
```
### Customizing Class Names
You can also specify which class names are applied to the component's
element by setting its `classNames` property to an array of strings:
```javascript
App.NavigationBarComponent = Ember.Component.extend({
classNames: ['primary']
});
```
If you want class names to be determined by properties of the component,
you can use class name bindings. If you bind to a Boolean property, the
class name will be added or removed depending on the value:
```js
App.TodoItemComponent = Ember.Component.extend({
classNameBindings: ['isUrgent'],
isUrgent: true
});
```
This component would render the following:
```html
<div class="ember-view is-urgent"></div>
```
If `isUrgent` is changed to `false`, then the `is-urgent` class name will be removed.
By default, the name of the Boolean property is dasherized. You can customize the class name
applied by delimiting it with a colon:
```javascript
App.TodoItemComponent = Ember.Component.extend({
classNameBindings: ['isUrgent:urgent'],
isUrgent: true
});
```
This would render this HTML:
```html
<div class="ember-view urgent">
```
Besides the custom class name for the value being `true`, you can also specify a class name which is used when the value is `false`:
```javascript
App.TodoItemComponent = Ember.Component.extend({
classNameBindings: ['isEnabled:enabled:disabled'],
isEnabled: false
});
```
This would render this HTML:
```html
<div class="ember-view disabled">
```
You can also specify a class which should only be added when the property is
`false` by declaring `classNameBindings` like this:
```javascript
App.TodoItemComponent = Ember.Component.extend({
classNameBindings: ['isEnabled::disabled'],
isEnabled: false
});
```
This would render this HTML:
```html
<div class="ember-view disabled">
```
If the `isEnabled` property is set to `true`, no class name is added:
```html
<div class="ember-view">
```
If the bound value is a string, that value will be added as a class name without
modification:
```javascript
App.TodoItemComponent = Ember.Component.extend({
classNameBindings: ['priority'],
priority: 'highestPriority'
});
```
This would render this HTML:
```html
<div class="ember-view highestPriority">
```
### Customizing Attributes
You can bind attributes to the DOM element that represents a component
by using `attributeBindings`:
```javascript
App.LinkItemComponent = Ember.Component.extend({
tagName: 'a',
attributeBindings: ['href'],
href: "http://emberjs.com"
});
```
You can also bind these attributes to differently named properties:
```javascript
App.LinkItemComponent = Ember.Component.extend({
tagName: 'a',
attributeBindings: ['customHref:href'],
customHref: "http://emberjs.com"
});
```
### Example
Here is an example todo application that shows completed todos with a
red background:
## Handling User Interaction with Actions
Components allow you to define controls that you can reuse throughout
your application. If they're generic enough, they can also be shared
with others and used in multiple applications.
To make a reusable control useful, however, you first need to allow
users of your application to interact with it.
You can make elements in your component interactive by using the
`{{action}}` helper. This is the [same `{{action}}` helper you use in
application templates](/guides/templates/actions), but it has an
important difference when used inside a component.
Instead of sending an action to the template's controller, then bubbling
up the route hierarchy, actions sent from inside a component are sent
directly to the component's `Ember.Component` instance, and do not
bubble.
For example, imagine the following component that shows a post's title.
When the title is clicked, the entire post body is shown:
```handlebars
<script type="text/x-handlebars" id="components/post-summary">
<h3 {{action "toggleBody"}}>{{title}}</h3>
{{#if isShowingBody}}
<p>{{{body}}}</p>
{{/if}}
</script>
```
```js
App.PostSummaryComponent = Ember.Component.extend({
actions: {
toggleBody: function() {
this.toggleProperty('isShowingBody');
}
}
});
```
The `{{action}}` helper can accept arguments, listen for different event
types, control how action bubbling occurs, and more.
For details about using the `{{action}}` helper, see the [Actions
section](/guides/templates/actions) of the Templates chapter.
## Sending Actions from Components to Your Application
When a component is used inside a template, it has the ability to send
actions to that template's controller and routes. These allow the
component to inform the application when important events, such as the
user clicking a particular element in a component, occur.
Like the `{{action}}` Handlebars helper, actions sent from components
first go to the template's controller. If the controller does not
implement a handler for that action, it will bubble to the template's
route, and then up the route hierarchy. For more information about this
bubbling behavior, see [Action
Bubbling](/guides/templates/actions/#toc_action-bubbling).
Components are designed to be reusable across different parts of your
application. In order to achieve this reusability, it's important that
the actions that your components send be specified when the component is
used in a template.
In other words, if you were writing a button component, you would not
want to send a `click` action, because it is ambiguous and likely to
conflict with other components on the page. Instead, you would want to
allow the person using the component to specify which action to send
when the button was clicked.
Luckily, components have a `sendAction()` method that allows them to
send actions specified when the component is used in a template.
### Sending a Primary Action
Many components only send one kind of action. For example, a button
component might send an action when it is clicked on; this is the
_primary action_.
To set a component's primary action, set its `action` attribute in
Handlebars:
```handlebars
{{my-button action="showUser"}}
```
This tells the `my-button` component that it should send the `showUser`
action when it triggers its primary action.
So how do you trigger sending a component's primary action? After
the relevant event occurs, you can call the `sendAction()` method
without arguments:
```js
App.MyButtonComponent = Ember.Component.extend({
click: function() {
this.sendAction();
}
}
```
In the above example, the `my-button` component will send the `showUser`
action when the component is clicked.
### Sending Parameters with an Action
You may want to provide additional context to the route or controller
handling an action. For example, a button component may want to tell a
controller not only that _an_ item was deleted, but also _which_ item.
To send parameters with the primary action, call `sendAction()` with the
string `'action'` as the first argument and any additional parameters
following it:
```js
this.sendAction('action', param1, param2);
```
For example, imagine we're building a todo list that allows the user to
delete a todo:
```js
App.IndexRoute = Ember.Route.extend({
model: function() {
return {
todos: [{
title: "Learn Ember.js"
}, {
title: "Walk the dog"
}]
};
},
actions: {
deleteTodo: function(todo) {
var todos = this.modelFor('index').todos;
todos.removeObject(todo);
}
}
});
```
```handlebars
{{! index.handlebars }}
{{#each todo in todos}}
<p>{{todo.title}} <button {{action "deleteTodo" todo}}>Delete</button></p>
{{/each}}
```
We want to update this app so that, before actually deleting a todo, the
user must confirm that this is what they intended. We'll implement a
component that first double-checks with the user before completing the
action.
In the component, when triggering the primary action, we'll pass an
additional argument that the component user can specify:
```js
App.ConfirmButtonComponent = Ember.Component.extend({
actions: {
showConfirmation: function() {
this.toggleProperty('isShowingConfirmation');
},
confirm: function() {
this.toggleProperty('isShowingConfirmation');
this.sendAction('action', this.get('param'));
}
}
});
```
```handlebars
{{#if isShowingConfirmation}}
<button {{action "confirm"}}>Click again to confirm</button>
{{else}}
<button {{action "showConfirmation"}}>{{title}}</button>
{{/if}}
```
Now we can update our initial template and replace the `{{action}}`
helper with our new component:
```handlebars
{{#each todo in todos}}
<p>{{todo.title}} {{confirm-button title="Delete" action="deleteTodo" param=todo}}</p>
{{/each}}
```
Note that we've specified the action to send by setting the component's
`action` attribute, and we've specified which argument should be sent as
a parameter by setting the component's `param` attribute.
### Sending Multiple Actions
Depending on the complexity of your component, you may need to let users
specify multiple different actions for different events that your
component can generate.
For example, imagine that you're writing a form component that the user
can either submit or cancel. Depending on which button the user clicks,
you want to send a different action to your controller or route.
You can specify _which_ action to send by passing the name of the event
as the first argument to `sendAction()`. For example, you can specify two
actions when using the form component:
```handlebars
{{user-form submit="createUser" cancel="cancelUserCreation"}}
```
In this case, you can send the `createUser` action by calling
`this.sendAction('submit')`, or send the `cancelUserCreation` action by
calling `this.sendAction('cancel')`.
### Actions That Aren't Specified
If someone using your component does not specify an action for a
particular event, calling `sendAction()` has no effect.
For example, if you define a component that triggers the primary action
on click:
```js
App.MyButtonComponent = Ember.Component.extend({
click: function() {
this.sendAction();
}
});
```
Using this component without assigning a primary action will have no
effect if the user clicks it:
```handlebars
{{my-button}}
```
### Thinking About Component Actions
In general, you should think of component actions as translating a
_primitive event_ (like a mouse click or an `<audio>` element's `pause`
event) into actions that have semantic meaning in your application.
This allows your routes and controllers to implement action handlers
with names like `deleteTodo` or `songDidPause` instead of vague names
like `click` or `pause` that may be ambiguous to other developers when
read out of context.
Another way to think of component actions is as the _public API_ of your
component. Thinking about which events in your component can trigger
actions in their application is the primary way other developers will
use your component. In general, keeping these events as generic as
possible will lead to components that are more flexible and reusable.
# Controllers
## Controllers
In Ember.js, controllers allow you to decorate your models with
display logic. In general, your models will have properties that
are saved to the server, while controllers will have properties
that your app does not need to save to the server.
For example, if you were building a blog, you would have a
`BlogPost` model that you would present in a `blog_post` template.
Your `BlogPost` model would have properties like:
* `title`
* `intro`
* `body`
* `author`
Your template would bind to these properties in the `blog_post`
template:
```handlebars
<h1>{{title}}</h1>
<h2>by {{author}}</h2>
<div class='intro'>
{{intro}}
</div>
<hr>
<div class='body'>
{{body}}
</div>
```
In this simple example, we don't have any display-specific properties
or actions just yet. For now, our controller just acts as a
pass-through (or "proxy") for the model properties. (Remember that
a controller gets the model it represents from its route handler.)
Let's say we wanted to add a feature that would allow the user to
toggle the display of the body section. To implement this, we would
first modify our template to show the body only if the value of a
new `isExpanded` property is true.
```handlebars
<h1>{{title}}</h1>
<h2>by {{author}}</h2>
<div class='intro'>
{{intro}}
</div>
<hr>
{{#if isExpanded}}
<button {{action 'toggleProperty' 'isExpanded'}}>Hide Body</button>
<div class='body'>
{{body}}
</div>
{{else}}
<button {{action 'toggleProperty' 'isExpanded'}}>Show Body</button>
{{/if}}
```
You might think you should put this property on the model, but
whether the body is expanded or not is strictly a display concern.
Putting this property on the controller cleanly separates logic
related to your data model from logic related to what you display
on the screen. This makes it easy to unit-test your model without
having to worry about logic related to your display creeping into
your test setup.
## A Note on Coupling
In Ember.js, templates get their properties from controllers, which
decorate a model.
This means that templates _know about_ controllers and controllers
_know about_ models, but the reverse is not true. A model knows
nothing about which (if any) controllers are decorating it, and
controller does not know which views are presenting its properties.
<figure>
<img src="/images/controller-guide/objects.png">
</figure>
This also means that as far as a template is concerned, all of its
properties come from its controller, and it doesn't need to know
about the model directly.
In practice, Ember.js will create a template's controller once for
the entire application, but the controller's model may change
throughout the lifetime of the application without requiring that
the view knows anything about those mechanics.
<aside>
For example, if the user navigates from `/posts/1` to `/posts/2`,
the `PostController` will change its model from `Post.find(1)` to
`Post.find(2)`. The template will update its representations of any
properties on the model, as well as any computed properties on the
controller that depend on the model.
</aside>
This makes it easy to test a template in isolation by rendering it
with a controller object that contains the properties the template
expects. From the template's perspective, a **controller** is simply
an object that provides its data.
### Representing Models
Templates are always connected to controllers, not models. This
makes it easy to separate display-specific properties from model
specific properties, and to swap out the controller's model as the
user navigates around the page.
For convenience, Ember.js provides controllers that _proxy_
properties from their models so that you can say `{{name}}` in your
template rather than `{{model.name}}`. An `Ember.ArrayController`
proxies properties from an Array, and an `Ember.ObjectController`
proxies properties from an object.
If your controller is an `ArrayController`, you can iterate directly
over the controller using `{{#each controller}}`. This keeps the
template from having to know about how the controller is implemented
and makes isolation testing and refactoring easier.
### Storing Application Properties
Not all properties in your application need to be saved to the
server. Any time you need to store information only for the lifetime
of this application run, you should store it on a controller.
For example, imagine your application has a search field that
is always present. You could store a `search` property on your
`ApplicationController`, and bind the search field in the `
application` template to that property, like this:
```handlebars
<!-- application.handlebars -->
<header>
{{input type="text" value=search action="query"}}
</header>
{{outlet}}
```
```javascript
App.ApplicationController = Ember.Controller.extend({
// the initial value of the `search` property
search: '',
actions: {
query: function() {
// the current value of the text field
var query = this.get('search');
this.transitionToRoute('search', { query: query });
}
}
});
```
The `application` template stores its properties and sends its
actions to the `ApplicationController`. In this case, when the user
hits enter, the application will transition to the `search` route,
passing the query as a parameter.
## Representing a Single Model with ObjectController
Use `Ember.ObjectController` to represent a single model. To tell an
`ObjectController` which model to represent, set its `model`
property in your route's `setupController` method.
When a template asks an `ObjectController` for a property, it will first
check to see if it has its own property with that name defined. If so, it will
return its current value.
However, if the controller does not have a property with that name defined, it
will return the value of the property on the model.
For example, imagine you are writing a music player. You have defined
your `SongController` to represent the currently playing song.
```javascript
App.SongController = Ember.ObjectController.extend({
soundVolume: 1
});
```
In your router, you set the `model` of the controller to the
currently playing song:
```javascript
App.SongRoute = Ember.Route.extend({
setupController: function(controller, song) {
controller.set('model', song);
}
});
```
In your template, you want to display the name of the currently playing
song, as well as the volume at which it is playing.
```handlebars
<p>
<strong>Song</strong>: {{name}} by {{artist}}
</p>
<p>
<strong>Current Volume</strong>: {{soundVolume}}
</p>
```
Because `name` and `artist` are persisted information, and thus stored
on the model, the controller looks them up there and provides them to
the template.
`soundVolume`, however, is specific to the current user's session, and
thus stored on the controller. The controller can return its own value
without consulting the model.
The advantage of this architecture is that it is easy to get started
by accessing the properties of the model via the object controller. If,
however, you need to transform a model property for a template, there is
a well-defined place to do so without adding view-specific concerns to
the model.
For example, imagine we want to display the duration of the song:
```handlebars
<p>
<strong>Song</strong>: {{name}} by {{artist}}
</p>
<p>
<strong>Duration</strong>: {{duration}}
</p>
```
This is saved on the server as an integer representing the number of
seconds, so our first attempt looks like this:
```html
<p>
<strong>Song</strong>: 4 Minute Warning by Radiohead
</p>
<p>
<strong>Duration</strong>: 257
</p>
```
Since our users are humans and not robots, however, we'd like to display
the duration as a formatted string.
This is very easy to do by defining a computed property on the
controller which transforms the model's value into a human-readable
format for the template:
```javascript
App.SongController = Ember.ObjectController.extend({
duration: function() {
var duration = this.get('model.duration'),
minutes = Math.floor(duration / 60),
seconds = duration % 60;
return [minutes, seconds].join(':');
}.property('model.duration')
});
```
Now, the output of our template is a lot friendlier:
```html
<p>
<strong>Song</strong>: 4 Minute Warning by Radiohead
</p>
<p>
<strong>Duration</strong>: 4:17
</p>
```
## Representing Multiple Models with ArrayController
You can use [Ember.ArrayController](/api/classes/Ember.ArrayController.html) to represent an array of models. To tell an
`ArrayController` which model to represent, set its `model` property
in your route's `setupController` method.
You can treat an `ArrayController` just like its underlying array. For
example, imagine we want to display the current playlist. In our router,
we setup our `SongsController` to represent the songs in the playlist:
```javascript
App.SongsRoute = Ember.Route.extend({
setupController: function(controller, playlist) {
controller.set('model', playlist.get('songs'));
}
});
```
In the `songs` template, we can use the `{{#each}}` helper to display
each song:
```handlebars
<h1>Playlist</h1>
<ul>
{{#each}}
<li>{{name}} by {{artist}}</li>
{{/each}}
</ul>
```
You can use the `ArrayController` to collect aggregate information about
the models it represents. For example, imagine we want to display the
number of songs that are over 30 seconds long. We can add a new computed
property called `longSongCount` to the controller:
```javascript
App.SongsController = Ember.ArrayController.extend({
longSongCount: function() {
var longSongs = this.filter(function(song) {
return song.get('duration') > 30;
});
return longSongs.get('length');
}.property('@each.duration')
});
```
Now we can use this property in our template:
```handlebars
<ul>
{{#each}}
<li>{{name}} by {{artist}}</li>
{{/each}}
</ul>
{{longSongCount}} songs over 30 seconds.
```
### Sorting
The `Ember.ArrayController` uses the [Ember.SortableMixin](/api/classes/Ember.SortableMixin.html) to allow sorting
of content. There are two properties that can be set in order to set up sorting:
```javascript
App.SongsController = Ember.ArrayController.extend({
sortProperties: ['name', 'artist'],
sortAscending: true // false for descending
});
```
## Managing Dependencies Between Controllers
Sometimes, especially when nesting resources, we find ourselves needing
to have some kind of connection between two controllers. Let's take this
router as an example:
```javascript
App.Router.map(function() {
this.resource("post", { path: "/posts/:post_id" }, function() {
this.resource("comments", { path: "/comments" });
});
});
```
If we visit a `/posts/1/comments` URL, our `Post` model will get
loaded into a `PostController`'s model, which means it is not directly
accessible in the `CommentsController`. We might however want to display
some information about it in the `comments` template.
To be able to do this we define our `CommentsController` to `need` the `PostController`
which has our desired `Post` model.
```javascript
App.CommentsController = Ember.ArrayController.extend({
needs: "post"
});
```
This tells Ember that our `CommentsController` should be able to access
its parent `PostController`, which can be done via `controllers.post`
(either in the template or in the controller itself).
```handlebars
<h1>Comments for {{controllers.post.title}}</h1>
<ul>
{{#each comments}}
<li>{{text}}</li>
{{/each}}
</ul>
```
We can also create an aliased property to give ourselves a shorter way to access
the `PostController` (since it is an `ObjectController`, we don't need
or want the `Post` instance directly).
```javascript
App.CommentsController = Ember.ArrayController.extend({
needs: "post",
post: Ember.computed.alias("controllers.post")
});
```
If you want to connect multiple controllers together, you can specify an
array of controller names:
```javascript
App.AnotherController = Ember.Controller.extend({
needs: ['post', 'comments']
});
```
For more information about aliased property, see the API docs for
[aliased properties](http://emberjs.com/api/#method_computed_alias).
# Models
## Models
In Ember, every route has an associated model. This model is set by
implementing a route's `model` hook, by passing the model as an argument
to `{{link-to}}`, or by calling a route's `transitionTo()` method.
See [Specifying a Route's
Model](/guides/routing/specifying-a-routes-model) for more information
on setting a route's model.
For simple applications, you can get by using jQuery to load JSON data
from a server, then use those JSON objects as models.
However, using a model library that manages finding models, making
changes, and saving them back to the server can dramatically simplify
your code while improving the robustness and performance of your
application.
Many Ember apps use [Ember Data][emberdata] to handle this.
Ember Data is a library that integrates tightly with Ember.js to make it
easy to retrieve records from a server, cache them for performance,
save updates back to the server, and create new records on the client.
Without any configuration, Ember Data can load and save records and
their relationships served via a RESTful JSON API, provided it follows
certain conventions.
If you need to integrate your Ember.js app with existing JSON APIs that
do not follow strong conventions, Ember Data is designed to be easily
configurable to work with whatever data your server returns.
Ember Data is also designed to work with streaming APIs like
socket.io, Firebase, or WebSockets. You can open a socket to your server
and push changes to records into the store whenever they occur.
Currently, Ember Data ships as a separate library from Ember.js. Until
Ember Data is included as part of the standard distribution, you can get
a copy of the latest passing build from
[emberjs.com/builds][builds]:
* [Development][development-build]
* [Minified][minified-build]
[emberdata]: https://github.com/emberjs/data
[builds]: http://emberjs.com/builds
[development-build]: http://builds.emberjs.com/canary/ember-data.js
[minified-build]: http://builds.emberjs.com/canary/ember-data.min.js
### Core Concepts
Learning to use Ember Data is easiest once you understand some of the
concepts that underpin its design.
#### Store
The **store** is the central repository of records in your application.
You can think of the store as a cache of all of the records available in
your app. Both your application's controllers and routes have access to this
shared store; when they need to display or modify a record, they will
first ask the store for it.
This instance of `DS.Store` is created for you automatically and is shared
among all of the objects in your application.
You will use the store to retrieve records, as well to create new ones.
For example, we might want to find an `App.Person` model with the ID of
`1` from our route's `model` hook:
```js
App.IndexRoute = Ember.Route.extend({
model: function() {
return this.store.find('person', 1);
}
});
```
#### Models
A **model** is a class that defines the properties and behavior of the
data that you present to the user. Anything that the user expects to see
if they leave your app and come back later (or if they refresh the page)
should be represented by a model.
For example, if you were writing a web application for placing orders at
a restaurant, you might have models like `Order`, `LineItem`, and
`MenuItem`.
Fetching orders becomes very easy:
```js
this.store.find('order');
```
Models define the type of data that will be provided by your server. For
example, a `Person` model might have a `firstName` attribute that is a
string, and a `birthday` attribute that is a date:
```js
App.Person = DS.Model.extend({
firstName: DS.attr('string'),
birthday: DS.attr('date')
});
```
A model also describes its relationships with other objects. For
example, an `Order` may have many `LineItems`, and a `LineItem` may
belong to a particular `Order`.
```js
App.Order = DS.Model.extend({
lineItems: DS.hasMany('lineItem')
});
App.LineItem = DS.Model.extend({
order: DS.belongsTo('order')
});
```
Models don't have any data themselves; they just define the properties and
behavior of specific instances, which are called _records_.
#### Records
A **record** is an instance of a model that contains data loaded from a
server. Your application can also create new records and save them back
to the server.
Records are uniquely identified by two things:
1. A model type.
2. A globally unique ID.
For example, if you were writing a contact management app, you might
have a model called `Person`. An individual record in your app might
have a type of `Person` and an ID of `1` or `steve-buscemi`.
```js
this.store.find('person', 1); // => { id: 1, name: 'steve-buscemi' }
```
IDs are usually assigned by the server when you save them for the first
time, but you can also generate IDs client-side.
#### Adapter
An **adapter** is an object that knows about your particular server
backend and is responsible for translating requests for and changes to
records into the appropriate calls to your server.
For example, if your application asks for a `person` record with an ID
of `1`, how should Ember Data load it? Is it over HTTP or a WebSocket?
If it's HTTP, is the URL `/person/1` or `/resources/people/1`?
The adapter is responsible for answering all of these questions.
Whenever your app asks the store for a record that it doesn't have
cached, it will ask the adapter for it. If you change a record and save
it, the store will hand the record to the adapter to send the
appropriate data to your server and confirm that the save was
successful.
#### Serializer
A **serializer** is responsible for turning a raw JSON payload returned
from your server into a record object.
JSON APIs may represent attributes and relationships in many different
ways. For example, some attribute names may be `camelCased` and others
may be `under_scored`. Representing relationships is even more diverse:
they may be encoded as an array of IDs, an array of embedded objects, or
as foreign keys.
When the adapter gets a payload back for a particular record, it will
give that payload to the serializer to normalize into the form that
Ember Data is expecting.
While most people will use a serializer for normalizing JSON, because
Ember Data treats these payloads as opaque objects, there's no reason
they couldn't be binary data stored in a `Blob` or
[ArrayBuffer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays/ArrayBuffer).
#### Automatic Caching
The store will automatically cache records for you. If a record had already
been loaded, asking for it a second time will always return the same
object instance. This minimizes the number of round-trips to the
server, and allows your application to render its UI to the user as fast as
possible.
For example, the first time your application asks the store for a
`person` record with an ID of `1`, it will fetch that information from
your server.
However, the next time your app asks for a `person` with ID `1`, the
store will notice that it had already retrieved and cached that
information from the server. Instead of sending another request for the
same information, it will give your application the same record it had
provided it the first time. This feature—always returning the same
record object, no matter how many times you look it up—is sometimes
called an _identity map_.
Using an identity map is important because it ensures that changes you
make in one part of your UI are propagated to other parts of the UI. It
also means that you don't have to manually keep records in sync—you can
ask for a record by ID and not have to worry about whether other parts
of your application have already asked for and loaded it.
### Architecture Overview
The first time your application asks the store for a record, the store
sees that it doesn't have a local copy and requests it from your
adapter. Your adapter will go and retrieve the record from your
persistence layer; typically, this will be a JSON representation of the
record served from an HTTP server.
![Diagram showing process for finding an unloaded record](/images/guides/models/finding-unloaded-record-step1-diagram.png)
As illustrated in the diagram above, the adapter cannot always return the
requested record immediately. In this case, the adapter must make an
_asynchronous_ request to the server, and only when that request finishes
loading can the record be created with its backing data.
Because of this asynchronicity, the store immediately returns a
_promise_ from the `find()` method. Similarly, any requests that the
store makes to the adapter also return promises.
Once the request to the server returns with a JSON payload for the
requested record, the adapter resolves the promise it returned to the
store with the JSON.
The store then takes that JSON, initializes the record with the
JSON data, and resolves the promise returned to your application
with the newly-loaded record.
![Diagram showing process for finding an unloaded record after the payload has returned from the server](/images/guides/models/finding-unloaded-record-step2-diagram.png)
Let's look at what happens if you request a record that the store
already has in its cache.
![Diagram showing process for finding an unloaded record after the payload has returned from the server](/images/guides/models/finding-loaded-record-diagram.png)
In this case, because the store already knew about the record, it
returns a promise that it resolves with the record immediately. It does
not need to ask the adapter (and, therefore, the server) for a copy
since it already has it saved locally.
---
These are the core concepts you should understand to get the most out of
Ember Data. The following sections go into more depth about each of
these concepts, and how to use them together.
## Defining Models
A model is a class that defines the properties and behavior of the
data that you present to the user. Anything that the user expects to see
if they leave your app and come back later (or if they refresh the page)
should be represented by a model.
For every model in your application, create a subclass of `DS.Model`:
```javascript
App.Person = DS.Model.extend();
```
After you have defined a model class, you can start finding and creating
records of that type. When interacting with the store, you will need to
specify a record's type using the model name. For example, the store's
`find()` method expects a string as the first argument to tell it what
type of record to find:
```js
store.find('person', 1);
```
The table below shows how model names map to model classes.
<table>
<thead>
<tr>
<th>Model Name</th>
<th>Model Class</th>
</tr>
</thead>
<tr>
<td><code>photo</code></td>
<td><code>App.Photo</code></td>
</tr>
<tr>
<td><code>adminUserProfile</code></td>
<td><code>App.AdminUserProfile</code></td>
</tr>
</table>
### Defining Attributes
You can specify which attributes a model has by using `DS.attr`.
```javascript
var attr = DS.attr;
App.Person = DS.Model.extend({
firstName: attr(),
lastName: attr(),
birthday: attr()
});
```
Attributes are used when turning the JSON payload returned from your
server into a record, and when serializing a record to save back to the
server after it has been modified.
You can use attributes just like any other property, including as part of a
computed property. Frequently, you will want to define computed
properties that combine or transform primitive attributes.
```javascript
var attr = DS.attr;
App.Person = DS.Model.extend({
firstName: attr(),
lastName: attr(),
fullName: function() {
return this.get('firstName') + ' ' + this.get('lastName');
}.property('firstName', 'lastName')
});
```
For more about adding computed properties to your classes, see [Computed
Properties](/guides/object-model/computed-properties).
If you don't specify the type of the attribute, it will be whatever was
provided by the server. You can make sure that an attribute is always
coerced into a particular type by passing a `type` to `attr`:
```js
App.Person = DS.Model.extend({
birthday: DS.attr('date')
});
```
The default adapter supports attribute types of `string`,
`number`, `boolean`, and `date`. Custom adapters may offer additional
attribute types, and new types can be registered as transforms. See the
[documentation section on the REST Adapter](/guides/models/the-rest-adapter).
#### Options
`DS.attr` takes an optional hash as a second parameter, current options are:
- `defaultValue`: Pass a string or a function to be called to set the
attribute to a default value if none is supplied.
Example
```JavaScript
var attr = DS.attr;
App.User = DS.Model.extend({
username: attr('string'),
email: attr('string'),
verified: attr('boolean', {defaultValue: false}),
createdAt: DS.attr('string', {
defaultValue: function() { return new Date(); }
})
});
```
### Defining Relationships
Ember Data includes several built-in relationship types to help you
define how your models relate to each other.
#### One-to-One
To declare a one-to-one relationship between two models, use
`DS.belongsTo`:
```js
App.User = DS.Model.extend({
profile: DS.belongsTo('profile')
});
App.Profile = DS.Model.extend({
user: DS.belongsTo('user')
});
```
#### One-to-Many
To declare a one-to-many relationship between two models, use
`DS.belongsTo` in combination with `DS.hasMany`, like this:
```js
App.Post = DS.Model.extend({
comments: DS.hasMany('comment')
});
App.Comment = DS.Model.extend({
post: DS.belongsTo('post')
});
```
#### Many-to-Many
To declare a many-to-many relationship between two models, use
`DS.hasMany`:
```js
App.Post = DS.Model.extend({
tags: DS.hasMany('tag')
});
App.Tag = DS.Model.extend({
posts: DS.hasMany('post')
});
```
#### Explicit Inverses
Ember Data will do its best to discover which relationships map to one
another. In the one-to-many code above, for example, Ember Data can figure out that
changing the `comments` relationship should update the `post`
relationship on the inverse because `post` is the only relationship to
that model.
However, sometimes you may have multiple `belongsTo`/`hasMany`s for the
same type. You can specify which property on the related model is the
inverse using `DS.hasMany`'s `inverse` option:
```javascript
var belongsTo = DS.belongsTo,
hasMany = DS.hasMany;
App.Comment = DS.Model.extend({
onePost: belongsTo('post'),
twoPost: belongsTo('post'),
redPost: belongsTo('post'),
bluePost: belongsTo('post')
});
App.Post = DS.Model.extend({
comments: hasMany('comment', {
inverse: 'redPost'
})
});
```
You can also specify an inverse on a `belongsTo`, which works how you'd expect.
## Creating and Deleting Records
You can create records by calling the `createRecord` method on the store.
```js
store.createRecord('post', {
title: 'Rails is Omakase',
body: 'Lorem ipsum'
});
```
The store object is available in controllers and routes using `this.store`.
Although `createRecord` is fairly straightforward, the only thing to watch out for
is that you cannot assign a promise as a relationship, currently.
For example, if you want to set the `author` property of a post, this would **not** work
if the `user` with id isn't already loaded into the store:
```js
var store = this.store;
store.createRecord('post', {
title: 'Rails is Omakase',
body: 'Lorem ipsum',
author: store.find('user', 1)
});
```
However, you can easily set the relationship after the promise has fulfilled:
```js
var store = this.store;
var post = store.createRecord('post', {
title: 'Rails is Omakase',
body: 'Lorem ipsum'
});
store.find('user', 1).then(function(user) {
post.set('author', user);
});
```
### Deleting Records
Deleting records is just as straightforward as creating records. Just call `deleteRecord()`
on any instance of `DS.Model`. This flags the record as `isDeleted` and thus removes
it from `all()` queries on the `store`. The deletion can then be persisted using `save()`.
Alternatively, you can use the `destroyRecord` method to delete and persist at the same time.
```js
var post = store.find('post', 1);
post.deleteRecord();
post.get('isDeleted'); // => true
post.save(); // => DELETE to /posts/1
// OR
var post = store.find('post', 2);
post.destroyRecord(); // => DELETE to /posts/2
```
## Pushing Records into the Store
One way to think about the store is as a cache of all of the records
that have been loaded by your application. If a route or a controller in
your app asks for a record, the store can return it immediately if it is
in the cache. Otherwise, the store must ask the adapter to load it,
which usually means a trip over the network to retrieve it from the
server.
Instead of waiting for the app to request a record, however, you can
push records into the store's cache ahead of time.
This is useful if you have a good sense of what records the user
will need next. When they click on a link, instead of waiting for a
network request to finish, Ember.js can render the new template
immediately. It feels instantaneous.
Another use case for pushing in records is if your application has a
streaming connection to a backend. If a record is created or modified,
you want to update the UI immediately.
### Pushing Records
To push a record into the store, call the store's `push()` method.
For example, imagine we want to preload some data into the store when
the application boots for the first time.
We can use the `ApplicationRoute` to do so. The `ApplicationRoute` is
the top-most route in the route hierarchy, and its `model` hook gets
called once when the app starts up.
```js
var attr = DS.attr;
App.Album = DS.Model.extend({
title: attr(),
artist: attr(),
songCount: attr()
});
App.ApplicationRoute = Ember.Route.extend({
model: function() {
this.store.push('album', {
id: 1,
title: "Fewer Moving Parts",
artist: "David Bazan",
songCount: 10
});
this.store.push('album', {
id: 2,
title: "Calgary b/w I Can't Make You Love Me/Nick Of Time",
artist: "Bon Iver",
songCount: 2
});
}
});
```
## Persisting Records
Records in Ember Data are persisted on a per-instance basis.
Call `save()` on any instance of `DS.Model` and it will make a network request.
Here are a few examples:
```javascript
var post = store.createRecord('post', {
title: 'Rails is Omakase',
body: 'Lorem ipsum'
});
post.save(); // => POST to '/posts'
```
```javascript
var post = store.find('post', 1);
post.get('title') // => "Rails is Omakase"
post.set('title', 'A new post');
post.save(); // => PUT to '/posts/1'
```
### Promises
`save()` returns a promise, so it is extremely easy to handle success and failure scenarios.
Here's a common pattern:
```javascript
var post = store.createRecord('post', {
title: 'Rails is Omakase',
body: 'Lorem ipsum'
});
var self = this;
function transitionToPost(post) {
self.transitionToRoute('posts.show', post);
}
function failure(reason) {
// handle the error
}
post.save().then(transitionToPost).catch(failure);
// => POST to '/posts'
// => transitioning to posts.show route
```
Promises even make it easy to work with failed network requests:
```javascript
var post = store.createRecord('post', {
title: 'Rails is Omakase',
body: 'Lorem ipsum'
});
var onSuccess = function(post) {
this.transitionToRoute('posts.show', post);
};
var onFail = function(post) {
// deal with the failure here
};
post.save().then(onSuccess, onFail);
// => POST to '/posts'
// => transitioning to posts.show route
```
You can read more about promises [here](https://github.com/tildeio/rsvp.js), but here is another
example showing how to retry persisting:
```javascript
function retry(callback, nTimes) {
// if the promise fails
return callback().fail(function(reason) {
// if we haven't hit the retry limit
if (nTimes-- > 0) {
// retry again with the result of calling the retry callback
// and the new retry limit
return retry(callback, nTimes);
}
// otherwise, if we hit the retry limit, rethrow the error
throw reason;
});
}
// try to save the post up to 5 times
retry(function() {
return post.save();
}, 5);
```
## Finding Records
The Ember Data store provides a simple interface for finding records of a single
type through the `store` object's `find` method. Internally, the `store`
uses `find`, `findAll`, and `findQuery` based on the supplied arguments.
The first argument to `store.find()` is always the record type. The optional second
argument determines if a request is made for all records, a single record, or a query.
### Finding All Records of a Type
```javascript
var posts = this.store.find('post'); // => GET /posts
```
To get a list of records already loaded into the store, without making
another network request, use `all` instead.
```javascript
var posts = this.store.all('post'); // => no network request
```
`find` returns a `DS.PromiseArray` that fulfills to a `DS.RecordArray` and `all`
directly returns a `DS.RecordArray`.
It's important to note that `DS.RecordArray` is not a JavaScript array.
It is an object that implements [`Ember.Enumerable`][1]. This is important
because, for example, if you want to retrieve records by index, the `[]` notation
will not work--you'll have to use `objectAt(index)` instead.
[1]: http://emberjs.com/api/classes/Ember.Enumerable.html
### Finding a Single Record
If you provide a number or string as the second argument to `store.find()`,
Ember Data will attempt to retrieve a record of that with that ID. This will
return a promise that fulfills with the requested record:
```javascript
var aSinglePost = this.store.find('post', 1); // => GET /posts/1
```
### Querying For Records
If you provide a plain object as the second argument to `find`, Ember Data will
make a `GET` request with the object serialized as query params. This method returns
`DS.PromiseArray` in the same way as `find` with no second argument.
For example, we could search for all `person` models who have the name of
`Peter`:
```javascript
var peters = this.store.find('person', { name: "Peter" }); // => GET to /persons?name='Peter'
```
### Integrating with the Route's Model Hook
As discussed in [Specifying a Route's Model][3], routes are
responsible for telling their template which model to render.
[3]: /guides/routing/specifying-a-routes-model
`Ember.Route`'s `model` hook supports asynchronous values
out-of-the-box. If you return a promise from the `model` hook, the
router will wait until the promise has fulfilled to render the
template.
This makes it easy to write apps with asynchronous data using Ember
Data. Just return the requested record from the `model` hook, and let
Ember deal with figuring out whether a network request is needed or not.
```javascript
App.Router.map(function() {
this.resource('posts');
this.resource('post', { path: ':post_id' });
});
App.PostsRoute = Ember.Route.extend({
model: function() {
return this.store.find('post');
}
});
App.PostRoute = Ember.Route.extend({
model: function(params) {
return this.store.find('post', params.post_id);
}
})
```
## Working with Records
### Modifying Attributes
Once a record has been loaded, you can begin making changes to its
attributes. Attributes behave just like normal properties in Ember.js
objects. Making changes is as simple as setting the attribute you
want to change:
```js
var tyrion = this.store.find('person', 1);
// ...after the record has loaded
tyrion.set('firstName', "Yollo");
```
All of the Ember.js conveniences are available for
modifying attributes. For example, you can use `Ember.Object`'s
`incrementProperty` helper:
```js
person.incrementProperty('age'); // Happy birthday!
```
You can tell if a record has outstanding changes that have not yet been
saved by checking its `isDirty` property.
```js
person.get('isDirty'); //=> false
person.set('isAdmin', true);
person.get('isDirty'); //=> true
```
## Connecting to an HTTP Server
If your Ember application needs to load JSON data from an HTTP
server, this guide will walk you through the process of configuring
Ember Data to load records in whatever format your server returns.
The store uses an object called an _adapter_ to know how to
communicate over the network. By default, the store will use
`DS.RESTAdapter`, an adapter that communicates with an HTTP server by
transmitting JSON via XHR.
This guide is divided into two sections. The first section covers what
the default behavior of the adapter is, including what URLs it will
request records from and what format it expects the JSON to be in.
The second section covers how to override these default settings to
customize things like which URLs data is requested from and how the JSON
data is structured.
### URL Conventions
The REST adapter uses the name of the model to determine what URL to
send JSON to.
For example, if you ask for an `App.Photo` record by ID:
```js
App.PhotoRoute = Ember.Route.extend({
model: function(params) {
return this.store.find('photo', params.photo_id);
}
});
```
The REST adapter will automatically send a `GET` request to `/photos/1`.
The actions you can take on a record map onto the following URLs in the
REST adapter:
<table>
<thead>
<tr><th>Action</th><th>HTTP Verb</th><th>URL</th></tr>
</thead>
<tbody>
<tr><th>Find</th><td>GET</td><td>/people/123</td></tr>
<tr><th>Find All</th><td>GET</td><td>/people</td></tr>
<tr><th>Update</th><td>PUT</td><td>/people/123</td></tr>
<tr><th>Create</th><td>POST</td><td>/people</td></tr>
<tr><th>Delete</th><td>DELETE</td><td>/people/123</td></tr>
</tbody>
</table>
### JSON Conventions
Given the following models:
```js
var attr = DS.attr,
hasMany = DS.hasMany,
belongsTo = DS.belongsTo;
App.Post = DS.Model.extend({
title: attr(),
comments: hasMany('comment'),
user: belongsTo('user')
});
App.Comment = DS.Model.extend({
body: attr()
});
```
Ember Data expects that a `GET` request to `/posts/1` would
return the JSON in the following format:
```js
{
"post": {
"id": 1,
"title": "Rails is omakase",
"comments": ["1", "2"],
"user" : "dhh"
},
"comments": [{
"id": "1",
"body": "Rails is unagi"
}, {
"id": "2",
"body": "Omakase O_o"
}]
}
```
### Customizing the Adapter
To customize the REST adapter, define a subclass of `DS.RESTAdapter` and
name it `App.ApplicationAdapter`. You can then override its properties
and methods to customize how records are retrieved and saved.
#### Customizing a Specific Model
It's entirely possible that you need to define options for just one model instead of an application-wide customization. In that case, you can create an adapter named after the model you are specifying:
```js
App.PostAdapter = DS.RESTAdapter.extend({
namespace: 'api/v2',
host: 'https://api.example2.com'
});
App.PhotoAdapter = DS.RESTAdapter.extend({
namespace: 'api/v1'
host: 'https://api.example.com'
});
```
This allows you to easily connect to multiple API versions simultaneously or interact with different domains on a per model basis.
### Customizing URLs
#### URL Prefix
If your JSON API lives somewhere other than on the host root,
you can set a prefix that will be added to all requests.
For example, if you are using a versioned JSON API, a request for a
particular person might go to `/api/v1/people/1`.
In that case, set `namespace` property to `api/v1`.
```js
App.ApplicationAdapter = DS.RESTAdapter.extend({
namespace: 'api/v1'
});
```
Requests for a `person` with ID `1` would now go to `/api/v1/people/1`.
#### URL Host
If your JSON API runs on a different domain than the one serving your
Ember app, you can change the host used to make HTTP requests.
Note that in order for this to work, you will need to be using a browser
that supports [CORS](http://www.html5rocks.com/en/tutorials/cors/), and
your server will need to be configured to send the correct CORS headers.
To change the host that requests are sent to, set the `host` property:
```js
App.ApplicationAdapter = DS.RESTAdapter.extend({
host: 'https://api.example.com'
});
```
Requests for a `person` with ID `1` would now target `https://api.example.com/people/1`.
#### Custom HTTP Headers
Some APIs require HTTP headers, e.g. to provide an API key. Arbitrary
headers can be set as key/value pairs on the `RESTAdapter`'s `headers`
property and Ember Data will send them along with each ajax request.
For Example
```js
App.ApplicationAdapter = DS.RESTAdapter.extend({
headers: {
"API_KEY": "secret key",
"ANOTHER_HEADER": "Some header value"
}
});
```
Requests for any resource will include the following HTTP headers.
```http
ANOTHER_HEADER: Some header value
API_KEY: secret key
```
## Handling Metadata
Along with the records returned from your store, you'll likely need to handle some kind of metadata. *Metadata* is data that goes along with a specific *model* or *type* instead of a record.
Pagination is a common example of using metadata. Imagine a blog with far more posts than you can display at once. You might query it like so:
```js
this.store.findQuery("post", {
limit: 10,
offset: 0
});
```
To get different *pages* of data, you'd simply change your offset in increments of 10. So far, so good. But how do you know how many pages of data you have? Your server would need to return the total number of records as a piece of metadata.
By default, Ember Data's JSON deserializer looks for a `meta` key:
```js
{
"post": {
"id": 1,
"title": "Progressive Enhancement is Dead",
"comments": ["1", "2"],
"links": {
"user": "/people/tomdale"
},
// ...
},
"meta": {
"total": 100
}
}
```
The metadata for a specific type is then set to the contents of `meta`. You can access it with `store.metadataFor`:
```js
var meta = this.store.metadataFor("post");
```
Now, `meta.total` can be used to calculate how many pages of posts you'll have.
You can also customize metadata extraction by overriding the `extractMeta` method. For example, if instead of a `meta` object, your server simply returned:
```js
{
"post": [
// ...
],
"total": 100
}
```
You could extract it like so:
```js
App.ApplicationSerializer = DS.RESTSerializer.extend({
extractMeta: function(store, type, payload) {
if (payload && payload.total) {
store.metaForType(type, { total: payload.total }); // sets the metadata for "post"
delete payload.total; // keeps ember data from trying to parse "total" as a record
}
}
});
```
## Frequently Asked Questions
#### Should I use a query or a filter to search records?
It depends on how many records you want to search and whether they have
been loaded into the store.
_Queries_ are useful for doing searches of hundreds, thousands, or even
millions of records. You just hand the search options to your server,
and it is responsible for handing you back the list of records that
match. Because the response from the server includes the ID of all of
the records that matched, it doesn't matter if the store hadn't loaded
them previously; it sees that they are not in the cache and can request
the records by ID if necessary.
The downside of queries is that they do not live update, they are
slower, and they require that your server support the kind of queries
that you wish to perform.
Because the server decides which records match the query, not the store,
queries do not live update. If you want to update them, you must
manually call `reload()` and wait for the server to respond. If you
create a new record on the client, it will not show up in the results
until you both save the new record to the server and reload the query
results.
Because the store must confer with your server to determine the results
of a query, it necessitates a network request. This can feel slow to
users, especially if they are on a slow connection or your server is
slow to respond. The typical speed of JavaScript web applications can
heighten the perceived slowness when the server must be consulted.
Lastly, performing queries requires collaboration between the store and
your server. By default, Ember Data will send the search options that
you pass as the body of an HTTP request to your server. If your server
does not support requests in this format, you will need to either change
your server to do so, or customize how queries are sent by creating a
custom adapter.
_Filters_, on the other hand, perform a live search of all of the records
in the store's cache. As soon as a new record is loaded into the store,
the filter will check to see if the record matches, and if so, add it to
the array of search results. If that array is displayed in a template,
it will update automatically.
Filters also take into account newly created records that have not been
saved, and records that have been modified but not yet saved. If you
want records to show up in search results as soon as they are created or
modified on the client, you should use a filter.
Keep in mind that records will not show up in a filter if the store
doesn't know about them. You can ensure that a record is in the store by
using the store's `push()` method.
There is also a limit to how many records you can reasonably keep in
memory and search before you start hitting performance issues.
Finally, keep in mind that you can combine queries and filters to take
advantage of their respective strengths and weaknesses. Remember that
records returned by a query to the server are cached in the store. You
can use this fact to perform a filter, passing it a query that starts
matching records into the store, and a filter function that matches the
same records.
This will offload searching all of the possible records to the server,
while still creating a live updating list that includes records created
and modified on the client.
```js
App.PostsFavoritedRoute = Ember.Route.extend({
model: function() {
var store = this.store;
// Create a filter for all favorited posts that will be displayed in
// the template. Any favorited posts that are already in the store
// will be displayed immediately;
// Kick off a query to the server for all posts that
// the user has favorited. As results from the query are
// returned from the server, they will also begin to appear.
return store.filter('post', { favorited: true }, function(post) {
return post.get('isFavorited');
});
}
});
```
# Views
Because Handlebars templates in Ember.js are so powerful, the majority
of your application's user interface will be described using them. If
you are coming from other JavaScript libraries, you may be surprised at
how few views you have to create.
Views in Ember.js are typically only created for the following reasons:
* When you need sophisticated handling of user events
* When you want to create a re-usable component
Often, both of these requirements will be present at the same time.
### Event Handling
The role of the view in an Ember.js application is to translate
primitive browser events into events that have meaning to your
application.
For example, imagine you have a list of todo items. Next to each todo is
a button to delete that item:
![Todo List](/guides/views/images/todo-list.png)
The view is responsible for turning a _primitive event_ (a click) into a
_semantic event_: delete this todo! These semantic events are first sent
up to the controller, or if no method is defined there, your application's
router, which is responsible for reacting to the event based on the
current state of the application.
![Todo List](/guides/views/images/primitive-to-semantic-event.png)
## Defining a View
You can use `Ember.View` to render a Handlebars template and insert it into the DOM.
To tell the view which template to use, set its `templateName` property. For example, if I had a `<script>` tag like this:
```html
<html>
<head>
<script type="text/x-handlebars" data-template-name="say-hello">
Hello, <b>{{view.name}}</b>
</script>
</head>
</html>
```
I would set the `templateName` property to `"say-hello"`.
```javascript
var view = Ember.View.create({
templateName: 'say-hello',
name: "Bob"
});
```
Note: For the remainder of the guide, the `templateName` property will be omitted from most examples. You can assume that if we show a code sample that includes an Ember.View and a Handlebars template, the view has been configured to display that template via the `templateName` property.
You can append views to the document by calling `appendTo`:
```javascript
view.appendTo('#container');
```
As a shorthand, you can append a view to the document body by calling `append`:
```javascript
view.append();
```
To remove a view from the document, call `remove`:
```javascript
view.remove();
```
## Handling Events
Instead of having to register event listeners on elements you'd like to
respond to, simply implement the name of the event you want to respond to
as a method on your view.
For example, imagine we have a template like this:
```handlebars
{{#view App.ClickableView}}
This is a clickable area!
{{/view}}
```
Let's implement `App.ClickableView` such that when it is
clicked, an alert is displayed:
```javascript
App.ClickableView = Ember.View.extend({
click: function(evt) {
alert("ClickableView was clicked!");
}
});
```
Events bubble up from the target view to each parent view in succession,
until the root view. These values are read-only. If you want to
manually manage views in JavaScript (instead of creating them using
the `{{view}}` helper in Handlebars), see the `Ember.ContainerView`
documentation below.
###Sending Events
To have the click event from `App.ClickableView` affect the state of your application, simply send an event to the view's controller:
````javascript
App.ClickableView = Ember.View.extend({
click: function(evt) {
this.get('controller').send('turnItUp', 11);
}
});
````
If the controller has an action handler called `turnItUp`, it will be called:
````javascript
App.PlaybackController = Ember.ObjectController.extend({
actions: {
turnItUp: function(level){
//Do your thing
}
}
});
````
If it doesn't, the message will be passed to the current route:
````javascript
App.PlaybackRoute = Ember.Route.extend({
actions: {
turnItUp: function(level){
//This won't be called if it's defined on App.PlaybackController
}
}
});
````
To see a full listing of the `Ember.View` built-in events, see the
documentation section on [Event Names](/api/classes/Ember.View.html#toc_event-names).
## Inserting Views in Templates
So far, we've discussed writing templates for a single view. However, as your application grows, you will often want to create a hierarchy of views to encapsulate different areas on the page. Each view is responsible for handling events and maintaining the properties needed to display it.
### {{view}}
To add a child view to a parent, use the `{{view}}` helper, which takes a path to a view class.
```javascript
// Define parent view
App.UserView = Ember.View.extend({
templateName: 'user',
firstName: "Albert",
lastName: "Hofmann"
});
// Define child view
App.InfoView = Ember.View.extend({
templateName: 'info',
posts: 25,
hobbies: "Riding bicycles"
});
```
```html
<script type="text/x-handlebars" data-template-name="user">
User: {{view.firstName}} {{view.lastName}}
{{view App.InfoView}}
</script>
```
```html
<script type="text/x-handlebars" data-template-name="info">
<b>Posts:</b> {{view.posts}}
<br>
<b>Hobbies:</b> {{view.hobbies}}
</script>
```
If we were to create an instance of `App.UserView` and render it, we would get
a DOM representation like this:
```html
User: Albert Hofmann
<div>
<b>Posts:</b> 25
<br>
<b>Hobbies:</b> Riding bicycles
</div>
```
#### Relative Paths
Instead of specifying an absolute path, you can also specify which view class
to use relative to the parent view. For example, we could nest the above view
hierarchy like this:
```javascript
App.UserView = Ember.View.extend({
templateName: 'user',
firstName: "Albert",
lastName: "Hofmann",
infoView: Ember.View.extend({
templateName: 'info',
posts: 25,
hobbies: "Riding bicycles"
})
});
```
```handlebars
User: {{view.firstName}} {{view.lastName}}
{{view view.infoView}}
```
When nesting a view class like this, make sure to use a lowercase
letter, as Ember will interpret a property with a capital letter as a
global property.
### Setting Child View Templates
If you'd like to specify the template your child views use inline in
the main template, you can use the block form of the `{{view}}` helper.
We might rewrite the above example like this:
```javascript
App.UserView = Ember.View.extend({
templateName: 'user',
firstName: "Albert",
lastName: "Hofmann"
});
App.InfoView = Ember.View.extend({
posts: 25,
hobbies: "Riding bicycles"
});
```
```handlebars
User: {{view.firstName}} {{view.lastName}}
{{#view App.InfoView}}
<b>Posts:</b> {{view.posts}}
<br>
<b>Hobbies:</b> {{view.hobbies}}
{{/view}}
```
When you do this, it may be helpful to think of it as assigning views to
portions of the page. This allows you to encapsulate event handling for just
that part of the page.
## Adding Layouts to Views
Views can have a secondary template that wraps their main template. Like templates,
layouts are Handlebars templates that will be inserted inside the
view's tag.
To tell a view which layout template to use, set its `layoutName` property.
To tell the layout template where to insert the main template, use the Handlebars `{{yield}}` helper.
The HTML contents of a view's rendered `template` will be inserted where the `{{yield}}` helper is.
First, you define the following layout template:
```html
<script type="text/x-handlebars" data-template-name="my_layout">
<div class="content-wrapper">
{{yield}}
</div>
</script>
```
And then the following main template:
```html
<script type="text/x-handlebars" data-template-name="my_content">
Hello, <b>{{view.name}}</b>!
</script>
```
Finally, you define a view, and instruct it to wrap the template with the defined layout:
```javascript
AViewWithLayout = Ember.View.extend({
name: 'Teddy',
layoutName: 'my_layout',
templateName: 'my_content'
});
```
This will result in view instances containing the following HTML
```html
<div class="content-wrapper">
Hello, <b>Teddy</b>!
</div>
```
#### Applying Layouts in Practice
Layouts are extremely useful when you have a view with a common wrapper and behavior, but its main template might change.
One possible scenario is a Popup View.
You can define your popup layout template:
```html
<script type="text/x-handlebars" data-template-name="popup">
<div class="popup">
<button class="popup-dismiss">x</button>
<div class="popup-content">
{{yield}}
</div>
</div>
</script>
```
Then define your popup view:
```javascript
App.PopupView = Ember.View.extend({
layoutName: 'popup'
});
```
Now you can re-use your popup with different templates:
```html
{{#view App.PopupView}}
<form>
<label for="name">Name:</label>
<input id="name" type="text" />
</form>
{{/view}}
{{#view App.PopupView}}
<p> Thank you for signing up! </p>
{{/view}}
```
## Customizing a View's Element
A view is represented by a single DOM element on the page. You can change what kind of element is created by
changing the `tagName` property.
```javascript
App.MyView = Ember.View.extend({
tagName: 'span'
});
```
You can also specify which class names are applied to the view by setting its `classNames` property to an array of strings:
```javascript
App.MyView = Ember.View.extend({
classNames: ['my-view']
});
```
If you want class names to be determined by the state of properties on the view, you can use class name bindings. If you bind to
a Boolean property, the class name will be added or removed depending on the value:
```javascript
App.MyView = Ember.View.extend({
classNameBindings: ['isUrgent'],
isUrgent: true
});
```
This would render a view like this:
```html
<div class="ember-view is-urgent">
```
If `isUrgent` is changed to `false`, then the `is-urgent` class name will be removed.
By default, the name of the Boolean property is dasherized. You can customize the class name
applied by delimiting it with a colon:
```javascript
App.MyView = Ember.View.extend({
classNameBindings: ['isUrgent:urgent'],
isUrgent: true
});
```
This would render this HTML:
```html
<div class="ember-view urgent">
```
Besides the custom class name for the value being `true`, you can also specify a class name which is used when the value is `false`:
```javascript
App.MyView = Ember.View.extend({
classNameBindings: ['isEnabled:enabled:disabled'],
isEnabled: false
});
```
This would render this HTML:
```html
<div class="ember-view disabled">
```
You can also specify to only add a class when the property is `false` by declaring `classNameBindings` like this:
```javascript
App.MyView = Ember.View.extend({
classNameBindings: ['isEnabled::disabled'],
isEnabled: false
});
```
This would render this HTML:
```html
<div class="ember-view disabled">
```
If the `isEnabled` property is set to `true`, no class name is added:
```html
<div class="ember-view">
```
If the bound value is a string, that value will be added as a class name without
modification:
```javascript
App.MyView = Ember.View.extend({
classNameBindings: ['priority'],
priority: 'highestPriority'
});
```
This would render this HTML:
```html
<div class="ember-view highestPriority">
```
#### Attribute Bindings on a View
You can bind attributes to the DOM element that represents a view by using `attributeBindings`:
```javascript
App.MyView = Ember.View.extend({
tagName: 'a',
attributeBindings: ['href'],
href: "http://emberjs.com"
});
```
You can also bind these attributes to differently named properties:
```javascript
App.MyView = Ember.View.extend({
tagName: 'a',
attributeBindings: ['customHref:href'],
customHref: "http://emberjs.com"
});
```
### Customizing a View's Element from Handlebars
When you append a view, it creates a new HTML element that holds its content.
If your view has any child views, they will also be displayed as child nodes
of the parent's HTML element.
By default, new instances of `Ember.View` create a `<div>` element. You can
override this by passing a `tagName` parameter:
```handlebars
{{view App.InfoView tagName="span"}}
```
You can also assign an ID attribute to the view's HTML element by passing an `id` parameter:
```handlebars
{{view App.InfoView id="info-view"}}
```
This makes it easy to style using CSS ID selectors:
```css
/** Give the view a red background. **/
#info-view {
background-color: red;
}
```
You can assign class names similarly:
```handlebars
{{view App.InfoView class="info urgent"}}
```
You can bind class names to a property of the view by using `classBinding` instead of `class`. The same behavior as described in `bind-attr` applies:
```javascript
App.AlertView = Ember.View.extend({
priority: "p4",
isUrgent: true
});
```
```handlebars
{{view App.AlertView classBinding="isUrgent priority"}}
```
This yields a view wrapper that will look something like this:
```html
<div id="ember420" class="ember-view is-urgent p4"></div>
```
## Built-in Views
Ember comes pre-packaged with a set of views for building a few basic controls like text inputs, check boxes, and select lists.
They are:
#### Ember.Checkbox
```handlebars
<label>
{{view Ember.Checkbox checkedBinding="model.isDone"}}
{{model.title}}
</label>
```
#### Ember.TextField
```javascript
App.MyText = Ember.TextField.extend({
formBlurred: null, // passed to the view helper as formBlurred=controllerPropertyName
change: function(evt) {
this.set('formBlurred', true);
}
});
```
#### Ember.Select
```handlebars
{{view Ember.Select viewName="select"
contentBinding="people"
optionLabelPath="model.fullName"
optionValuePath="model.id"
prompt="Pick a person:"
selectionBinding="selectedPerson"}}
```
#### Ember.TextArea
```javascript
var textArea = Ember.TextArea.create({
valueBinding: 'TestObject.value'
});
```
## Manually Managing View Hierarchy
## Ember.ContainerView
As you probably know by now, views usually create their child views
by using the `{{view}}` helper. However, it is sometimes useful to
_manually_ manage a view's child views.
[`Ember.ContainerView`](/api/classes/Ember.ContainerView.html)
is the way to do just that.
As you programmatically add or remove views to a `ContainerView`,
those views' rendered HTML are added or removed from the DOM to
match.
```javascript
var container = Ember.ContainerView.create();
container.append();
var firstView = App.FirstView.create(),
secondView = App.SecondView.create();
container.pushObject(firstView);
container.pushObject(secondView);
// When the rendering completes, the DOM
// will contain a `div` for the ContainerView
// and nested inside of it, a `div` for each of
// firstView and secondView.
```
### Defining the Initial Views of a Container View
There are a few ways to specify which initial child views a
`ContainerView` should render. The most straight-forward way is to add
them in `init`:
```javascript
var container = Ember.ContainerView.create({
init: function() {
this._super();
this.pushObject(App.FirstView.create());
this.pushObject(App.SecondView.create());
}
});
container.objectAt(0).toString(); //=> '<App.FirstView:ember123>'
container.objectAt(1).toString(); //=> '<App.SecondView:ember124>'
```
As a shorthand, you can specify a `childViews` property that will be
consulted on instantiation of the `ContainerView` also. This example is
equivalent to the one above:
```javascript
var container = Ember.ContainerView.extend({
childViews: [App.FirstView, App.SecondView]
});
container.objectAt(0).toString(); //=> '<App.FirstView:ember123>'
container.objectAt(1).toString(); //=> '<App.SecondView:ember124>'
```
Another bit of syntactic sugar is available as an option as well:
specifying string names in the `childViews` property that correspond
to properties on the `ContainerView`. This style is less intuitive
at first but has the added bonus that each named property will
be updated to reference its instantiated child view:
```javascript
var container = Ember.ContainerView.create({
childViews: ['firstView', 'secondView'],
firstView: App.FirstView,
secondView: App.SecondView
});
container.objectAt(0).toString(); //=> '<App.FirstView:ember123>'
container.objectAt(1).toString(); //=> '<App.SecondView:ember124>'
container.get('firstView').toString(); //=> '<App.FirstView:ember123>'
container.get('secondView').toString(); //=> '<App.SecondView:ember124>'
```
### It Feels Like an Array Because it _is_ an Array
You may have noticed that some of these examples use `pushObject` to add
a child view, just like you would interact with an Ember array.
[`Ember.ContainerView`](/api/classes/Ember.ContainerView.html)
gains its collection-like behavior by mixing in
[`Ember.MutableArray`](/api/classes/Ember.MutableArray.html). That means
that you can manipulate the collection of views very expressively, using
methods like `pushObject`, `popObject`, `shiftObject`, `unshiftObject`, `insertAt`,
`removeAt`, or any other method you would use to interact with an Ember array.
# Enumerables
## Enumerables
In Ember.js, an Enumerable is any object that contains a number of child
objects, and which allows you to work with those children using the
[Ember.Enumerable](/api/classes/Ember.Enumerable.html) API. The most common
Enumerable in the majority of apps is the native JavaScript array, which
Ember.js extends to conform to the Enumerable interface.
By providing a standardized interface for dealing with enumerables,
Ember.js allows you to completely change the way your underlying data is
stored without having to modify the other parts of your application that
access it.
For example, you might display a list of items from fixture data during
development. If you switch the underlying data from synchronous fixtures
to an array that fetches data from the server lazily, your view,
template and controller code do not change at all.
The Enumerable API follows ECMAScript specifications as much as
possible. This minimizes incompatibility with other libraries, and
allows Ember.js to use the native browser implementations in arrays
where available.
For instance, all Enumerables support the standard `forEach` method:
```javascript
[1,2,3].forEach(function(item) {
console.log(item);
});
//=> 1
//=> 2
//=> 3
```
In general, Enumerable methods, like `forEach`, take an optional second
parameter, which will become the value of `this` in the callback
function:
```javascript
var array = [1,2,3];
array.forEach(function(item) {
console.log(item, this.indexOf(item));
}, array)
//=> 1 0
//=> 2 1
//=> 3 2
```
### Enumerables in Ember.js
Usually, objects that represent lists implement the Enumerable interface. Some examples:
* **Array** - Ember extends the native JavaScript `Array` with the
Enumerable interface (unless you [disable prototype
extensions.](/guides/configuring-ember/disabling-prototype-extensions/))
* **Ember.ArrayController** - A controller that wraps an underlying array and
adds additional functionality for the view layer.
* **Ember.Set** - A data structure that can efficiently answer whether it
includes an object.
### API Overview
In this guide, we'll explore some of the most common Enumerable
conveniences. For the full list, please see the [Ember.Enumerable API
reference documentation.](/api/classes/Ember.Enumerable.html)
#### Iterating Over an Enumerable
To enumerate all the values of an enumerable object, use the `forEach` method:
```javascript
var food = ["Poi", "Ono", "Adobo Chicken"];
food.forEach(function(item, index) {
console.log('Menu Item %@: %@'.fmt(index+1, item));
});
// Menu Item 1: Poi
// Menu Item 2: Ono
// Menu Item 3: Adobo Chicken
```
#### Making an Array Copy
You can make a native array copy of any object that implements
`Ember.Enumerable` by calling the `toArray()` method:
```javascript
var states = Ember.Set.create();
states.add("Hawaii");
states.add("California")
states.toArray()
//=> ["Hawaii", "California"]
```
Note that in many enumerables, such as the `Ember.Set` used in this
example, the order of the resulting array is not guaranteed.
#### First and Last Objects
All Enumerables expose `firstObject` and `lastObject` properties
that you can bind to.
```javascript
var animals = ["rooster", "pig"];
animals.get('lastObject');
//=> "pig"
animals.pushObject("peacock");
animals.get('lastObject');
//=> "peacock"
```
#### Map
You can easily transform each item in an enumerable using the
`map()` method, which creates a new array with results of calling a
function on each item in the enumerable.
```javascript
var words = ["goodbye", "cruel", "world"];
var emphaticWords = words.map(function(item) {
return item + "!";
});
// ["goodbye!", "cruel!", "world!"]
```
If your enumerable is composed of objects, there is a `mapBy()`
method that will extract the named property from each of those objects
in turn and return a new array:
```javascript
var hawaii = Ember.Object.create({
capital: "Honolulu"
});
var california = Ember.Object.create({
capital: "Sacramento"
});
var states = [hawaii, california];
states.mapBy('capital');
//=> ["Honolulu", "Sacramento"]
```
#### Filtering
Another common task to perform on an Enumerable is to take the
Enumerable as input, and return an Array after filtering it based on
some criteria.
For arbitrary filtering, use the `filter` method. The filter method
expects the callback to return `true` if Ember should include it in the
final Array, and `false` or `undefined` if Ember should not.
```javascript
var arr = [1,2,3,4,5];
arr.filter(function(item, index, self) {
if (item < 4) { return true; }
})
// returns [1,2,3]
```
When working with a collection of Ember objects, you will often want to filter a set of objects based upon the value of some property. The `filterBy` method provides a shortcut.
```javascript
Todo = Ember.Object.extend({
title: null,
isDone: false
});
todos = [
Todo.create({ title: 'Write code', isDone: true }),
Todo.create({ title: 'Go to sleep' })
];
todos.filterBy('isDone', true);
// returns an Array containing only items with `isDone == true`
```
If you want to return just the first matched value, rather than an Array containing all of the matched values, you can use `find` and `findBy`, which work just like `filter` and `filterBy`, but return only one item.
#### Aggregate Information (All or Any)
If you want to find out whether every item in an Enumerable matches some condition, you can use the `every` method:
```javascript
Person = Ember.Object.extend({
name: null,
isHappy: false
});
var people = [
Person.create({ name: 'Yehuda', isHappy: true }),
Person.create({ name: 'Majd', isHappy: false })
];
people.every(function(person, index, self) {
if(person.get('isHappy')) { return true; }
});
// returns false
```
If you want to find out whether at least one item in an Enumerable matches some conditions, you can use the `some` method:
```javascript
people.some(function(person, index, self) {
if(person.get('isHappy')) { return true; }
});
// returns true
```
Just like the filtering methods, the `every` and `some` methods have analogous `isEvery` and `isAny` methods.
```javascript
people.isEvery('isHappy', true) // false
people.isAny('isHappy', true) // true
```
# Testing
## Integration Testing
Ember includes several helpers to facilitate integration testing. These helpers are "aware" of (and wait for) asynchronous behavior within your application, making it much easier to write deterministic tests.
[QUnit](http://qunitjs.com/) is the default testing framework for this package, but others are supported through third-party adapters.
### Setup
In order to integration test the Ember application, you need to run the app within your test framework. Set the root element of the application to an arbitrary element you know will exist. It is useful, as an aid to test-driven development, if the root element is visible while the tests run. You can potentially use #qunit-fixture, typically used to contain fixture html for use in tests, but you will need to override css to make it visible.
```javascript
App.rootElement = '#arbitrary-element-to-contain-ember-application';
```
This hook defers the readiness of the application, so that you can start the app when your tests are ready to run. It also sets the router's location to 'none', so that the window's location will not be modified (preventing both accidental leaking of state between tests and interference with your testing framework).
```javascript
App.setupForTesting();
```
This injects the test helpers into the window's scope.
```javascript
App.injectTestHelpers();
```
With QUnit, `setup` and `teardown` functions are defined in each test module's configuration. These functions are called for each test in the module. If you are using a framework other than QUnit, use the hook that is called before each individual test.
Before each test, reset the application: `App.reset()` completely resets the state of the application.
```javascript
module("Integration Tests", {
setup: function() {
App.reset();
}
});
```
### Helpers
* `visit(url)`
- Visits the given route and returns a promise that fulfills when all resulting async behavior is complete.
* `find(selector, context)`
- Finds an element within the app's root element and within the context (optional). Scoping to the root element is especially useful to avoid conflicts with the test framework's reporter.
* `fillIn(input_selector, text)`
- Fills in the selected input with the given text and returns a promise that fulfills when all resulting async behavior is complete.
* `click(selector)`
- Clicks an element and triggers any actions triggered by the element's `click` event and returns a promise that fulfills when all resulting async behavior is complete.
* `keyEvent(selector, type, keyCode)`
- Simulates a key event type, e.g. `keypress`, `keydown`, `keyup` with the desired keyCode on element found by the selector.
### Writing tests
Almost every test has a pattern of visiting a route, interacting with the page (using the helpers), and checking for expected changes in the DOM.
Examples:
```javascript
test("root lists first page of posts", function(){
visit("/");
andThen(function() {
equal(find(".post").length, 5, "The first page should have 5 posts");
// Assuming we know that 5 posts display per page and that there are more than 5 posts
});
});
```
The helpers that perform actions use a global promise object and automatically chain onto that promise object if it exists. This allows you write your tests without worrying about async behaviour your helper might trigger.
```javascript
test("creating a post displays the new post", function(){
visit("/posts/new");
fillIn(".post-title", "A new post");
fillIn(".post-author", "John Doe");
click("button.create");
andThen(function() {
ok(find("h1:contains('A new post')").length, "The post's title should display");
ok(find("a[rel=author]:contains('John Doe')").length, "A link to the author should display");
});
});
```
### Creating your own test helpers
`Ember.Test.registerHelper` and `Ember.Test.registerAsyncHelper` are used to register test helpers that will be injected when `App.injectTestHelpers` is called. The difference between `Ember.Test.registerHelper` and `Ember.Test.registerAsyncHelper` is that the latter will not run until any previous async helper has completed and any subsequent async helper will wait for it to finish before running.
The helper method will always be called with the current Application as the first parameter. Helpers need to be registered prior to calling `App.injectTestHelpers()`.
For example:
```javascript
Ember.Test.registerAsyncHelper('dblclick', function(app, selector, context) {
var $el = findWithAssert(selector, context);
Ember.run(function() {
$el.dblclick();
});
});
```
### Test adapters for other libraries
If you use a library other than QUnit, your test adapter will need to provide methods for `asyncStart` and `asyncEnd`. To facilitate asynchronous testing, the default test adapter for QUnit uses methods that QUnit provides: (globals) `stop()` and `start()`.
**(Please note: Only development builds of Ember include the testing package. The ember-testing package is not included in the production build of Ember. The package can be loaded in your dev or qa builds to facilitate testing your application. By not including the ember-testing package in production, your tests will not be executable in a production environment.)**
# Configuring Ember.js
## Disabling Prototype Extensions
By default, Ember.js will extend the prototypes of native JavaScript
objects in the following ways:
* `Array` is extended to implement the `Ember.Enumerable`,
`Ember.MutableEnumerable`, `Ember.MutableArray` and `Ember.Array`
interfaces. This polyfills ECMAScript 5 array methods in browsers that
do not implement them, adds convenience methods and properties to
built-in arrays, and makes array mutations observable.
* `String` is extended to add convenience methods, such as
`camelize()` and `fmt()`.
* `Function` is extended with methods to annotate functions as
computed properties, via the `property()` method, and as observers,
via the `observes()` or `observesBefore()` methods.
This is the extent to which Ember.js enhances native prototypes. We have
carefully weighed the tradeoffs involved with changing these prototypes,
and recommend that most Ember.js developers use them. These extensions
significantly reduce the amount of boilerplate code that must be typed.
However, we understand that there are cases where your Ember.js
application may be embedded in an environment beyond your control. The
most common scenarios are when authoring third-party JavaScript that is
embedded directly in other pages, or when transitioning an application
piecemeal to a more modern Ember.js architecture.
In those cases, where you can't or don't want to modify native
prototypes, Ember.js allows you to completely disable the extensions
described above.
To do so, simply set the `EXTEND_PROTOTYPES` flag to `false`:
```javascript
window.ENV = {};
ENV.EXTEND_PROTOTYPES = false;
```
Note that the above code must be evaluated **before** Ember.js loads. If
you set the flag after the Ember.js JavaScript file has been evaluated,
the native prototypes will already have been modified.
### Life Without Prototype Extension
In order for your application to behave correctly, you will need to
manually extend or create the objects that the native objects were
creating before.
#### Arrays
Native arrays will no longer implement the functionality needed to
observe them. If you disable prototype extension and attempt to use
native arrays with things like a template's `{{#each}}` helper, Ember.js
will have no way to detect changes to the array and the template will
not update as the underlying array changes.
Additionally, if you try to set the model of an
`Ember.ArrayController` to a plain native array, it will raise an
exception since it no longer implements the `Ember.Array` interface.
You can manually coerce a native array into an array that implements the
required interfaces using the convenience method `Ember.A`:
```javascript
var islands = ['Oahu', 'Kauai'];
islands.contains('Oahu');
//=> TypeError: Object Oahu,Kauai has no method 'contains'
// Convert `islands` to an array that implements the
// Ember enumerable and array interfaces
Ember.A(islands);
islands.contains('Oahu');
//=> true
```
#### Strings
Strings will no longer have the convenience methods described in the
[Ember.String API reference.](/api/classes/Ember.String.html). Instead,
you can use the similarly-named methods of the `Ember.String` object and
pass the string to use as the first parameter:
```javascript
"my_cool_class".camelize();
//=> TypeError: Object my_cool_class has no method 'camelize'
Ember.String.camelize("my_cool_class");
//=> "myCoolClass"
```
#### Functions
To annotate computed properties, use the `Ember.computed()` method to
wrap the function:
```javascript
// This won't work:
fullName: function() {
return this.get('firstName') + ' ' + this.get('lastName');
}.property('firstName', 'lastName')
// Instead, do this:
fullName: Ember.computed('firstName', 'lastName', function() {
return this.get('firstName') + ' ' + this.get('lastName');
})
```
Observers are annotated using `Ember.observer()`:
```javascript
// This won't work:
fullNameDidChange: function() {
console.log("Full name changed");
}.observes('fullName')
// Instead, do this:
fullNameDidChange: Ember.observer('fullName', function() {
console.log("Full name changed");
})
```
## Embedding Applications
In most cases, your application's entire UI will be created by templates
that are managed by the router.
But what if you have an Ember.js app that you need to embed into an
existing page, or run alongside other JavaScript frameworks?
### Changing the Root Element
By default, your application will render the [application
template](/guides/templates/the-application-template) and attach it to
the document's `body` element.
You can tell the application to append the application template to a
different element by specifying its `rootElement` property:
```js
App = Ember.Application.create({
rootElement: '#app'
});
```
This property can be specified as either an element or a
[jQuery-compatible selector
string](http://api.jquery.com/category/selectors/).
### Disabling URL Management
You can prevent Ember from making changes to the URL by [changing the
router's `location`](/guides/routing/specifying-the-location-api) to
`none`:
```js
App.Router = Ember.Router.extend({
location: 'none'
});
```
## Feature Flags
## About Features
When a new feature is added to Ember they will be written in such a way that the
feature can be conditionally included in the generated build output and enabled
(or completely removed) based on whether a particular flag is present. This
allows newly developed features to be selectively released when they are
considered ready for production use.
## Feature Life-Cycle
When a new feature is flagged it is only available in canary builds (if enabled
at runtime). When it is time for the next beta cycle to be started (generally
6-12 week cycles) each feature will be evaluated and those features that are
ready will be enabled in the next `beta` (and subsequently automatically enabled
in all future canary builds).
If a given feature is deemed unstable it will be disabled in the next beta point
release, and not be included in the next stable release. It may still be included
in the next beta cycle if the issues/concerns have been resolved.
Once the beta cycle has completed the final release will include any features that
were enabled during that cycle. At this point the feature flags will be removed from
the canary and future beta branches, and the feature flag will no longer be used.
## Flagging Details
The flag status in the generated build output is controlled by the `features.json`
file in the root of the project. This file lists all features and their current
status.
A feature can have one of a few different statuses:
* `true` - The feature is **enabled**: the code behind the flag is always enabled in
the generated build.
* `false` - The feature is **disabled**: the code behind the flag is not present in
the generated build at all.
* `null` - The feature is **present** in the build output, but must be enabled at
runtime (it is still behind feature flags).
The process of removing the feature flags from the resulting build output is
handled by `defeatureify`.
## Feature Listing ([`FEATURES.md`](https://github.com/emberjs/ember.js/blob/master/FEATURES.md))
When a new feature is added to the `canary` channel (aka `master` branch), an
entry is added to [`FEATURES.md`](https://github.com/emberjs/ember.js/blob/master/FEATURES.md)
explaining what the feature does (and linking the originating pull request).
This listing is kept current, and reflects what is available in each branch
(`stable`,`beta`, and `master`).
## Enabling At Runtime
The only time a feature can be enabled at runtime is if the
`features.json` for that build contains `null` (technically, anything other
than `true` or `false` will do, but `null` is the chosen value).
A global `EmberENV` object will be used to initialize the `Ember.ENV`
object, and any feature flags that are enabled/disabled under
`EmberENV.FEATURES` will be migrated to `Ember.FEATURES`; those features
will be enabled based on the flag value. **Ember only reads** the
`EmberENV` value upon initial load so setting this value after Ember has
been loaded will have no affect.
Example:
```javascript
EmberENV = {FEATURES: {'link-to': true}};
```
Additionally you can define `EmberENV.ENABLE_ALL_FEATURES` to force all
features to be enabled.
# Cookbook
Welcome to the Ember.js Cookbook! The Cookbook provides answers and solutions
to common Ember questions and problems. Anyone is welcome to <a href="/guides/cookbook/contributing">contribute</a>.
Here are all of the available recipes:
### Contributing
1. [Understanding the Cookbook Format](/guides/cookbook/contributing/understanding_the_cookbook_format)
1. [Participating If You Know Ember](/guides/cookbook/contributing/participating_if_you_know_ember)
1. [Participating If You Don't Know Ember](/guides/cookbook/contributing/participating_if_you_dont_know_ember)
1. [Deciding If A Recipe is a Good Fit](/guides/cookbook/contributing/deciding_if_a_recipe_is_a_good_fit)
1. [Suggesting A Recipe](/guides/cookbook/contributing/suggesting_a_recipe)
### User Interface &amp; Interaction
1. [Adding CSS Classes to Your Components](/guides/cookbook/user_interface_and_interaction/adding_css_classes_to_your_components)
1. [Adding CSS Classes to Your Components Based on Properties](/guides/cookbook/user_interface_and_interaction/adding_css_classes_to_your_components_based_on_properties)
1. [Focusing a Textfield after It's Been Inserted](/guides/cookbook/user_interface_and_interaction/focusing_a_textfield_after_its_been_inserted)
1. [Displaying Formatted Dates With Moment.js](/guides/cookbook/user_interface_and_interaction/displaying_formatted_dates_with_moment_js)
1. [Specifying Data-Driven Areas of Templates That Do Not Need To Update](/guides/cookbook/user_interface_and_interaction/specifying_data_driven_areas_of_templates_that_do_not_need_to_update)
1. [Using Modal Dialogs](/guides/cookbook/user_interface_and_interaction/using_modal_dialogs)
1. [Resetting scroll on route changes](/guides/cookbook/user_interface_and_interaction/resetting_scroll_on_route_changes)
### Event Handling &amp; Data Binding
1. [Binding Properties of an Object to Its Own Properties](/guides/cookbook/event_handling_and_data_binding/binding_properties_of_an_object_to_its_own_properties)
### Helpers &amp; Components
1. [Creating Reusable Social Share Buttons](/guides/cookbook/helpers_and_components/creating_reusable_social_share_buttons)
2. [A Spinning Button for Asynchronous Actions](/guides/cookbook/helpers_and_components/spin_button_for_asynchronous_actions)
3. [Adding Google Analytics Tracking](/guides/cookbook/helpers_and_components/adding_google_analytics_tracking)
### Working with Objects
1. [Incrementing Or Decrementing A Property](/guides/cookbook/working_with_objects/incrementing_or_decrementing_a_property)
1. [Setting Multiple Properties At Once](/guides/cookbook/working_with_objects/setting_multiple_properties_at_once)
1. [Continuous Redrawing of Views](/guides/cookbook/working_with_objects/continuous_redrawing_of_views)
If you would like to see more recipes, take a look at the <a href="/guides/cookbook/contributing/suggesting_a_recipe">Suggesting A Recipe</a> section.
The Ember Cookbook provides answers and solutions to common Ember questions and problems. Anyone is welcome to
[contribute](/guides/cookbook/contributing/understanding_the_cookbook_format).
If you are new to Ember, we recommend that you spend some time reading the guides and tutorials before coming
to the Cookbook. Cookbook recipes assume that you have a basic understanding of Ember's concepts.
If you have experience with Ember and would like to contribute to the Cookbook, the discussion section of each
recipe is a great place to start.
### Recipes
1. [Understanding the Cookbook Format](/guides/cookbook/contributing/understanding_the_cookbook_format)
1. [Participating If You Know Ember](/guides/cookbook/contributing/participating_if_you_know_ember)
1. [Participating If You Don't Know Ember](/guides/cookbook/contributing/participating_if_you_dont_know_ember)
1. [Deciding If A Recipe is a Good Fit](/guides/cookbook/contributing/deciding_if_a_recipe_is_a_good_fit)
1. [Suggesting A Recipe](/guides/cookbook/contributing/suggesting_a_recipe)
## Understanding the Cookbook Format
### Problem
You want to contribute, but aren't familiar with the Cookbook format or don't know
how your contribution should be formatted.
### Solution
Cookbook-style guides contain recipes that guide a beginning programmer to a deeper knowledge of the subject
by answering specific, "how-to" style questions. Cookbook recipes address more topics than
[API documentation for a class](http://docs.emberjs.com/#doc=Ember.StateManager&src=fal), but are smaller in
scope than [a topic-based guide](http://emberjs.com/guides/view_layer/).
All recipes follow the same format:
<dl>
<dt>Title</dt>
<dd>Broadly explains the topic of the recipe</dd>
<dt>Problem</dt>
<dd>Outlines the recipe's goals</dd>
<dt>Solution</dt>
<dd>Summarizes the correct approach to addressing the problem</dd>
<dt>Discussion</dt>
<dd>Explores the solution in detail</dd>
</dl>
A Cookbook does not need to be read in any particular order, and each recipe should contain all the information
necessary for a beginner to address the _problem statement_. Referring to other recipes that are considered
prerequisite knowledge is encouraged.
### Discussion
Take a look at an [O'Reilly Cookbook](http://shop.oreilly.com/category/series/cookbooks.do) or the
[Coffeescript Cookbook](http://coffeescriptcookbook.com/). Both of these are great examples of the Cookbook
format.
[api_docs_for_class]: http://docs.emberjs.com/#doc=Ember.StateManager&src=fal
[topic_based_guide]: http://emberjs.com/guides/view_layer/
[oreilly_cookbooks]: http://shop.oreilly.com/category/series/cookbooks.do
[coffeescript_cookbook]: http://coffeescriptcookbook.com/
## Participating If You Know Ember
### Problem
You are familiar with Ember and want to help write the Cookbook.
### Solution
Get started by [forking the repository][fork_repo]. Send a pull request with an
update to an existing recipe or a new recipe.
### Discussion
Based on your experience and knowledge of Ember, we recommend submitting pull requests with the following:
<dl>
<dt>Beginner</dt>
<dd><em>Problem</em> statements are a good place for anyone to start helping. Feel free to submit pull requests that are just problem statements if there is a recipe you'd like to see. If you're new to Ember and/or haven't ever written an Ember app, this is a perfect place to start contributing.</dd>
<dt>Intermediate</dt>
<dd><em>Problem</em> &amp; <em>Solution</em> statements are a great way to participate if you're already writing Ember applications and have a known good solution to a particular problem statement. Feel free to leave _Discussion_ missing for someone else to fill out later.</dd>
<dt>Advanced</dt>
<dd><em>Problem</em>, <em>Solution</em> &amp; <em>Discussion</em> is the right way to help if you have a deeper understanding of the topic and can write cogently about why the solution is a good idea, explain pitfalls of other solutions, etc.</dd>
</dl>
You will be able to suggest possible recipes by forking this project and submitting a pull request with a new recipe (see [Suggesting a Recipe][suggesting_a_recipe]).
[fork_repo]: https://github.com/emberjs/website
[suggesting_a_recipe]: /guides/cookbook/contributing/suggesting_a_recipe
## Participating If You Don't Know Ember
### Problem
You are new to Ember, but want to help write the Cookbook.
### Solution
Suggest and/or submit pull requests with a _problem_ statement (see [Suggesting A Recipe](/guides/cookbook/contributing/suggesting_a_recipe)). You do not need to worry about providing a solution or discussion. Someone more experienced with Ember will be able to take your _problem_ and provide a _solution_ and _discussion_.
### Discussion
The first version of the Ember Cookbook will be completed in a few phases. First, we will be accepting
recipe suggestions. You can suggest a recipe by forking this repository and submitting a pull request
(see _Suggesting a Recipe_). Once we have written recipes, we'll be asking for help to proofread and test
them.
See ["Watch a project"](http://help.github.com/be-social/) on Github for information on watching projects.
## Deciding If A Recipe is a Good Fit
### Problem
You have an idea for a recipe, but aren't sure it is a good fit for the Cookbook.
### Solution
Read existing cookbook solutions and compare them to yours. You may also want to borrow or buy a cookbook-style
book for another technology to better understand the format.
Cookbook recipes are usually quick answers to focused questions. Your recipe should be narrowly tailored to
solve a single problem.
### Discussion
The Cookbook format best serves beginners who have a basic knowledge of Ember.js and have ideally completed a
small application of their own. Recipes in the Cookbook should teach intermediate and advanced topics, or present
skills an Ember.js developer should know. Popular topics on StackOverflow are great examples of what a Cookbook
recipe should cover.
A good recipe solves a single problem. Topics like "Syncing data with one-way bindings" or "Integrating Ember with
moment.js" make great recipes. Broader topics like "Building an Ember application with Node.js" or "Creating a GridView
with sortable fields and search" are not. If your topic is too big, consider breaking it into multiple recipes (e.g.
"Organizing an Ember application," "Responding to user events," "Connecting to remote data").
## Suggesting A Recipe
### Problem
You'd like to submit a recipe to the Ember Cookbook.
### Solution
[Fork the repository][fork_repo] and create a feature branch named after your
recipe. New recipes should have four sections: a _title_, a _problem statement_, a _solution statement_, and
an empty _discussion section_.
### Discussion
A [feature branch](http://nvie.com/posts/a-successful-git-branching-model/) is a branch in a local git
repository. Its name should be the camel-cased or underscored name of your recipe. For example, the branch
name for this recipe &ndash; "Suggesting a Recipe" &ndash; would be `SuggestingARecipe` or `suggesting_a_recipe`.
The _title_, _problem_, and _solution_ of your recipe should match the Cookbook's style (see
_Understanding the Cookbook Format_). While your recipe should include a _discussion_ section, you should leave
it blank. These sections will be created in a later phase of the Cookbook project.
The filename of your suggested recipe should be the lowercase, underscored version of your recipe's name. The
filename name for this recipe &nash; "Suggesting a Recipe" &ndash; would be `suggesting_a_recipe.mdown`.
When you are ready to submit your recipe, push your local branch to the remote branch on your Github fork and
submit a pull request. Before submitting a pull request, make sure someone hasn't already submitted a similar
recipe and that your recipe is a good fit for the Cookbook (see _Deciding If A Recipe Is A Good Fit_).
[fork_repo]: https://github.com/emberjs/website
[feature_branch]: http://nvie.com/posts/a-successful-git-branching-model/
[understanding]: /guides/cookbook/contributing/understanding_the_cookbook_format
[deciding]: /guides/cookbook/contributing/deciding_if_a_recipe_is_a_good_fit
Here are some recipes that will help you provide a better user experience.
1. [Adding CSS Classes to Your Components](/guides/cookbook/user_interface_and_interaction/adding_css_classes_to_your_components)
1. [Adding CSS Classes to Your Components Based on Properties](/guides/cookbook/user_interface_and_interaction/adding_css_classes_to_your_components_based_on_properties)
1. [Focusing a Textfield after It's Been Inserted](/guides/cookbook/user_interface_and_interaction/focusing_a_textfield_after_its_been_inserted)
1. [Displaying Formatted Dates With Moment.js](/guides/cookbook/user_interface_and_interaction/displaying_formatted_dates_with_moment_js)
1. [Specifying Data-Driven Areas of Templates That Do Not Need To Update](/guides/cookbook/user_interface_and_interaction/specifying_data_driven_areas_of_templates_that_do_not_need_to_update)
1. [Using Modal Dialogs](/guides/cookbook/user_interface_and_interaction/using_modal_dialogs)
1. [Resetting scroll on route changes](/guides/cookbook/user_interface_and_interaction/resetting_scroll_on_route_changes)
## Adding CSS Classes to Your Components
### Problem
You want to add CSS class names to your Ember Components.
### Solution
Set additional class names with the `classNames` property of subclassed components:
```js
App.AwesomeInputComponent = Ember.Component.extend({
classNames: ['css-framework-fancy-class']
})
```
```handlebars
{{awesome-input}}
```
```html
<div class="css-framework-fancy-class"></div>
```
### Discussion
If desired, you can apply multiple class names.
```js
classNames: ['bold', 'italic', 'blue']
```
#### Example
See [Customizing a Component's Element](/guides/components/customizing-a-components-element/) for further examples.
## Adding CSS Classes to Your Components Based on Properties
### Problem
You want to add or remove CSS class names to your Ember Components based on properties of the component.
### Solution
Add property names to the `classNameBindings` property of subclassed components.
### Discussion
You can apply classes based on properties of the component, or even by properties bound to data passed into the component. This is done by binding the class attribute using `classNameBindings`.
```js
classNameBindings: ['active'],
active: true
```
You can also set the class name based on a computed property.
```js
classNameBindings: ['isActive'],
isActive: function() {
return 'active';
}.property('someAttribute')
```
Another way would be to bind the class name to a bound property.
```js
classNameBindings: ['isRelated:relative'],
isRelatedBinding: "content.isRelated" // value resolves to boolean
```
#### Example
See [Customizing a Component's Element](/guides/components/customizing-a-components-element/) for further examples.
## Focusing a Textfield after It's Been Inserted
### Problem
You have an Ember.TextField instance that you would like become focused after it's been inserted.
### Solution
Subclass `Ember.TextField` and define a method marked with
`.on('didInsertElement')`. Inside this method apply `focus`
to the text field by accessing the components's jQuery `$` property:
```javascript
App.FocusInputComponent = Ember.TextField.extend({
becomeFocused: function() {
this.$().focus();
}.on('didInsertElement')
});
```
For the component's template:
```handlebars
Focus Input component!
```
```handlebars
{{focus-input}}
```
### Discussion
Custom components provide a way to extend native HTML elements with new behavior
like autofocusing.
Our App.FocusInputComponent is an extension of the Ember.TextField component
with a `becomeFocused` method added. After it is added to the DOM, every
component in Ember.js has access to an underlying jQuery object. This object wraps
the component's element and provides a unified, cross-browser interface for DOM
manipulations like triggering focus.
Because we can only work with these DOM features once an Ember.js component has
been added to the DOM we need to wait for this event to occur. Component's have a
`didInsertElement` event that is triggered when the component has been added to the
DOM.
By default Ember.js extends the native `Function.prototype` object to include a
number of additional functions, the `on` function among them. `on` gives us a declarative
syntax for signify that a method should be called when a specific event has fired. In this case,
we want to call our new `becomeFocused` method when the `didInsertElement` is fired for an instance
of our component.
Prototype extension can be disabled by setting the `Ember.EXTEND_PROTOTYPES` property to false.
#### Example
## Displaying Formatted Dates With Moment.js
### Problem
Display JavaScript Date objects in human readable format.
### Solution
There are two ways of formatting the value:
1. Create a Handlebars helper `{{format-date}}` and use it in your template
2. Create a computed property `formattedDate` that will return a transformed date
We will use [MomentJs](http://momentjs.com) for formatting dates.
Let's look at a simple example. You're working on a website for your
client, and one of the requirements is to have the current date on the index page in human readable format. This is a perfect place to use a
Handlebars helper that "pretty prints" the current date:
```javascript
Ember.Handlebars.registerBoundHelper('currentDate', function() {
return moment().format('LL');
});
```
Your template will look like:
```html
Today's date: {{currentDate}} // Today's date: August 30 2013
```
You can even enhance your code and pass in the date format to the helper:
```javascript
Ember.Handlebars.registerBoundHelper('currentDate', function(format) {
return moment().format(format);
});
```
Now you would need to pass an additional parameter to the helper:
```html
Today's date: {{currentDate 'LL'}} // Today's date: August 30 2013
```
Let's look at another example. Say you need
to create a simple control that allows you to type in a date and
a date format. The date will be formatted accordingly.
Define `formattedDate` computed property that depends on
`date` and `format`. Computed property in this example does
the same thing as Handlebars helpers defined above.
```javascript
App.ApplicationController = Ember.Controller.extend({
format: "YYYYMMDD",
date: null,
formattedDate: function() {
var date = this.get('date'),
format = this.get('format');
return moment(date).format(format);
}.property('date', 'format')
});
```
```html
{{input value=date}}
{{input value=format}}
<div>{{formattedDate}}</div>
```
### Discussion
Both helper and computed property can format your date value.
Which one do I use and when?
Handlebars helpers are shorthand for cases where you want to format
a value specifically for presentation. That value may be used
across different models and controllers.
You can use `{{currentDate}}` across your application to format dates
without making any changes to controllers.
Computed property in the example above does the same thing as the
Handlebars helper with one big difference:
`formattedDate` can be consumed later without applying
date format on the date property again.
#### Example
## Specifying Data-Driven Areas of Templates That Do Not Need To Update
### Problem
You have a section of a template that is based on a data but you don't need the template to update
### Solution
Use the `{{unbound}}` Handlebars helper.
```handlebars
{{unbound firstName}}
{{lastName}}
```
### Discussion
By default all uses of Handlebars helpers in Ember.js will use data bound values that will automatically update
the section of the template where a property changes after initial rendering. Ember.Handlebars does this by
applying the `{{bind}}` helper automatically for you.
For example, the two following uses of Handlebars are identical in an Ember.js application:
```handlebars
{{lastName}}
{{bind lastName}}
```
If you know that a property accessed in Handlebars will not change for the duration of the application's
life, you can specifiy that the property is not bound by applying the `{{unbound}}` helper. A property
that is not bound will avoid adding unnecessary observers on a property.
#### Example
## Using Modal Dialogs
### Problem
You want to show part of your UI in a modal dialog.
### Solution
Render a specific controller into a named `modal` outlet in your application
template.
### Discussion
You can use a route's `render` method to render a specific controller and
template into a named outlet. In this case we can setup our application template
to handle the main outlet and a modal outlet:
```handlebars
{{outlet}}
{{outlet modal}}
```
Then you can render a controller and template into the `modal` outlet. Sending
an action in a template will propagate to the application route's actions.
In a template:
```handlebars
<button {{action 'openModal' 'myModal'}}>Open modal</button>
```
In your application route:
```javascript
App.ApplicationRoute = Ember.Route.extend({
actions: {
openModal: function(modalName) {
return this.render(modalName, {
into: 'application',
outlet: 'modal'
});
}
}
});
```
When closing a modal, you can use the route's `disconnectOutlet` method to remove
the modal from the DOM.
```javascript
closeModal: function() {
return this.disconnectOutlet({
outlet: 'modal',
parentView: 'application'
});
}
```
It may also be helpful to use a `modal-dialog` component to handle common markup
and interactions such as rendering an overlay and handling clicks outside of the
modal.
#### Example
This example shows:
1. Rendering a pop-up modal in a named outlet.
1. Sending a specific model to the modal controller.
1. Wrapping the common modal markup and actions in a component.
1. Handling events to close the modal when the overlay is clicked.
## Resetting scroll on route changes
### Problem
The page scroller keeps in the same position when you go from one page to another. For instance, if you scroll down a long list of displayed elements on a page and then you navigate to another page with another long list of elements, you should be able to notice that scroll position is not being reset.
### Solution
Add the following mixin to the affected Routes:
```js
App.ResetScroll = Ember.Mixin.create({
activate: function() {
this._super();
window.scrollTo(0,0);
}
});
```
Only if you need do something on the `activate` method you must call `this._super()` at the beginning:
```js
App.IndexRoute = Ember.Route.extend(App.ResetScroll, {
//I need to do other things with activate
activate: function() {
this._super.apply(this, arguments); // Call super at the beginning
// Your stuff
}
});
```
#### Example
Here are some recipes for managing events and dealing with bindings.
1. [Binding Properties of an Object to Its Own Properties](/guides/cookbook/event_handling_and_data_binding/binding_properties_of_an_object_to_its_own_properties)
## Binding Properties of an Object to Its Own Properties
### Problem
You want to base the value of one property on the value of another property.
### Solution
Use one of the computed property macros like `Ember.computed.alias` or `Ember.computed.gte`
```js
App.Person = Ember.Object.extend({
firstName : null,
lastName : null,
surname : Ember.computed.alias("lastName"),
eligibleForRetirement: Ember.computed.gte("age", 65)
});
```
### Discussion
Ember.js includes a number of macros that will help create properties whose values are based
on the values of other properties, correctly connecting them with bindings so they remain
updated when values change. These all are stored on the `Ember.computed` object
and [documented in the API documentation](http://emberjs.com/api/#method_computed)
#### Example
Here are some recipes to help you encapsulate your code into Components and build Helpers.
1. [Creating Reusable Social Share Buttons](/guides/cookbook/helpers_and_components/creating_reusable_social_share_buttons)
2. [A Spinning Button for Asynchronous Actions](/guides/cookbook/helpers_and_components/spin_button_for_asynchronous_actions)
3. [Adding Google Analytics Tracking](/guides/cookbook/helpers_and_components/adding_google_analytics_tracking)
## Creating Reusable Social Share Buttons
### Problem
You want to create a reusable [Tweet button](https://dev.twitter.com/docs/tweet-button)
for your application.
### Solution
Write a custom component that renders the Tweet button with specific attributes
passed in.
```handlebars
{{share-twitter data-url="http://emberjs.com"
data-text="EmberJS Components are Amazing!"
data-size="large"
data-hashtags="emberjs"}}
```
```javascript
App.ShareTwitterComponent = Ember.Component.extend({
tagName: 'a',
classNames: 'twitter-share-button',
attributeBindings: ['data-size', 'data-url', 'data-text', 'data-hashtags']
});
```
Include Twitter's widget code in your HTML:
```javascript
<script type="text/javascript" src="http://platform.twitter.com/widgets.js" id="twitter-wjs"></script>
```
### Discussion
Twitter's widget library expects to find an `<a>` tag on the page with specific `data-` attributes applied.
It takes the values of these attributes and, when the `<a>` tag is clicked, opens an iFrame for twitter sharing.
The `share-twitter` component takes four options that match the four attributes for the resulting `<a>` tag:
`data-url`, `data-text`, `data-size`, `data-hashtags`. These options and their values become properties on the
component object.
The component defines certain attributes of its HTML representation as bound to properties of the object through
its `attributeBindings` property. When the values of these properties change, the component's HTML element's
attributes will be updated to match the new values.
An appropriate tag and css class are applied through the `tagName` and `classNames` properties.
#### Example
Here are some recipes to help you understand working with Ember Objects.
1. [Incrementing Or Decrementing A Property](/guides/cookbook/working_with_objects/incrementing_or_decrementing_a_property)
1. [Setting Multiple Properties At Once](/guides/cookbook/working_with_objects/setting_multiple_properties_at_once)
1. [Continuous Redrawing of Views](/guides/cookbook/working_with_objects/continuous_redrawing_of_views)
## Incrementing Or Decrementing A Property
### Problem
You want to increment or decrement a property.
### Solution
Use the `incrementProperty` or `decrementProperty` methods of `Ember.Object`.
To increment:
```javascript
person.incrementProperty('age');
```
To decrement:
```javascript
person.decrementProperty('age');
```
### Discussion
You can optionally specify a value to increment or decrement by:
```javascript
person.incrementProperty('age', 10);
```
#### Example
## Setting Multiple Properties At Once
### Problem
You want to set multiple properties on an object with a single method call.
### Solution
Use the `setProperties` method of `Ember.Object`.
```js
person.setProperties({
name: 'Gavin',
age: 36
})
```
#### Example
## Continuous Redrawing of Views
## Problem
You'd like to redraw your views every few seconds/minutes e.g. to update
relative timestamps (like on twitter.com).
## Solution
Have a clock object with a `pulse` attribute in your application which
increments using a timed interval. You want to let view(s) bind values to be
refreshed when the `pulse` attribute increments.
The clock object can be used to create new instances for binding to new views
generated within the application, like a list of comments.
## Discussion
Cookbook: Continuous Redrawing of Views
</a><script src="http://static.jsbin.com/js/embed.js"></script>
### ClockService object
This `ClockService` is an example of an object that may come from a library.
And, is injected into the application via an initializer.
During initialization the `tick` method is called which uses `Ember.run.later`
with a time of 250 milliseconds as the interval. A property is set at the end
of the interval. Since the `tick` method observes the incremented property
another interval is triggered each time the property increases.
```javascript
var ClockService = Ember.Object.extend({
pulse: Ember.computed.oneWay('_seconds').readOnly(),
tick: function () {
var clock = this;
Ember.run.later(function () {
var seconds = clock.get('_seconds');
if (typeof seconds === 'number') {
clock.set('_seconds', seconds + (1/4));
}
}, 250);
}.observes('_seconds').on('init'),
_seconds: 0,
});
```
### Binding to the `pulse` attribute
In this recipe, an application initializer is used to inject an instance of the
`ClockService` object, setting a controller's `clock` property to this instance.
```javascript
Ember.Application.initializer({
name: 'clockServiceInitializer',
initialize: function(container, application) {
container.register('clock:service', ClockService);
application.inject('controller:interval', 'clock', 'clock:service');
}
});
```
The controller can set any computed properties based on the `pulse` property of
the injected `clock` instance.
In this case the `seconds` property is bound to the `pulse` property of the
controller's `clock`. The property `clock.pulse` was injected during
initialization.
The controller has (session) data to display `seconds` to visitors, as well as
a handful of properties used as conditions in the Handlebars template.
```javascript
App.IntervalController = Ember.ObjectController.extend({
secondsBinding: 'clock.pulse',
fullSecond: function () {
return (this.get('seconds') % 1 === 0);
}.property('seconds'),
quarterSecond: function () {
return (this.get('seconds') % 1 === 1/4);
}.property('seconds'),
halfSecond: function () {
return (this.get('seconds') % 1 === 1/2);
}.property('seconds'),
threeQuarterSecond: function () {
return (this.get('seconds') % 1 === 3/4);
}.property('seconds')
});
```
A controller for a list of comments, each comment will have a new clock
instance when added to the list. The comment item controller sets up
the `seconds` binding, used by the template to show the time since the
comment was created.
```javascript
App.CommentItemController = Ember.ObjectController.extend({
seconds: Ember.computed.oneWay('clock.pulse').readOnly()
});
App.CommentsController = Ember.ArrayController.extend({
needs: ['interval'],
itemController: 'commentItem',
actions: {
add: function () {
this.addObject(Em.Object.create({
comment: $('#comment').val(),
clock: ClockService.create()
}));
}
}
});
```
### Handlebars template which displays the `pulse`
The `seconds` value is computed from the `pulse` attribute. And the controller
has a few properties to select a component to render, `fullSecond`,
`quarterSecond`, `halfSecond`, `threeQuarterSecond`.
```handlebars
{{#if fullSecond}}
{{nyan-start}}
{{/if}}
{{#if quarterSecond}}
{{nyan-middle}}
{{/if}}
{{#if halfSecond}}
{{nyan-end}}
{{/if}}
{{#if threeQuarterSecond}}
{{nyan-middle}}
{{/if}}
<h3>You&apos;ve nyaned for {{digital_clock seconds}} (h:m:s)</h3>
{{render 'comments'}}
```
A template for a list of comments
```handlebars
<input type="text" id="comment" />
<button {{action 'add'}}>Add Comment</button>
<ul>
{{#each}}
<li>{{comment}} ({{digital_clock clock.pulse}})</li>
{{/each}}
</ul>
```
### Handlebars helper to format the clock display (h:m:s)
This helper is used in the template like so `{{digital_clock seconds}}`,
`seconds` is the property of the controller that will be displayed (h:m:s).
```javascript
Ember.Handlebars.registerBoundHelper('digital_clock', function(seconds) {
var h = Math.floor(seconds / 3600);
var m = Math.floor((seconds % 3600) / 60);
var s = Math.floor(seconds % 60);
var addZero = function (number) {
return (number < 10) ? '0' + number : '' + number;
};
var formatHMS = function(h, m, s) {
if (h > 0) {
return '%@:%@:%@'.fmt(h, addZero(m), addZero(s));
}
return '%@:%@'.fmt(m, addZero(s));
};
return new Ember.Handlebars.SafeString(formatHMS(h, m, s));
});
```
### Note
To explore the concept further, try adding a timestamp and updating the clock's
pulse by comparing the current time. This would be needed to update the pulse
property when a user puts his/her computer to sleep then reopens their browser
after waking.
### Links
The source code:
* <http://jsbin.com/iLETUTI/17/edit?html,js,output>
Further reading:
* <http://emberjs.com/api/classes/Ember.Object.html>
* <http://emberjs.com/api/classes/Ember.Application.html>, See section on
"Initializers"
* <http://emberjs.com/api/classes/Ember.Application.html#method_inject>
* <http://emberjs.com/guides/templates/conditionals/>
* <http://emberjs.com/guides/templates/writing-helpers/>
* <http://emberjs.com/guides/components/defining-a-component/>
* <http://emberjs.com/api/classes/Ember.ArrayController.html>
# Understanding Ember.js
## The View Layer
This guide goes into extreme detail about the Ember.js view layer. It is
intended for an experienced Ember developer, and includes details that
are unnecessary for getting started with Ember.
Ember.js has a sophisticated system for creating, managing and rendering a hierarchy of views that connect to the browser's DOM. Views are responsible for responding to user events, like clicks, drags, and scrolls, as well as updating the contents of the DOM when the data underlying the view changes.
View hierarchies are usually created by evaluating a Handlebars template. As the template is evaluated, child views are added. As the templates for _those_ child views are evaluated, they may have child views added, and so on, until an entire hierarchy is created.
Even if you do not explicitly create child views from your Handlebars templates, Ember.js internally uses the view system to update bound values. For example, every Handlebars expression `{{value}}` creates a view behind-the-scenes that knows how to update the bound value if it changes.
You can also dynamically make changes to the view hierarchy at application runtime using the `Ember.ContainerView` class. Rather than being template-driven, a container view exposes an array of child view instances that can be manually managed.
Views and templates work in tandem to provide a robust system for creating whatever user interface you dream up. End users should be isolated from the complexities of things like timing issues while rendering and event propagation. Application developers should be able to describe their UI once, as a string of Handlebars markup, and then carry on with their application without having to worry about making sure that it remains up-to-date.
### What problems does it solve?
#### Child Views
In a typical client-side application, views may represent elements nested inside of each other in the DOM. In the naïve solution to this problem, separate view objects represent each DOM element, and ad-hoc references help the various view object keep track of the views conceptually nested inside of them.
Here is a simple example, representing one main app view, a collection nested inside of it, and individual items nested inside of the collection.
<figure>
<img src="/images/view-guide/view-hierarchy-simple.png">
</figure>
This system works well at first glance, but imagine that we want to open Joe's Lamprey Shack at 8am instead of 9am. In this situation, we will want to re-render the App View. Because the developer needed to build up the references to the children on an ad-hoc basis, this re-rendering process has several problems.
In order to re-render the App View, the App View must also manually re-render the child views and re-insert them into App View's element. If implemented perfectly, this process works well, but it relies upon a perfect, ad hoc implementation of a view hierarchy. If any single view fails to implement this precisely, the entire re-render will fail.
In order to avoid these problems, Ember's view hierarchy has the concept of child views baked in.
<figure>
<img src="/images/view-guide/view-hierarchy-ember.png">
</figure>
When the App View re-renders, Ember is responsible for re-rendering and inserting the child views, not application code. This also means that Ember can perform any memory management for you, such as cleaning up observers and bindings.
Not only does this eliminate quite a bit of boilerplate code, but it eliminates the possibility that an imperfectly implemented view hierarchy will cause unexpected failures.
#### Event Delegation
In the past, web developers have added event listeners to individual elements in order to know when the user interacts with them. For example, you might have a `<div>` element on which you register a function that gets called when the user clicks it.
However, this approach often does not scale when dealing with large numbers of interactive elements. For example, imagine a `<ul>` with 100 `<li>`s in it, with a delete button next to each item. Since the behavior is the same for all of these items, it would be inefficient to create 100 event listeners, one for each delete button.
<figure>
<img src="/images/view-guide/undelegated.png">
</figure>
To solve this problem, developers discovered a technique called "event delegation". Instead of registering a listener on each element in question, you can register a single listener for the containing element and use `event.target` to identify which element the user clicked on.
<figure>
<img src="/images/view-guide/delegated.png">
</figure>
Implementing this is a bit tricky, because some events (like `focus`, `blur` and `change`) don't bubble. Fortunately, jQuery has solved this problem thoroughly; using jQuery's `on` method reliably works for all native browser events.
Other JavaScript frameworks tackle this problem in one of two ways. In the first approach, they ask you to implement the naïve solution yourself, creating a separate view for each element. When you create the view, it sets up an event listener on the view's element. If you had a list of 500 items, you would create 500 views and each would set up a listener on its own element.
In the second approach, the framework builds in event delegation at the view level. When creating a view, you can supply a list of events to delegate and a method to call when the event occurs. This leaves identifying the context of the click (for example, which item in the list) to the method receiving the event.
You are now faced with an uncomfortable choice: create a new view for each item and lose the benefits of event delegation, or create a single view for all of the items and have to store information about the underlying JavaScript object in the DOM.
In order to solve this problem, Ember delegates all events to the application's root element (usually the document `body`) using jQuery. When an event occurs, Ember identifies the nearest view that handles the event and invokes its event handler. This means that you can create views to hold a JavaScript context, but still get the benefit of event delegation.
Further, because Ember registers only one event for the entire Ember application, creating new views never requires setting up event listeners, making re-renders efficient and less error-prone. When a view has child views, this also means that there is no need to manually undelegate views that the re-render process replaces.
#### The Rendering Pipeline
Most web applications specify their user interface using the markup of a particular templating language. For Ember.js, we've done the work to make templates written using the Handlebars templating language automatically update when the values used inside of them are changed.
While the process of displaying a template is automatic for developers, under the hood there are a series of steps that must be taken to go from the original template to the final, live DOM representation that the user sees.
This is the approximate lifecycle of an Ember view:
<figure>
<img src="/images/view-guide/view-lifecycle-ember.png">
</figure>
##### 1. Template Compilation
The application's templates are loaded over the network or as part of the application payload in string form. When the application loads, it sends the template string to Handlebars to be compiled into a function. Once compiled, the template function is saved, and can be used by multiple views repeatedly, each time they need to re-render.
This step may be omitted in applications where the templates are pre-compiled on the server. In those cases, the template is transferred not as the original, human-readable template string but as the compiled code.
Because Ember is responsible for template compilation, you don't have to do any additional work to ensure that compiled templates are reused.
##### 2. String Concatenation
A view's rendering process is kickstarted when the application calls `append` or `appendTo` on the view. Calling `append` or `appendTo` **schedules** the view to be rendered and inserted later. This allows any deferred logic in your application (such as binding synchronization) to happen before rendering the element.
To begin the rendering process, Ember creates a `RenderBuffer` and gives it to the view to append its contents to. During this process, a view can create and render child views. When it does so, the parent view creates and assigns a `RenderBuffer` for the child, and links it to the parent's `RenderBuffer`.
Ember flushes the binding synchronization queue before rendering each view. By syncing bindings before rendering each view, Ember guarantees that it will not render stale data it needs to replace right away.
Once the main view has finished rendering, the render process has created a tree of views (the "view hierarchy"), linked to a tree of buffers. By walking down the tree of buffers and converting them into Strings, we have a String that we can insert into the DOM.
Here is a simple example:
<figure>
<img src="/images/view-guide/render-buffer.png">
</figure>
In addition to children (Strings and other `RenderBuffer`s), a `RenderBuffer` also encapsulates the element's tag name, id, classes, style, and other attributes. This makes it possible for the render process to modify one of these properties (style, for example), even after its child Strings have rendered. Because many of these properties are controlled via bindings (e.g. using `bind-attr`), this makes the process robust and transparent.
##### 3. Element Creation and Insertion
At the end of the rendering process, the root view asks the `RenderBuffer` for its element. The `RenderBuffer` takes its completed string and uses jQuery to convert it into an element. The view assigns that element to its `element` property and places it into the correct place in the DOM (the location specified in `appendTo` or the application's root element if the application used `append`).
While the parent view assigns its element directly, each child views looks up its element lazily. It does this by looking for an element whose `id` matches its `elementId` property. Unless explicitly provided, the rendering process generates an `elementId` property and assigns its value to the view's `RenderBuffer`, which allows the view to find its element as needed.
##### 4. Re-Rendering
After the view inserts itself into the DOM, either Ember or the application may want to re-render the view. They can trigger a re-render by calling the `rerender` method on a view.
Rerendering will repeat steps 2 and 3 above, with two exceptions:
* Instead of inserting the element into an explicitly specified location, `rerender` replaces the existing element with the new element.
* In addition to rendering a new element, it also removes the old element and destroys its children. This allows Ember to automatically handle unregistering appropriate bindings and observers when re-rendering a view. This makes observers on a path more viable, because the process of registering and unregistering all of the nested observers is automatic.
The most common cause of a view re-render is when the value bound to a Handlebars expression (`{{foo}}`) changes. Internally, Ember creates a simple view for each expression, and registers an observer on the path. When the path changes, Ember updates the area of the DOM with the new value.
Another common case is an `{{#if}}` or `{{#with}}` block. When rendering a template, Ember creates a virtual view for these block helpers. These virtual views do not appear in the publicly available view hierarchy (when getting `parentView` and `childViews` from a view), but they exist to enable consistent re-rendering.
When the path passed to an `{{#if}}` or `{{#with}}` changes, Ember automatically re-renders the virtual view, which will replace its contents, and importantly, destroy all child views to free up their memory.
In addition to these cases, the application may sometimes want to explicitly re-render a view (usually a `ContainerView`, see below). In this case, the application can call `rerender` directly, and Ember will queue up a re-rendering job, with the same semantics.
The process looks something like:
<figure>
<img src="/images/view-guide/re-render.png">
</figure>
### The View Hierarchy
#### Parent and Child Views
As Ember renders a templated view, it will generate a view hierarchy. Let's assume we have a template `form`.
```handlebars
{{view App.Search placeholder="Search"}}
{{#view Ember.Button}}Go!{{/view}}
```
And we insert it into the DOM like this:
```javascript
var view = Ember.View.create({
templateName: 'form'
}).append();
```
This will create a small view hierarchy that looks like this:
<figure>
<img src="/images/view-guide/simple-view-hierarchy.png">
</figure>
You can move around in the view hierarchy using the `parentView` and `childViews` properties.
```javascript
var children = view.get('childViews') // [ <App.Search>, <Ember.Button> ]
children.objectAt(0).get('parentView') // view
```
One common use of the `parentView` method is inside of an instance of a child view.
```javascript
App.Search = Ember.View.extend({
didInsertElement: function() {
// this.get('parentView') in here references `view`
}
})
```
#### Lifecycle Hooks
In order to make it easy to take action at different points during your view's lifecycle, there are several hooks you can implement.
* `willInsertElement`: This hook is called after the view has been rendered but before it has been inserted into the DOM. It does not provide access to the view's `element`.
* `didInsertElement`: This hook is called immediately after the view has been inserted into the DOM. It provides access to the view's `element` and is most useful for integration with an external library. Any explicit DOM setup code should be limited to this hook.
* `willDestroyElement`: This hook is called immediately before the element is removed from the DOM. This is your opportunity to tear down any external state associated with the DOM node. Like `didInsertElement`, it is most useful for integration with external libraries.
* `willClearRender`: This hook is called immediately before a view is re-rendered. This is useful if you want to perform some teardown immediately before a view is re-rendered.
* `becameVisible`: This hook is called after a view's `isVisible` property, or one of its ancestor's `isVisible` property, changes to true and the associated element becomes visible. Note that this hook is only reliable if all visibility is routed through the `isVisible` property.
* `becameHidden`: This hook is called after a view's `isVisible` property, or one of its ancestor's `isVisible` property, changes to false and the associated element becomes hidden. Note that this hook is only reliable if all visibility is routed through the `isVisible` property.
Apps can implement these hooks by defining a method by the hook's name on the view. Alternatively, it is possible to register a listener for the hook on a view:
```javascript
view.on('willClearRender', function() {
// do something with view
});
```
#### Virtual Views
As described above, Handlebars creates views in the view hierarchy to
represent bound values. Every time you use a Handlebars expression,
whether it's a simple value or a block helper like `{{#with}}` or
`{{#if}}`, Handlebars creates a new view.
Because Ember uses these views for internal bookkeeping only,
they are hidden from the view's public `parentView` and `childViews`
API. The public view hierarchy reflects only views created using the
`{{view}}` helper or through `ContainerView` (see below).
For example, consider the following Handlebars template:
```handlebars
<h1>Joe's Lamprey Shack</h1>
{{controller.restaurantHours}}
{{#view App.FDAContactForm}}
If you are experiencing discomfort from eating at Joe's Lamprey Shack,
please use the form below to submit a complaint to the FDA.
{{#if controller.allowComplaints}}
{{view Ember.TextArea valueBinding="controller.complaint"}}
<button {{action 'submitComplaint'}}>Submit</button>
{{/if}}
{{/view}}
```
Rendering this template would create a hierarchy like this:
<figure>
<img src="/images/view-guide/public-view-hierarchy.png">
</figure>
Behind the scenes, Ember tracks additional virtual views for the
Handlebars expressions:
<figure>
<img src="/images/view-guide/virtual-view-hierarchy.png">
</figure>
From inside of the `TextArea`, the `parentView` would point to the
`FDAContactForm` and the `FDAContactForm`'s `childViews` would be an
array of the single `TextArea` view.
You can see the internal view hierarchy by asking for the `_parentView`
or `_childViews`, which will include virtual views:
```javascript
var _childViews = view.get('_childViews');
console.log(_childViews.objectAt(0).toString());
//> <Ember._HandlebarsBoundView:ember1234>
```
**Warning!** You may not rely on these internal APIs in application code.
They may change at any time and have no public contract. The return
value may not be observable or bindable. It may not be an Ember object.
If you feel the need to use them, please contact us so we can expose a better
public API for your use-case.
Bottom line: This API is like XML. If you think you have a use for it,
you may not yet understand the problem enough. Reconsider!
#### Event Bubbling
One responsibility of views is to respond to primitive user events
and translate them into events that have semantic meaning for your
application.
For example, a delete button translates the primitive `click` event into
the application-specific "remove this item from an array."
In order to respond to user events, create a new view subclass that
implements that event as a method:
```javascript
App.DeleteButton = Ember.View.create({
click: function(event) {
var item = this.get('model');
this.get('controller').send('deleteItem', item);
}
});
```
When you create a new `Ember.Application` instance, it registers an event
handler for each native browser event using jQuery's event delegation
API. When the user triggers an event, the application's event dispatcher
will find the view nearest to the event target that implements the
event.
A view implements an event by defining a method corresponding to the
event name. When the event name is made up of multiple words (like
`mouseup`) the method name should be the camelized form of the event
name (`mouseUp`).
Events will bubble up the view hierarchy until the event reaches the
root view. An event handler can stop propagation using the same
techniques as normal jQuery event handlers:
* `return false` from the method
* `event.stopPropagation`
For example, imagine you defined the following view classes:
```javascript
App.GrandparentView = Ember.View.extend({
click: function() {
console.log('Grandparent!');
}
});
App.ParentView = Ember.View.extend({
click: function() {
console.log('Parent!');
return false;
}
});
App.ChildView = Ember.View.extend({
click: function() {
console.log('Child!');
}
});
```
And here's the Handlebars template that uses them:
```handlebars
{{#view App.GrandparentView}}
{{#view App.ParentView}}
{{#view App.ChildView}}
<h1>Click me!</h1>
{{/view}}
{{/view}}
{{/view}}
```
If you clicked on the `<h1>`, you'd see the following output in your
browser's console:
```
Child!
Parent!
```
You can see that Ember invokes the handler on the child-most view that
received the event. The event continues to bubble to the `ParentView`,
but does not reach the `GrandparentView` because `ParentView` returns
false from its event handler.
You can use normal event bubbling techniques to implement familiar
patterns. For example, you could implement a `FormView` that defines a
`submit` method. Because the browser triggers the `submit` event when
the user hits enter in a text field, defining a `submit` method on the
form view will "just work".
```javascript
App.FormView = Ember.View.extend({
tagName: "form",
submit: function(event) {
// will be invoked whenever the user triggers
// the browser's `submit` method
}
});
```
```handlebars
{{#view App.FormView}}
{{view Ember.TextField valueBinding="controller.firstName"}}
{{view Ember.TextField valueBinding="controller.lastName"}}
<button type="submit">Done</button>
{{/view}}
```
#### Adding New Events
Ember comes with built-in support for the following native browser
events:
<table class="figure">
<thead>
<tr><th>Event Name</th><th>Method Name</th></tr>
</thead>
<tbody>
<tr><td>touchstart</td><td>touchStart</td></tr>
<tr><td>touchmove</td><td>touchMove</td></tr>
<tr><td>touchend</td><td>touchEnd</td></tr>
<tr><td>touchcancel</td><td>touchCancel</td></tr>
<tr><td>keydown</td><td>keyDown</td></tr>
<tr><td>keyup</td><td>keyUp</td></tr>
<tr><td>keypress</td><td>keyPress</td></tr>
<tr><td>mousedown</td><td>mouseDown</td></tr>
<tr><td>mouseup</td><td>mouseUp</td></tr>
<tr><td>contextmenu</td><td>contextMenu</td></tr>
<tr><td>click</td><td>click</td></tr>
<tr><td>dblclick</td><td>doubleClick</td></tr>
<tr><td>mousemove</td><td>mouseMove</td></tr>
<tr><td>focusin</td><td>focusIn</td></tr>
<tr><td>focusout</td><td>focusOut</td></tr>
<tr><td>mouseenter</td><td>mouseEnter</td></tr>
<tr><td>mouseleave</td><td>mouseLeave</td></tr>
<tr><td>submit</td><td>submit</td></tr>
<tr><td>change</td><td>change</td></tr>
<tr><td>dragstart</td><td>dragStart</td></tr>
<tr><td>drag</td><td>drag</td></tr>
<tr><td>dragenter</td><td>dragEnter</td></tr>
<tr><td>dragleave</td><td>dragLeave</td></tr>
<tr><td>dragover</td><td>dragOver</td></tr>
<tr><td>drop</td><td>drop</td></tr>
<tr><td>dragend</td><td>dragEnd</td></tr>
</tbody>
</table>
You can add additional events to the event dispatcher when you create a
new application:
```javascript
App = Ember.Application.create({
customEvents: {
// add support for the loadedmetadata media
// player event
'loadedmetadata': "loadedMetadata"
}
});
```
In order for this to work for a custom event, the HTML5 spec must define
the event as "bubbling", or jQuery must have provided an event
delegation shim for the event.
### Templated Views
As you've seen so far in this guide, the majority of views that you will
use in your application are backed by a template. When using templates,
you do not need to programmatically create your view hierarchy because
the template creates it for you.
While rendering, the view's template can append views to its child views
array. Internally, the template's `{{view}}` helper calls the view's
`appendChild` method.
Calling `appendChild` does two things:
1. Adds the child view to the `childViews` array.
2. Immediately renders the child view and adds it to the parent's render
buffer.
<figure>
<img src="/images/view-guide/template-appendChild-interaction.png">
</figure>
You may not call `appendChild` on a view after it has left the rendering
state. A template renders "mixed content" (both views and plain text) so
the parent view does not know exactly where to insert the new child view
once the rendering process has completed.
In the example above, imagine trying to insert a new view inside of
the parent view's `childViews` array. Should it go immediately
after the closing `</div>` of `App.MyView`? Or should it go after the
closing `</div>` of the entire view? There is no good answer that will
always be correct.
Because of this ambiguity, the only way to create a view hierarchy using
templates is via the `{{view}}` helper, which always inserts views
in the right place relative to any plain text.
While this works for most situations, occasionally you may want to have
direct, programmatic control of a view's children. In that case, you can
use `Ember.ContainerView`, which explicitly exposes a public API for
doing so.
### Container Views
Container views contain no plain text. They are composed entirely of
their child views (which may themselves be template-backed).
`ContainerView` exposes two public APIs for changing its contents:
1. A writable `childViews` array into which you can insert `Ember.View`
instances.
2. A `currentView` property that, when set, inserts the new value into
the child views array. If there was a previous value of
`currentView`, it is removed from the `childViews` array.
Here is an example of using the `childViews` API to create a view that
starts with a hypothetical `DescriptionView` and can add a new button at
any time by calling the `addButton` method:
```javascript
App.ToolbarView = Ember.ContainerView.create({
init: function() {
var childViews = this.get('childViews');
var descriptionView = App.DescriptionView.create();
childViews.pushObject(descriptionView);
this.addButton();
return this._super();
},
addButton: function() {
var childViews = this.get('childViews');
var button = Ember.ButtonView.create();
childViews.pushObject(button);
}
});
```
As you can see in the example above, we initialize the `ContainerView`
with two views, and can add additional views during runtime. There is a
convenient shorthand for doing this view setup without having to
override the `init` method:
```javascript
App.ToolbarView = Ember.ContainerView.create({
childViews: ['descriptionView', 'buttonView'],
descriptionView: App.DescriptionView,
buttonView: Ember.ButtonView,
addButton: function() {
var childViews = this.get('childViews');
var button = Ember.ButtonView.create();
childViews.pushObject(button);
}
});
```
As you can see above, when using this shorthand, you specify the
`childViews` as an array of strings. At initialization time, each of the
strings is used as a key to look up a view instance or class. That view
is automatically instantiated, if necessary, and added to the
`childViews` array.
<figure>
<img src="/images/view-guide/container-view-shorthand.png">
</figure>
### Template Scopes
Standard Handlebars templates have the concept of a *context*--the
object from which expressions will be looked up.
Some helpers, like `{{#with}}`, change the context inside their block.
Others, like `{{#if}}`, preserve the context. These are called
"context-preserving helpers."
When a Handlebars template in an Ember app uses an expression
(`{{#if foo.bar}}`), Ember will automatically set up an
observer for that path on the current context.
If the object referenced by the path changes, Ember will automatically
re-render the block with the appropriate context. In the case of a
context-preserving helper, Ember will re-use the original context when
re-rendering the block. Otherwise, Ember will use the new value of the
path as the context.
```handlebars
{{#if controller.isAuthenticated}}
<h1>Welcome {{controller.name}}</h1>
{{/if}}
{{#with controller.user}}
<p>You have {{notificationCount}} notifications.</p>
{{/with}}
```
In the above template, when the `isAuthenticated` property changes from
false to true, Ember will render the block, using the original outer
scope as its context.
The `{{#with}}` helper changes the context of its block to the `user`
property on the current controller. When the `user` property changes,
Ember re-renders the block, using the new value of `controller.user` as
its context.
#### View Scope
In addition to the Handlebars context, templates in Ember also have the
notion of the current view. No matter what the current context is, the
`view` property always references the closest view.
Note that the `view` property never references the internal views
created for block expressions like `{{#if}}`. This allows you to
differentiate between Handlebars contexts, which always work the way
they do in vanilla Handlebars, and the view hierarchy.
Because `view` points to an `Ember.View` instance, you can access any
properties on the view by using an expression like `view.propertyName`.
You can get access to a view's parent using `view.parentView`.
For example, imagine you had a view with the following properties:
```javascript
App.MenuItemView = Ember.View.create({
templateName: 'menu_item_view',
bulletText: '*'
});
```
…and the following template:
```handlebars
{{#with controller}}
{{view.bulletText}} {{name}}
{{/with}}
```
Even though the Handlebars context has changed to the current
controller, you can still access the view's `bulletText` by referencing
`view.bulletText`.
### Template Variables
So far in this guide, we've been handwaving around the use of the
`controller` property in our Handlebars templates. Where does it come
from?
Handlebars contexts in Ember can inherit variables from their parent
contexts. Before Ember looks up a variable in the current context, it
first checks in its template variables. As a template creates new
Handlebars scope, they automatically inherit the variables from their
parent scope.
Ember defines these `view` and `controller` variables, so they are
always found first when an expression uses the `view` or `controller`
names.
As described above, Ember sets the `view` variable on the Handlebars
context whenever a template uses the `{{#view}}` helper. Initially,
Ember sets the `view` variable to the view rendering the template.
Ember sets the `controller` variable on the Handlebars context whenever
a rendered view has a `controller` property. If a view has no
`controller` property, it inherits the `controller` variable from the
most recent view with one.
#### Other Variables
Handlebars helpers in Ember may also specify variables. For example, the
`{{#with controller.person as tom}}` form specifies a `tom` variable
that descendent scopes can access. Even if a child context has a `tom`
property, the `tom` variable will supersede it.
This form has one major benefit: it allows you to shorten long paths
without losing access to the parent scope.
It is especially important in the `{{#each}}` helper, which provides
the `{{#each person in people}}` form.
In this form, descendent context have access to the `person` variable,
but remain in the same scope as where the template invoked the `each`.
```handlebars
{{#with controller.preferences}}
<h1>Title</h1>
<ul>
{{#each person in controller.people}}
{{! prefix here is controller.preferences.prefix }}
<li>{{prefix}}: {{person.fullName}}</li>
{{/each}}
<ul>
{{/with}}
```
Note that these variables inherit through `ContainerView`s, even though
they are not part of the Handlebars context hierarchy.
#### Accessing Template Variables from Views
In most cases, you will need to access these template variables from
inside your templates. In some unusual cases, you may want to access the
variables in-scope from your view's JavaScript code.
You can do this by accessing the view's `templateVariables` property,
which will return a JavaScript object containing the variables that were
in scope when the view was rendered. `ContainerView`s also have access
to this property, which references the template variables in the most
recent template-backed view.
At present, you may not observe or bind a path containing
`templateVariables`.
## Managing Asynchrony
Many Ember concepts, like bindings and computed properties, are designed
to help manage asynchronous behavior.
### Without Ember
We'll start by taking a look at ways to manage asynchronous behavior
using jQuery or event-based MVC frameworks.
Let's use the most common asynchronous behavior in a web application,
making an Ajax request, as an example. The browser APIs for making Ajax
requests provide an asynchronous API. jQuery's wrapper does as well:
```javascript
jQuery.getJSON('/posts/1', function(post) {
$("#post").html("<h1>" + post.title + "</h1>" +
"<div>" + post.body + "</div>");
});
```
In a raw jQuery application, you would use this callback to make
whatever changes you needed to make to the DOM.
When using an event-based MVC framework, you move the logic out of the
callback and into model and view objects. This improves things, but
doesn't get rid of the need to explicitly deal with asynchronous
callbacks:
```javascript
Post = Model.extend({
author: function() {
return [this.salutation, this.name].join(' ')
},
toJSON: function() {
var json = Model.prototype.toJSON.call(this);
json.author = this.author();
return json;
}
});
PostView = View.extend({
init: function(model) {
model.bind('change', this.render, this);
},
template: _.template("<h1><%= title %></h1><h2><%= author %></h2><div><%= body %></div>"),
render: function() {
jQuery(this.element).html(this.template(this.model.toJSON());
return this;
}
});
var post = Post.create();
var postView = PostView.create({ model: post });
jQuery('#posts').append(postView.render().el);
jQuery.getJSON('/posts/1', function(json) {
// set all of the JSON properties on the model
post.set(json);
});
```
This example doesn't use any particular JavaScript library beyond
jQuery, but its approach is typical of event-driven MVC frameworks. It
helps organize the asynchronous events, but asynchronous behavior is
still the core programming model.
### Ember's Approach
In general, Ember's goal is to eliminate explicit forms of asynchronous
behavior. As we'll see later, this gives Ember the ability to coalesce
multiple events that have the same result.
It also provides a higher level of abstraction, eliminating the need to
manually register and unregister event listeners to perform most common
tasks.
You would normally use ember-data for this example, but let's see how
you would model the above example using jQuery for Ajax in Ember.
```javascript
App.Post = Ember.Object.extend({
});
App.PostController = Ember.ObjectController.extend({
author: function() {
return [this.get('salutation'), this.get('name')].join(' ');
}.property('salutation', 'name')
});
App.PostView = Ember.View.extend({
// the controller is the initial context for the template
controller: null,
template: Ember.Handlebars.compile("<h1>{{title}}</h1><h2>{{author}}</h2><div>{{body}}</div>")
});
var post = App.Post.create();
var postController = App.PostController.create({ model: post });
App.PostView.create({ controller: postController }).appendTo('body');
jQuery.getJSON("/posts/1", function(json) {
post.setProperties(json);
});
```
In contrast to the above examples, the Ember approach eliminates the
need to explicitly register an observer when the `post`'s properties
change.
The `{{title}}`, `{{author}}` and `{{body}}` template elements are bound
to those properties on the `PostController`. When the `PostController`'s
model changes, it automatically propagates those changes to the DOM.
Using a computed property for `author` eliminated the need to explicitly
invoke the computation in a callback when the underlying property
changed.
Instead, Ember's binding system automatically follows the trail from the
`salutation` and `name` set in the `getJSON` callback to the computed
property in the `PostController` and all the way into the DOM.
### Benefits
Because Ember is usually responsible for propagating changes, it can
guarantee that a single change is only propagated one time in response
to each user event.
Let's take another look at the `author` computed property.
```javascript
App.PostController = Ember.ObjectController.extend({
author: function() {
return [this.get('salutation'), this.get('name')].join(' ');
}.property('salutation', 'name')
});
```
Because we have specified that it depends on both `salutation` and
`name`, changes to either of those two dependencies will invalidate the
property, which will trigger an update to the `{{author}}` property in
the DOM.
Imagine that in response to a user event, I do something like this:
```javascript
post.set('salutation', "Mrs.");
post.set('name', "Katz");
```
You might imagine that these changes will cause the computed property to
be invalidated twice, causing two updates to the DOM. And in fact, that
is exactly what would happen when using an event-driven framework.
In Ember, the computed property will only recompute once, and the DOM
will only update once.
How?
When you make a change to a property in Ember, it does not immediately
propagate that change. Instead, it invalidates any dependent properties
immediately, but queues the actual change to happen later.
Changing both the `salutation` and `name` properties invalidates the
`author` property twice, but the queue is smart enough to coalesce those
changes.
Once all of the event handlers for the current user event have finished,
Ember flushes the queue, propagating the changes downward. In this case,
that means that the invalidated `author` property will invalidate the
`{{author}}` in the DOM, which will make a single request to recompute
the information and update itself once.
**This mechanism is fundamental to Ember.** In Ember, you should always
assume that the side-effects of a change you make will happen later. By
making that assumption, you allow Ember to coalesce repetitions of the
same side-effect into a single call.
In general, the goal of evented systems is to decouple the data
manipulation from the side effects produced by listeners, so you
shouldn't assume synchronous side effects even in a more event-focused
system. The fact that side effects don't propagate immediately in Ember
eliminates the temptation to cheat and accidentally couple code together
that should be separate.
### Side-Effect Callbacks
Since you can't rely on synchronous side-effects, you may be wondering
how to make sure that certain actions happen at the right time.
For example, imagine that you have a view that contains a button, and
you want to use jQuery UI to style the button. Since a view's `append`
method, like everything else in Ember, defers its side-effects, how can
you execute the jQuery UI code at the right time?
The answer is lifecycle callbacks.
```javascript
App.Button = Ember.View.extend({
tagName: 'button',
template: Ember.Handlebars.compile("{{view.title}}"),
didInsertElement: function() {
this.$().button();
}
});
var button = App.Button.create({
title: "Hi jQuery UI!"
}).appendTo('#something');
```
In this case, as soon as the button actually appears in the DOM, Ember
will trigger the `didInsertElement` callback, and you can do whatever
work you want.
The lifecycle callbacks approach has several benefits, even if we didn't
have to worry about deferred insertion.
*First*, relying on synchronous insertion means leaving it up to the
caller of `appendTo` to trigger any behavior that needs to run
immediately after appending. As your application grows, you may find
that you create the same view in many places, and now need to worry
about that concern everywhere.
The lifecycle callback eliminates the coupling between the code that
instantiates the view and its post-append behavior. In general, we find
that making it impossible to rely on synchronous side-effects leads to
better design in general.
*Second*, because everything about the lifecycle of a view is inside the
view itself, it is very easy for Ember to re-render parts of the DOM
on-demand.
For example, if this button was inside of an `{{#if}}` block, and Ember
needed to switch from the main branch to the `else` section, Ember can
easily instantiate the view and call the lifecycle callbacks.
Because Ember forces you to define a fully-defined view, it can take
control of creating and inserting views in appropriate situations.
This also means that all of the code for working with the DOM is in a
few sanctioned parts of your application, so Ember has more freedom in
the parts of the render process outside of these callbacks.
### Observers
In some rare cases, you will want to perform certain behavior after a
property's changes have propagated. As in the previous section, Ember
provides a mechanism to hook into the property change notifications.
Let's go back to our salutation example.
```javascript
App.PostController = Ember.ObjectController.extend({
author: function() {
return [this.get('salutation'), this.get('name')].join(' ');
}.property('salutation', 'name')
});
```
If we want to be notified when the author changes, we can register an
observer. Let's say that the view object wants to be notified:
```javascript
App.PostView = Ember.View.extend({
controller: null,
template: Ember.Handlebars.compile("<h1>{{title}}</h1><h2>{{author}}</h2><div>{{body}}</div>"),
authorDidChange: function() {
alert("New author name: " + this.get('controller.author'));
}.observes('controller.author')
});
```
Ember triggers observers after it successfully propagates the change. In
this case, that means that Ember will only call the `authorDidChange`
callback once in response to each user event, even if both of `salutation`
and `name` changed.
This gives you the benefits of executing code after the property has
changed, without forcing all property changes to be synchronous. This
basically means that if you need to do some manual work in response to a
change in a computed property, you get the same coalescing benefits as
Ember's binding system.
Finally, you can also register observers manually, outside of an object
definition:
```javascript
App.PostView = Ember.View.extend({
controller: null,
template: Ember.Handlebars.compile("<h1>{{title}}</h1><h2>{{author}}</h2><div>{{body}}</div>"),
didInsertElement: function() {
this.addObserver('controller.author', function() {
alert("New author name: " + this.get('controller.author'));
});
}
});
```
However, when you use the object definition syntax, Ember will
automatically tear down the observers when the object is destroyed. For
example, if an `{{#if}}` statement changes from truthy to falsy, Ember
destroys all of the views defined inside the block. As part of that
process, Ember also disconnects all bindings and inline observers.
If you define an observer manually, you need to make sure you remove it.
In general, you will want to remove observers in the opposite callback
to when you created it. In this case, you will want to remove the
callback in `willDestroyElement`.
```javascript
App.PostView = Ember.View.extend({
controller: null,
template: Ember.Handlebars.compile("<h1>{{title}}</h1><h2>{{author}}</h2><div>{{body}}</div>"),
didInsertElement: function() {
this.addObserver('controller.author', function() {
alert("New author name: " + this.get('controller.author'));
});
},
willDestroyElement: function() {
this.removeObserver('controller.author');
}
});
```
If you added the observer in the `init` method, you would want to tear
it down in the `willDestroy` callback.
In general, you will very rarely want to register a manual observer in
this way. Because of the memory management guarantees, we strongly
recommend that you define your observers as part of the object
definition if possible.
### Routing
There's an entire page dedicated to managing async within the Ember
Router: [Asynchronous Routing](/guides/routing/asynchronous-routing)
## Keeping Templates Up-to-Date
In order to know which part of your HTML to update when an underlying property changes, Handlebars will insert marker elements with a unique ID. If you look at your application while it's running, you might notice these extra elements:
```html
My new car is
<script id="metamorph-0-start" type="text/x-placeholder"></script>
blue
<script id="metamorph-0-end" type="text/x-placeholder"></script>.
```
Because all Handlebars expressions are wrapped in these markers, make sure each HTML tag stays inside the same block. For example, you shouldn't do this:
```handlebars
{{! Don't do it! }}
<div {{#if isUrgent}}class="urgent"{{/if}}>
```
If you want to avoid your property output getting wrapped in these markers, use the `unbound` helper:
```handlebars
My new car is {{unbound color}}.
```
Your output will be free of markers, but be careful, because the output won't be automatically updated!
```html
My new car is blue.
```
## Debugging
### Debugging Ember and Ember Data
Here are some tips you can use to help debug your Ember application.
Also, check out the
[ember-extension](https://github.com/tildeio/ember-extension)
project, which adds an Ember tab to Chrome DevTools that allows you
to inspect Ember objects in your application.
## Routing
#### Log router transitions
```javascript
window.App = Ember.Application.create({
// Basic logging, e.g. "Transitioned into 'post'"
LOG_TRANSITIONS: true,
// Extremely detailed logging, highlighting every internal
// step made while transitioning into a route, including
// `beforeModel`, `model`, and `afterModel` hooks, and
// information about redirects and aborted transitions
LOG_TRANSITIONS_INTERNAL: true
});
```
#### View all registered routes
```javascript
Ember.keys(App.Router.router.recognizer.names)
```
#### Get current route name / path
Ember installs the current route name and path on your
app's `ApplicationController` as the properties
`currentRouteName` and `currentPath`. `currentRouteName`'s
value (e.g. `"comments.edit"`) can be used as the destination parameter of
`transitionTo` and the `{{linkTo}}` Handlebars helper, while
`currentPath` serves as a full descriptor of each
parent route that has been entered (e.g.
`"admin.posts.show.comments.edit"`).
```javascript
// From within a Route
this.controllerFor("application").get("currentRouteName");
this.controllerFor("application").get("currentPath");
// From within a controller, after specifying `needs: ['application']`
this.get('controllers.application.currentRouteName');
this.get('controllers.application.currentPath');
// From the console:
App.__container__.lookup("controller:application").get("currentRouteName")
App.__container__.lookup("controller:application").get("currentPath")
```
## Views / Templates
#### Log view lookups
```javascript
window.App = Ember.Application.create({
LOG_VIEW_LOOKUPS: true
});
```
#### Get the View object from its DOM Element's ID
```javascript
Ember.View.views['ember605']
```
#### View all registered templates
```javascript
Ember.keys(Ember.TEMPLATES)
```
#### Handlebars Debugging Helpers
```handlebars
{{debugger}}
{{log record}}
```
## Controllers
#### Log generated controller
```javascript
window.App = Ember.Application.create({
LOG_ACTIVE_GENERATION: true
});
```
## Ember Data
#### View ember-data's identity map
```javascript
// all records in memory
App.__container__.lookup('store:main').recordCache
// attributes
App.__container__.lookup('store:main').recordCache[2].get('data.attributes')
// loaded associations
App.__container__.lookup('store:main').recordCache[2].get('comments')
```
## Observers / Binding
#### See all observers for a object, key
```javascript
Ember.observersFor(comments, keyName);
```
#### Log object bindings
```javascript
Ember.LOG_BINDINGS = true
```
## Miscellaneous
#### View an instance of something from the container
```javascript
App.__container__.lookup("controller:posts")
App.__container__.lookup("route:application")
```
#### Dealing with deprecations
```javascript
Ember.ENV.RAISE_ON_DEPRECATION = true
Ember.LOG_STACKTRACE_ON_DEPRECATION = true
```
#### Implement an Ember.onerror hook to log all errors in production
```javascript
Ember.onerror = function(error) {
Em.$.ajax('/error-notification', {
type: 'POST',
data: {
stack: error.stack,
otherInformation: 'exception message'
}
});
}
```
#### Import the console
If you are using imports with Ember, be sure to import the console:
```javascript
Ember = {
imports: {
Handlebars: Handlebars,
jQuery: $,
console: window.console
}
};
```
#### Errors within an `RSVP.Promise`
There are times when dealing with promises that it seems like any errors
are being 'swallowed', and not properly raised. This makes it extremely
difficult to track down where a given issue is coming from. Thankfully,
`RSVP` has a solution for this problem built in.
You can provide an `onerror` function that will be called with the error
details if any errors occur within your promise. This function can be anything
but a common practice is to call `console.assert` to dump the error to the
console.
```javascript
Ember.RSVP.configure('onerror', function(error) {
Ember.Logger.assert(false, error);
});
```
#### Errors within `Ember.run.later` ([Backburner.js](https://github.com/ebryn/backburner.js))
Backburner has support for stitching the stacktraces together so that you can
track down where an erroring `Ember.run.later` is being initiated from. Unfortunately,
this is quite slow and is not appropriate for production or even normal development.
To enable this mode you can set:
```javascript
Ember.run.backburner.DEBUG = true;
```
## The Run Loop
Ember's internals and most of the code you will write in your applications takes place in a run loop. The run loop is used to
batch, and order (or reorder) work in a way that is most effective and efficient.
It does so by scheduling work on specific queues. These queues have a priority,
and are processed to completion in priority order.
## Why is this useful?
Very often, batching similar work has benefits. Web browsers do something quite similar
by batching changes to the DOM.
Consider the following HTML snippet:
```html
<div id="foo"></div>
<div id="bar"></div>
<div id="baz"></div>
```
and executing the following code:
```js
foo.style.height = "500px" // write
foo.offsetHeight // read (recalculate style, layout, expensive!)
bar.style.height = "400px" // write
bar.offsetHeight // read (recalculate style, layout, expensive!)
baz.style.height = "200px" // write
baz.offsetHeight // read (recalculate style, layout, expensive!)
```
In this example, the sequence of code forced the browser to recalculate style,
and relayout after each step. However, if we were able to batch similar jobs together,
the browser would have only needed to recalulate the style and layout once.
```js
foo.style.height = "500px" // write
bar.style.height = "400px" // write
baz.style.height = "200px" // write
foo.offsetHeight // read (recalculate style, layout, expensive!)
bar.offsetHeight // read (fast since style and layout is already known)
baz.offsetHeight // read (fast since style and layout is already known)
```
Interestingly, this pattern holds true for many other types of work. Essentially,
batching similar work allows for better pipelining, and further optimization.
Let's look at a similar example that is optimized in Ember, starting with a `User` object:
```js
var User = Ember.Object.extend({
firstName: null,
lastName: null,
fullName: function() {
return this.get('firstName') + ' ' + this.get('lastName');
}.property('firstName', 'lastName')
});
```
and a template to display its attributes:
```handlebars
{{firstName}}
{{fullName}}
```
If we execute the following code without the run loop:
```js
var user = User.create({firstName:'Tom', lastName:'Huda'});
user.set('firstName', 'Yehuda');
// {{firstName}} and {{fullName}} are updated
user.set('lastName', 'Katz');
// {{lastName}} and {{fullName}} are updated
```
We see that the browser will rerender the template twice.
```js
var user = User.create({firstName:'Tom', lastName:'Huda'});
user.set('firstName', 'Yehuda');
user.set('lastName', 'Katz');
// {{firstName}} {{lastName}} and {{fullName}} are updated
```
However, if we have the run loop in the above code, the browser will only rerender the template once the attributes have all been set.
```js
var user = User.create({firstName:'Tom', lastName:'Huda'});
user.set('firstName', 'Yehuda');
user.set('lastName', 'Katz');
user.set('firstName', 'Tom');
user.set('lastName', 'Huda');
```
In the above example with the run loop, since the user's attributes end up at the same values as before execution, the template will not even rerender!
It is of course possible to optimize these scenarios on a case-by-case basis,
but getting them for free is much nicer. Using the run loop, we can apply these
classes of optimizations not only for each scenario, but holistically app-wide.
## How does the Run Loop work in Ember?
As mentioned earlier, we schedule work (in the form of function invocations) on
queues, and these queues are processed to completion in priority order.
What are the queues, and what is their priority order?
```js
Ember.run.queues
// => ["sync", "actions", "routerTransitions", "render", "afterRender", "destroy"]
```
Because the priority is first to last, the "sync" queue has higher priority than the "render" or "destroy" queue.
## What happens in these queues?
* The `sync` queue contains binding synchronization jobs
* The `actions` queue is the general work queue and will typically contain scheduled tasks e.g. promises
* The `routerTransitions` queue contains transition jobs in the router
* The `render` queue contains jobs meant for rendering, these will typically update the DOM
* The `afterRender` contains jobs meant to be run after all previously scheduled render tasks are complete. This is often good for 3rd-party DOM manipulation libraries, that should only be run after an entire tree of DOM has been updated
* The `destroy` queue contains jobs to finish the teardown of objects other jobs have scheduled to destroy
## In what order are jobs executed on the queues?
The algorithm works this way:
1. Let the highest priority queue with pending jobs be: `CURRENT_QUEUE`, if there are no queues with pending jobs the run loop is complete
2. Let a new temporary queue be defined as `WORK_QUEUE`
3. Move jobs from `CURRENT_QUEUE` into `WORK_QUEUE`
4. Process all the jobs sequentially in `WORK_QUEUE`
5. Return to Step 1
## An example of the internals
Rather than writing the higher level app code that internally invokes the various
run loop scheduling functions, we have stripped away the covers, and shown the raw run-loop interactions.
Working with this API directly is not common in most Ember apps, but understanding this example will
help you to understand the run-loops algorithm, which will make you a better Ember developer.
<iframe src="http://emberjs.com.s3.amazonaws.com/run-loop-guide/index.html" width="678" height="410" style="border:1px solid rgb(170, 170, 170);margin-bottom:1.5em;"></iframe>
## FAQs
#### What do I need to know to get started with Ember?
For basic Ember app development scenarios, nothing. All common paths are paved nicely
for you and don't require working with the run loop directly.
#### What do I need to know to actually build an app?
It is possible to build good apps without working with the run loop directly, so if
you don't feel the need to do so, don't.
#### What scenarios will require me to understand the run loop?
The most common case you will run into is integrating with a non-Ember API
that includes some sort of asynchronous callback. For example:
- AJAX callbacks
- DOM update and event callbacks
- Websocket callbacks
- `setTimeout` and `setInterval` callbacks
- `postMessage` and `messageChannel` event handlers
You should begin a run loop when the callback fires.
#### How do I tell Ember to start a run loop?
```js
$('a').click(function(){
Ember.run(function(){ // begin loop
// Code that results in jobs being scheduled goes here
}); // end loop, jobs are flushed and executed
});
```
#### What happens if I forget to start a run loop in an async handler?
As mentioned above, you should wrap any non-Ember async callbacks in `Ember.run`.
If you don't, Ember will try to approximate a beginning and end for you. Here
is some pseudocode to describe what happens:
```js
$('a').click(function(){
// Ember or runloop related code.
Ember.run.start();
// 1. we detect you need a run-loop
// 2. we start one for you, but we don't really know when it ends, so we guess
nextTick(function() {
Ember.run.end()
}, 0);
});
```
This is suboptimal because the current JS frame is allowed to end before the run loop is
flushed, which sometimes means the browser will take the opportunity to do other things,
like garbage collection. GC running in between data changing and DOM rerendering can cause visual lag and should be minimized.
#### When I am in testing mode, why are run-loop autoruns disabled?
Some of Ember's test helpers are promises that wait for the run loop to empty before resolving. This leads to resolving too early if there is code that is outside the run loop and gives erroneous test failures. Disabling autoruns help you identify these scenarios and helps both your testing and your application!
# Contributing to Ember.js
## Adding New Features
In general, new feature development should be done on master.
Bugfixes should not introduce new APIs or break existing APIs, and do
not need feature flags.
Features can introduce new APIs, and need feature flags. They should not
be applied to the release or beta branches, since SemVer requires
bumping the minor version to introduce new features.
Security fixes should not introduce new APIs, but may, if strictly
necessary, break existing APIs. Such breakages should be as limited as
possible.
### Bug Fixes
#### Urgent Bug Fixes
Urgent bugfixes are bugfixes that need to be applied to the existing
release branch. If possible, they should be made on master and prefixed
with [BUGFIX release].
#### Beta Bug Fixes
Beta bugfixes are bugfixes that need to be applied to the beta branch.
If possible, they should be made on master and tagged with [BUGFIX
beta].
#### Security Fixes
Security fixes need to be applied to the beta branch, the current
release branch, and the previous tag. If possible, they should be made
on master and tagged with [SECURITY].
### Features
Features must always be wrapped in a feature flag. Tests for the feature
must also be wrapped in a feature flag.
Because the build-tools will process feature-flags, flags must use
precisely this format. We are choosing conditionals rather than a block
form because functions change the surrounding scope and may introduce
problems with early return.
```js
if (Ember.FEATURES.isEnabled("feature")) {
// implementation
}
```
Tests will always run with all features on, so make sure that any tests
for the feature are passing against the current state of the feature.
#### Commits
Commits related to a specific feature should include a prefix like
[FEATURE htmlbars]. This will allow us to quickly identify all commits
for a specific feature in the future. Features will never be applied to
beta or release branches. Once a beta or release branch has been cut, it
contains all of the new features it will ever have.
If a feature has made it into beta or release, and you make a commit to
master that fixes a bug in the feature, treat it like a bugfix as
described above.
#### Feature Naming Conventions
```js
Ember.FEATURES["<packageName>-<feature>"] // if package specific
Ember.FEATURES["container-factory-injections"]
Ember.FEATURES["htmlbars"]
```
### Builds
The Canary build, which is based off master, will include all features,
guarded by the conditionals in the original source. This means that
users of the canary build can enable whatever features they want by
enabling them before creating their Ember.Application.
```js
Ember.FEATURES["htmlbars"] = true;
```
### `features.json`
The root of the repository will contain a features.json file, which will
contain a list of features that should be enabled for beta or release
builds.
This file is populated when branching, and may not gain additional
features after the original branch. It may remove features.
```js
{
"htmlbars": true
}
```
The build process will remove any features not included in the list, and
remove the conditionals for features in the list.
### Travis Testing
For a new PR:
1. Travis will test against master with all feature flags on.
2. If a commit is tagged with [BUGFIX beta], Travis will also
cherry-pick the commit into beta, and run the tests on that
branch. If the commit doesn't apply cleanly or the tests fail, the
tests will fail.
3. If a commit is tagged with [BUGFIX release], Travis will also cherry-pick
the commit into release, and run the test on that branch. If the commit
doesn't apply cleanly or the tests fail, the tests will fail.
For a new commit to master:
1. Travis will run the tests as described above.
2. If the build passes, Travis will cherry-pick the commits into the
appropriate branches.
The idea is that new commits should be submitted as PRs to ensure they
apply cleanly, and once the merge button is pressed, Travis will apply
them to the right branches.
### Go/No-Go Process
Every six weeks, the core team goes through the following process.
#### Beta Branch
All remaining features on the beta branch are vetted for readiness. If
any feature isn't ready, it is removed from features.json.
Once this is done, the beta branch is tagged and merged into release.
#### Master Branch
All features on the master branch are vetted for readiness. In order for
a feature to be considered "ready" at this stage, it must be ready as-is
with no blockers. Features are a no-go even if they are close and
additional work on the beta branch would make it ready.
Because this process happens every six weeks, there will be another
opportunity for a feature to make it soon enough.
Once this is done, the master branch is merged into beta. A
`features.json` file is added with the features that are ready.
### Beta Releases
Every week, we repeat the Go/No-Go process for the features that remain
on the beta branch. Any feature that has become unready is removed from
the features.json.
Once this is done, a Beta release is tagged and pushed.
## Repositories
Ember is made up of several libraries. If you wish to add a feature or fix a bug please file a pull request against the appropriate repository. Be sure to check the libraries listed below before making changes in the Ember.js repository.
# Main Repositories
**Ember.js** - The main repository for Ember.
* [https://github.com/emberjs/ember.js](https://github.com/emberjs/ember.js)
**Ember Data** - A data persistence library for Ember.js.
* [https://github.com/emberjs/data](https://github.com/emberjs/data)
**Ember Website** - Source for [http://www.emberjs.com](http://www.emberjs.com) including these guides.
* [https://github.com/emberjs/website](https://github.com/emberjs/website)
# Libraries Used By Ember
These libraries are part of the Ember.js source, but development of them takes place in a seperate repository.
## `packages/ember-metal/lib/vendor/backburner.js`
* **backburner.js** - Implements the Ember run loop.
* [https://github.com/ebryn/backburner.js](https://github.com/ebryn/backburner.js)
## `packages/ember-routing/lib/vendor/route-recognizer.js`
* **route-recognizer.js** - A lightweight JavaScript library that matches paths against registered routes.
* [https://github.com/tildeio/route-recognizer](https://github.com/tildeio/route-recognizer)
## `packages/ember-routing/lib/vendor/router.js`
* **router.js** - A lightweight JavaScript library that builds on route-recognizer and rsvp to provide an API for handling routes.
* [https://github.com/tildeio/router.js](https://github.com/tildeio/router.js)
## `packages/metamorph`
* **Metamorph.js** - Used by Ember for databinding handlebars templates
* [https://github.com/tomhuda/metamorph.js](https://github.com/tomhuda/metamorph.js)
## `packages/rsvp`
* **RSVP.js** - Implementation of the of Promises/A+ spec used by Ember.
* [https://github.com/tildeio/rsvp.js](https://github.com/tildeio/rsvp.js)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment