Ember - What's the difference between controller's content and model property - javascript

In ember's official guide, it provides two ways to set the controller's underlying object.
First is setting the model property:
App.SongsRoute = Ember.Route.extend({
setupController: function(controller, playlist) {
controller.set('model', playlist.get('songs'));
}
});
Second is setting the content property:
MyApp.listController = Ember.ArrayController.create();
$.get('people.json', function(data) {
MyApp.listController.set('content', data);
});
Are these two properties represent the same thing? Which way should i use?

It seems they are the same thing,
https://github.com/emberjs/ember.js/blob/v1.3.0/packages/ember-runtime/lib/controllers/controller.js#L44
Ember.ControllerMixin = Ember.Mixin.create(Ember.ActionHandler, {
....
model: Ember.computed.alias('content'),
....
The model property is an alias for content.
Also,
https://github.com/emberjs/ember.js/blob/v1.3.0/packages/ember-routing/lib/system/route.js#L849
which mentions that,
By default, the `setupController` hook sets the `content` property of
the controller to the `model`.
UPDATE
Deprecated since v1.7.0 and the code placed in a mixin.
https://github.com/emberjs/ember.js/blob/v2.12.0/packages/ember-runtime/lib/mixins/controller.js
Along with the related deprecation mixin.
https://github.com/emberjs/ember.js/blob/v2.12.0/packages/ember-runtime/lib/mixins/controller_content_model_alias_deprecation.js

In the documentation - http://emberjs.com/api/classes/Ember.Controller.html#property_model - it clearly states that when retrieving or modifying a controller's model, the model property should be used instead of the content property.

Related

Ember issue passing data to template using this.render

I want to render a template using render() and want to pass some data(model)
I get the data in template if I pass the parameter as model
model: this.controllerFor(this.routeName).someModel
this.render('my-template', {
into: 'application',
outlet: 'myOutlet',
model: this.controllerFor(this.routeName).someModel
});
But the below does not work. Is there some restriction on naming for the passed model ?
this.render('my-template', {
into: 'application',
outlet: 'flyout',
myModel: this.controllerFor(this.routeName).someModel
});
The property you are passing isn't the name for your model, it is your model.
Whatever you pass as the model property will be set as the model property on the corresponding controller.
Relevant check that ember does under the hood of render() is the following:
if (options && options.model) {
controller.set('model', options.model);
}
where options is what you pass as the second argument to render().
One thing worth noting is that this just sets controller.model to controller.someModel, which is redundant since you already have access to this data.
The render method has two parameters: name and options.
The options properties are:
into
outlet
controller
model
There is nothing called myModel. See docs.

Model object not preserved when using hash for model in ember route

EDIT: I've set up an actual repro of the issue on JSBIN
Been trying to resolve this for a while now and I'm clearly not understanding how the relationship between model and setupController works. I have a model which is returning a hash; the result of two find calls:
model(params) {
return Ember.RSVP.hash({
course: this.store.find('course', params.course_id),
topics: this.store.find('topic', { course_id: params.course_id })
});
},
The first time setupController gets called, the value of model if as expected, a hash like { course: <Class>, topics: <Class> }. Awesome, that's what I want.
However, the next time setupController gets called (for example, transition to another route and then press the back button in the browser), the model is now just the course <Class>:
setupController(controller, model) {
// when first called model will be { course: <Class>, topics: <Class> }
// next time entered, model will just be <Class> (just the value of "course" )
// why is the model object not preserved?
controller.set('model', model.course);
controller.set('topics', model.topics);
}}
If I just make model() return a single resource, it's the same every time:
model(params) { return this.store.find('course', params.course_id); }
// now `model` will always be "course" in setupController
Why is the original model not preserved when using a hash result? Am I doing something wrong?
You're sending the model color when you're linking here:
{{#link-to 'color' color}}{{color.name}}{{/link-to}}
Because of that, the model hooks aren't run. If you change that to color.id, it'll work.
It's mentioned here.
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.
Looking at it, the original model will not be preserved because on setupController, you are calling controller.set('model', model.course). When it first loads, its called the model(params {} function appropriately, but on back button transitions and certain {{link-to}} calls, that isn't always the case.
In your setupController, try changing it to controller.set('course', model.course);, that way you aren't overwriting your model on execution as well and it will always be able to find it.

Looping over an Ember.js promise

I am trying to loop over what I believe to be an Ember promise, but all I can seem to get returned is an object, when it should be an array.
jsbin: http://emberjs.jsbin.com/qakine/1/edit
If I just loop over the items in the template then I have no issues, but I want to be able to interact with the array items in my controller. Any help appreciated.
Quite a few things here, let me see if I can remember them all:
When you have a route under a resource, the routes and controllers of that route should take their parent's name.
App.Router.map(function() {
this.resource("parent", function(){
this.route("child");
});
});
App.ParentChildRoute...
App.ParentChildController...
Handlebars can't access normal functions from your controller, this should be converted into a computed property.
App.ParentChildController = Ember.ObjectController.extend({
middleNames: function(){
...
}.property('middles.[]')
});
naming is case sensitive
{{#each name in middlenames}}
should be
{{#each name in middleNames}}
Example: http://emberjs.jsbin.com/cowibi/1/edit
I created an new example based on yours to make things clear. You can check it out here:
http://emberjs.jsbin.com/hokabe/4/edit
For Ember route's model hook, if the return value is a promise, the route will wait for the promise resolved and pass the resolved value to controller's model property.
And a App.Parent instance's middles property returns a promise (actually it's a DS.PromiseArray instance) which will resolve a middles array (actually it's a DS.ManyArray instance).
so for getting children you can simply do this:
App.ParentMiddlesRoute = Ember.Route.extend({
model: function() {
return this.modelFor('parent').get('middles');
}
});
Note that modelFor argument is a route name but not a model name. It means "Get the model from given route".

Ember js: How to retrieve the underlying model from a controller

I am trying to retrieve the underlying model object from a controller so that it can be persisted (I am not using ember-data). The obvious way would simply be:
controller.get('content');
But this doesn't work. The problem can be summed up as follows:
controller.set("content", model);
sets the content as expected and at this point
controller.get('content');
works as expected. But if I then decorate the controller with other properties eg.
controller.set('IamNotPartOfTheModel', false);
then suddenly the 'content' includes this new property. I would've expected the content to remain unchanged and the new property to only be applied to the controller itself. I understand the controller is a proxy for the model so for the most part they are treated as one and the same but surely they should still be separable when needed? The whole point of this pattern is to separate data that should be stored from data that is just temporary. Am I missing something?
To have your display specific properties out of the model, just specify them explicitly in the controller... Otherwise the controller acts as a proxy for its model... just have the property "iamNotPartOfTheModel" in your controller
App.IndexController = Ember.ObjectController.extend({
iamNotPartOfTheModel: null
})
Sample fiddle here
Your controller needs to interface to some kind of model. You can't separate the persisted model from the controller except by some kind of object reference. Even if you don't use ember-data, you'll still need to create objects which then plug into the content of the controller. Have a look at Evil Trout's blog for an implementation of ember without ember-data. Its a great starting point.

Ember.js (pre4) array controller not keeping state

Edit 2013-03-02
This appears to be resolved in RC1
In previous versions of Ember.js, controllers would keep state assigned to them, but this seems to be an issue in Pre4.
So if I were to have this controller
App.UsersController = Ember.ArrayController.extend({
content: ['mike', 'jen', 'sofia'],
_content_observer: (function(){
/* I'm called, but my author doesn't know why */
console.log('Content was altered! But why? And by whom?');
}).observes('content')
});
The content is overwritten for some unexplained reason. I don't want to use ember data, but it seems like I'm being forced that direction.
This JS Fiddle exemplifies the issue.
What's going on? How do I stop it or is this so engrained in embers opinionatedness that I need to just accept it and go with the flow?
Edit
Taking this a bit further, it appears that whatever is setup as the model will be set to the content value, even if you override the setupController hook.
e.g.:
UsersRoute = Ember.Route.extend({
model: function() {
/*I should never be called, but I am. How curious.*/
return ['This','Shouldnt','Be','Assigned'];
},
setupController: function() {
/* According to http://emberjs.com/guides/routing/specifying-a-routes-model/, I should prevent the model from being assigned to content, but I don't */
}
});
The UsersController.content will end up with the value ['This','Shouldnt','Be','Assigned']
See this updated fiddle
This isn't really an ember-data thing. The new router sets controller's content property automatically. Instead of setting content from within the controller dedinition, customize the model that will be used for your route by overriding the model hook. For example:
App.UsersRoute = Ember.Route.extend({
model: function() {
return ['mike', 'jen', 'sofia', 'greta']
}
}
I modified your jsfiddle here: http://jsfiddle.net/WGYmg/
You may use the setupController method to set the controller's contents as you like:
setupController: function(controller) {
controller.set('content', []);
}
See this fiddle
Edit
You can use the model method to return the original content:
model: function () {
var c = this.controllerFor('users');
return c.get('content');
}
This is a bit hackish, but still..:)
See updated fiddle

Categories

Resources