Router is the core part of Ember. Every time we go to a new URL it means the route object is called with our params and stuff. These are the hooks sorted in order in which they are called
- enter (private)
- activate - executed when entering the route
- deserialize (private)
- model (formely deserialize) - takes the params and returns a model
which is set to the route’s
currentModel - serialize - used to generate dynamic segments in the URL from a model
- setupController - takes
currentModeland sets it to the controller’scontentby default - renderTemplate - takes current controller and what
modelreturns and renders the template with an appropriate name - deactivate - executed when exiting the route (called by exit internally)
- exit (private, requires call to
this._super)
Now let’s take a look at them in more detail
activate/deactivate
These were formely known as enter/exit, which are now marked as
private. activate will be executed when user enters a route, be it
from a transition or from a URL directly, and deactivate is executed
when user transitions away from the route.
One of the most common use cases for me is doing a transaction rollback
in deactivate.
App.PostsNewRoute = Ember.Route.extend({
deactivate: function() {
this.modelFor("postsNew").get("transaction").rollback();
}
});
I find this mostly useful when having a new record form (or even when editing a record), where you basically want to rollback any changes which happened when the user exits the route. It doesn’t matter if the user submits the form first, because then the transaction will be comitted and there will be nothing to rollback.
model/serialize
To allow Ember to work with dynamic segments in the URLs we need to
teach it how to serialize and deserialize our models. When we enter a
URL directly (or reload the page) model will be called with params
from the dynamic segments. Let’s take a look at an example
App.Router.map(function() {
this.resource("post", { path: "/:post_id" });
});
App.PostRoute = Ember.Route.extend({
model: function(params) {
return App.Post.find(params.post_id);
}
});
This is exactly what Ember will auto generate for us, along with a serialize hook
App.PostRoute = Ember.Route.extend({
model: function(params) {
return App.Post.find(params.post_id);
},
serialize: function(model) {
return { post_id: model.id };
}
});
it is important to note here that if we’re transitioning from a
different route our model hook will not be called.
setupController
One step further after model comes setupController, which is meant
to set additional properties on the controller, or override it’s
content.
But beware, there is no autogenerated setupController hook which sets to content,
this is done even before setupController is called in the setup hook of the route. This is basically simulates the following:
setupController: function(controller, model) {
controller.set("content", model);
}
But it also means we can set additional properties on the controller without needing to explicitly set the content
setupController: function(controller, model) {
controller.set("foo", "bar");
}
renderTemplate
The last one of the hooks is renderTemplate where you tell which
template you want to render in which outlet.
By default renderTemplate will call this.render as follows
App.PostRoute = App.Route.extend({
renderTemplate: function() {
this.render("post", {
into: "application",
outlet: "main",
controller: "post"
});
}
});
In this case render will render the post template into the
application template’s main outlet with the PostController.
This is the place where you can chose to render into other outlets. For
example let’s say that your application template has a sidebar outlet
{{outlet sidebar}}.
App.PostRoute = App.Route.extend({
renderTemplate: function() {
// render with the defaults
this.render();
// and once more for the sidebar outlet
this.render("similarPosts", {
into: "application",
outlet: "sidebar"
});
}
});
Important notes about controllerFor and modelFor
While calling controllerFor("posts") returns an instance of
PostsController, calling modelFor("posts") doesn’t return
content
of the PostController. Instead it looks up the PostsRoute and
returns it’s currentModel which is set when we return a value from the
model hook.
Let’s see an example
App.PostsRoute = Ember.Route.extend({
setupController: function(controller) {
controller.set("content", App.Post.find());
}
});
This will cause issues if we decide to use modelFor later on.
PostsRoute will not have anything in currentModel and modelFor
will return undefined, which might look weird as the controller has a
content properly set.
Ember.js: Using Transactions in Ember Data - part 1
Ember.js: render, control, partial, view, template
Ember.js