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.
Related
Probably a simple answer but as a beginner, say for example I wanted to store a property from my ember model inside of my controller which I could then compare against new data, how could I go about doing it?
To provide more context, I have an input field where the value is retrieved using model.user_input, I want to be able to store this somewhere when the view is first loaded and then compare it when the value changes. I've tried using computed properties but they are also getting updated when the model changes.
In your controller's route, you could set up your controller such that your controller saves the initial value:
import Ember from 'ember'
export default Ember.Route.extend({
model() {
return {
'user_input': /* ... */
}
},
setupController(controller, model) {
this._super(...arguments)
controller.set('original_input', Ember.get(model, 'user_input'))
}
})
That way, when the value changes, you could simply fetch the original value via Ember.get(this, 'original_input') on your controller:
import Ember from 'ember'
export default Ember.Controller.extend({
'original_input': '',
isChanged: Ember.computed('model.user_input', function() {
return Ember.get(this, 'original_input') !== Ember.get(this, 'model.user_input')
})
})
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.
My route is:
export default Ember.Route.extend({
model: function (params) {
var blocks = this.store.find('block', {'objectId': 777});
this.controllerFor("blocks").set('model', blocks);
return Ember.RSVP.hash({
object: this.store.find('object', params.id),
blocks: blocks
});
//return this.store.find('object', params.id);
}
});
My controller is:
export default Ember.ArrayController.extend({
init: function(e){
alert('jere');
}
});
Alert in init function works but next I get the error:
Error while processing route: objects.bc.index Cannot read property
'length' of null TypeError: Cannot read property 'length' of null
What is the right way to get collection of models through ajax and show it in template with custom array controller?
This code has a number of problems. First, ArrayController assumes that its model is an array, whereas your model hook is returning a hash. Second, your this.controllerFor("blocks").set('model', blocks) call attempts to set the model for the controller to a promise, which is useless. You do not set the model for the controller in the model hook like this. You set it by returning the model, which is then installed (after it resolves) into the controller by your (or the default) setupController hook.
You should not use an ArrayController, which is soon to be deprecated anyway, and instead use a plain old controller. The model for this controller will be the hash returned from the model hook. You need to access it explicitly in the template with {{model}}.
So you want something like this:
// route.js
export default Ember.Route.extend({
model: function(params) {
var blocks = this.store.find('block', {'objectId': 777});
return Ember.RSVP.hash({
object: this.store.find('object', params.id),
blocks: blocks
});
}
});
// controller.js
export default Ember.Controller.extend({
init: function(e) {
alert('jere');
}
});
In your templates, instead of
{{#each controller}}
blockProp is {{blockProp}}
as you are presumably doing now, use
{{#each block in model.blocks}}
blockProp is {{block.blockProp}}
{{/each}}
And objectProp is {{model.object.objectProp}}
I have a route that creates a new record like so:
App.ServicesNewRoute = Ember.Route.extend({
model : function() {
return this.store.createRecord('service');
},
setupController: function(controller, model) {
controller.set('model', model);
},
});
Then I bind that model's properties to the route's template using {{input type="text" value=model.serviceId ... }} which works great, the model gets populated as I fill up the form.
Then I save record:
App.ServicesNewController = Ember.ObjectController.extend({
actions : {
saveService : function() {
this.get('model').save(); // => POST to '/services'
}
}
});
Which works too.
Then I click the save button again, now the save method does a PUT as expected since the model has an id set (id: 102):
But then when I look at the PUT request in Dev Tools, I see that the id attribute was not serialized:
As a result, a new instance is created in the backend instead of updating the existing one.
Please ignore the serviceId property, it is just a regular string property unrelated to the record id which should be named just id.
I don't know why the id is not being serialized... I cannot define an id property on the model of course since Ember Data will not allow it, it is implicit. So I don't know what I am missing...
Any help is greatly appreciated!
The base JSONSerializer in Ember-Data only includes id in the payload when creating records. See DS.JSONAdapter.serialize docs.
The URL the RestAdapter generates for PUTting the update includes the ID in the path. In your case I believe it would be: PUT '/services/102'.
You can either extract it from the path in your backend service. Or you should be able to override the behavior of your serializer to add the id like this:
App.ServiceSerializer = DS.JSONSerializer.extend({
serialize: function(record, options) {
var json = this._super.apply(this, arguments); // Get default serialization
json.id = record.id; // tack on the id
return json;
}
});
There's plenty of additional info on serialization customization in the docs.
Hope that helps!
Initially I used ronco's answer and it worked well.
But when I looked at ember data's source code I noticed that this option is supported natively. You just need to pass the includeId option to the serializer.
Example code:
App.ApplicationSerializer = DS.RESTSerializer.extend({
serialize: function(record, options) {
options = options ? options : {}; // handle the case where options is undefined
options.includeId = true;
return this._super.apply(this, [record, options]); // Call the parent serializer
}
});
This will also handle custom primary key definitions nicely.
Well, as far as I know it's a sync issue. After first request you do the post request and then, it has been saved in the server, when you click next time the store haven't got enough time to refresh itself. I've got similar issue when I've created something and immediately after that (without any transition or actions) I've tried to delete it - the error appears, in your case there's a little bit another story but with the same source. I think the solution is to refresh state after promise resolving.
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.