I'm trying to wrap my head around the model
property or a route vs. the content
property of the controller. If you set the model
property in a route, does this automatically set it to the content
property in a generated controller.
Also, I think the content
property of the controller allows you to access the attributes of that object in the template, is that true?
I read the docs and still am having trouble digesting some of these conventions.
I'm trying to wrap my head around the model
property or a route vs. the content
property of the controller. If you set the model
property in a route, does this automatically set it to the content
property in a generated controller.
Also, I think the content
property of the controller allows you to access the attributes of that object in the template, is that true?
I read the docs and still am having trouble digesting some of these conventions.
Share Improve this question edited Apr 9, 2013 at 14:45 MilkyWayJoe 9,0922 gold badges40 silver badges53 bronze badges asked Apr 9, 2013 at 13:28 brandonhilkertbrandonhilkert 4,4857 gold badges26 silver badges39 bronze badges 2- 2 Have you seen any of the introduction screencasts that show how to use routes/views/controllers/models? I did one a month ago that covers the basics in 36 minutes toranbillups./blog/archive/2013/03/02/… – Toran Billups Commented Apr 9, 2013 at 13:43
- I haven't seen that one. I watched this one (youtube./watch?v=7O9X5oeAJm4) and it really helped me understand the overall structure of things. I'll check this one out. Thanks! – brandonhilkert Commented Apr 9, 2013 at 14:05
1 Answer
Reset to default 7As answered here, Ember.Route
has a model
function which allows you to set an object or a collection of objects as the model of that route. Routes that deal with a single object should have a controller that extends Ember.ObjectController
while routes that deal with a collection of objects should have a controller that extends Ember.ArrayController
.
Subsequently, in the Route
workflow, the data ing from the model
hook is set into the controller's content
property via setupController
hook.
The routes have their own workflow to setup their controllers, so by default this method will be called and populate the content with the model. Consider the following:
fiddle
App.Email = DS.Model.extend({
address: DS.attr('string'),
isActive: DS.attr('boolean')
});
App.Router.map(function() {
this.resource('emails', function() {
this.route('email', {path: ':email_id'});
});
});
App.EmailsRoute = Ember.Route.extend({
model: function() {
return App.Email.find();
}
});
App.EmailRoute = Ember.Route.extend({
model: function(params) {
return App.Email.find(params.email_id);
}
});
App.EmailsController = Ember.ArrayController.extend();
App.EmailController = Ember.ObjectController.extend();
The framework should generate the default code for these routes in order to setup the controller, which would look like this (and you can override if you want):
App.EmailsRoute = Ember.Route.extend({
...
setupController: function(controller, model) {
controller.set('content', model);
}
...
});
There are cases (see question/answer linked above) in which you may need/want to override these methods to do something different than the default functionality, for example:
fiddle
App.EmailsRoute = Ember.Route.extend({
model: function(params) {
return [{id: 1, address: '[email protected]'}];
},
setupController: function(controller, model) {
// here, controller is whatever controller this route needs
// by conventions, it knows it should be EmailsController
// of the type ArrayController
// model is whatever was returned by the model function above
// the content is a "bag" which can be filled with a model or any
// other object you need. Just keep in mind your view layer will
// be referring to this object later on
controller.set('content', model);
// you can set other properties of the controller here too
controller.set('applyFilter', true);
}
});
Now the templates will be able to access the data in the controller. The example below iterates through a collection of objects (App.Email
) in the EmailsController
. Any public attribute in this collection or in its child objects are accessible here, one example is {{email.address}}
:
<script type="text/x-handlebars" data-template-name="emails">
<ul>
{{#each email in controller}}
<li>
{{#linkTo emails.email email}}
{{email.address}}
{{/linkTo}}
</li>
{{/each}}
</ul>
{{outlet}}
</script>
Note that the template is not talking directly to the model, but rather to the content
, which was assigned with data from the model. Like I said, you can stash any object in the content or model via routes, so you're not tied to use DS.Model
nor the architecture is strongly coupled.
If this model, instead of App.Email
type, had a different type with different attributes, it would also be accessible here, with limitations tho. If an attribute of the model is a collection, it cannot be accessed through index (e.g. {{email.messages[0].body}}
wouldn't work). The best course of action in this case, would be a puted property in the controller which would give you direct access to the first item of the messages collection of the email, if it had one.