For CompaniesRoute I render links for each item:
{{#link-to 'company' id}}The name should change here:{{name}}{{/link-to}}
I have a (CompanyRoute) route that renders a template to edit the object.
The "find" method (AJAX request) on the model hook is called.
However, if I edit the object in CompanyController (ObjectController) it does not reflect back to the item in the CompaniesRoute (CompaniesController).
What I understand on the route is that the model hook is called only when it does not already know about the model.
So when I do this instead:
{{#link-to 'company' this}}The name should change here:{{name}}{{/link-to}}
Now it works, now the name (and any other related properties) changes when I get into edit mode.
However, now the problem is that the "find" method (AJAX request) on the model hook for the CompanyRoute is not being called. It assumes that the model is already there so that it just uses the existing model with the limited properties used when calling "all" method on the CompaniesRoute model hook.
My question is how to get around this so that it's called (find method) when I use the latter ({{#link-to 'company' this}}) link-to method?
Note: also I'm using nested resources on the Router.map. ie:
this.resource('companies', function() {
this.resource('company', {path:':company_id'});
}
Note2: I'm not using Ember Data
After playing around found I have to add setupController on the CompanyRoute:
setupController: function(controller, model) {
controller.set('model', App.CompanyAdapter.find(model.id));
this._super(controller, model);
}
This will now fire request each time and reflect changes accordingly based on link-to helper with this attribute.
Related
I have a route that loads all my models, and a nested route that allows the user to add a new model.
App.Router.map(function() {
this.resource("foo", {path: "/foo"}, function() {
this.route("add", {path: "/add"});
});
});
My add template looks like this (very basic)
{{input value=wat}}
Here is the linkTo from my index template
{{#linkTo 'foo.add'}}Add A New Model{{/linkTo}}
When I click the add button I simply create the model using $.ajax and transition back to the list route. All works great, until I click the "add" link again.
When the add route loads up the template from above the 2nd time it still shows the "wat" value I entered previously. I was hoping it would not persist any state as each time I "add" a new model it should be unaware of any previous model data.
How can I achieve this with ember 1.1.2+
Update
The approach I took was to reset each element in the setupController method of the route (as this is invoked each time you load the controller).
App.FooAddRoute = Ember.Route.extend({
model: function(params) {
var parentId = 1;
return Ember.Object.create({'bar': parentId});
},
setupController: function(controller, model) {
this._super(controller, model);
controller.set('bazz', '');
}
});
The quick and dirty answer is you want to use a model on the route. If you didn't, you'd have to manually blank out the values on the controller. Ember builds up singleton controllers. This generally is super convenient and very performant.
Singleton controllers keep state. The best way to keep them stateless is to have them backed by a model (return an empty object from the model hook, and don't have the values defined on the controller). By returning something from the model hook it will use an ObjectController (or you'll need to update your code to use an ObjectController on your controller). Then all values will be proxied to the model instead of being stored on the controller.
http://emberjs.jsbin.com/OPaguRU/1/edit
According to the docs:
If you're using Ember Data, you only need to override the model hook
if you need to return a model different from the record with the
provided ID
But this does not work for me, ember data gives me wrong data.
App.UsersEditRoute = Ember.Route.extend
model: (params) ->
return ['Just', 'Some', 'Random']
setupController: (controller, model) ->
controller.set('model', model) # Returns #get('store').find 'user', params.user_id
This should return ['Just', 'Some', Random], but instead it gives me the original #get('store').find 'user', params.user_id
Why and how do I get the data I want?
Btw, If I do like below, everything works, but I want to know why my model function never is called.
setupController: (controller, model) ->
controller.set('model', ['Just', 'Some', 'Random']) # returns ['Just', 'Some', 'Random']
Thank you, I'm using ember-data 0.14 and ember 1.0.0
The model hook, for routes with a dynamic segment, is only called when the page is (re)loaded, here's what the ember guide says (the note at the end):
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 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.
I had a similar problem when I wanted to override the model hook. The answer from Simon gave me the right direction. In addition, it should be noted, also from the ember guide but in the Links section, that the {{link-to}} helper takes:
At most one model for each dynamic segment. 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 of the route, and will make sure that the model
hook is triggered.
So the bottom line is that by replacing the model in the {{link-to}} helper (in my case 'product') by the object id (in my case 'product.id'), my model hook is now called every time.
As I understad, a template in emberjs gets it's data from controller. So, it's a controller's job to get hold of model data and present it to the template.
The docs here associate a model with a route like this:
App.FavoritesRoute = Ember.Route.extend({
model: function() {
// the model is an Array of all of the posts
return App.Post.find();
}
});
In this case and ArrayController is automatically generated.
However, there's also the setupController function. So, can we also do this :
App.FavoritesRoute = Ember.Route.extend({
setupController: function(controller) {
controller.set('model', App.Post.find());
}
});
as the first example given here do?
Do the two ways do the same thing?
Do the two ways do the same thing?
Almost. In both cases the controller's content property will be set to the result of App.Post.find(). And both will work.
That said, using the model hook is the preferred way to do this. If your model hook returns a promise, the router will wait for it to resolve before moving on. That is not the case with the setupController hook. generally you will want to avoid anything async from the setupController hook.
I'm trying to build an Ember app and I'm running into some difficulty.
I have an index route, which I want to render the following page:
+--------------------------+
| Welcome, foo#bar.com |
+--------------------------+
| |
| New Posts |
| --------- |
| *foo |
| *bar |
| *baz |
| |
+--------------------------+
So I have an Account model, and a Post model. (which don't have any related fields)
I'm having conceptual difficulty with the following:
Ember routes have a model method which returns the model for the route. But what if I want multiple models to be associated with my route? In this case I have Account and Post. How do I make them both available to my page?
One thing I've tried is using setupController and manually setting account and posts on the controller so they can be accessed by the template. But if I can do this, what's the point/significance of the model method!?
Why does Ember want to associate a route with only a single model?
Appreciate any advice,
Thanks,
Daniel
One thing I've tried is using setupController and manually setting account and posts on the controller so they can be accessed by the template.
What you are doing is correct, this is what the setupController hook is for.
But if I can do this, what's the point/significance of the model method!? Why does Ember want to associate a route with only a single model?
In RC3, preventing the default behavior was impossible. In RC4, implementing the setupController hook prevents the default behavior from happening. This is a potentially breaking change for dev's migrating to newer versions.
Also note that if your route implements the setupController hook and you want to preserve the default behavior (the model from also being invoked) make sure you call this._super() from within the setupController hook. You can read more here in the announcing blog post.
Hope it helps.
Using model callback has some advantages:
It automatically generate model callback when you define router.
In template, when you use link-to "someRoute" model, then when you click that link and transition to another route, the route will use the model you pass in for it's model (without calling model callback to get data).
See http://emberjs.com/api/classes/Ember.Route.html#method_model
But the biggest advantage I think, is promise support.
A route uses model callback to get data it needs, then in setupController, it pass the data to the second argument.
Notice what I mean setupController gets data from model callback. If the model callback returns a promise, the route will wait until this promise is resolved, then get the data from promise. If the promise is processing, the setupController is not called, and the template is not rendered.
App.PostsRoute = Em.Route.extend({
model: function() {
// The server response an array of posts like [{name: 'foo'}, {name: 'bar'}, {name: 'baz'}]
return $.get('/api/posts.json');
},
setupController: function(controller, model) {
console.log(model); // it's array, not promise object
controller.set('model', model);
}
});
When you can use setupController to do the same thing, it's like this:
App.PostsRoute = Em.Route.extend({
setupController: function(controller, model) {
$.get('/api/posts.json').then(function(data) {
controller.set('model', data);
});
}
});
BUT, setupController does not support promise, that means if you get data from the server in the setupController, Ember will render template before the data is prepared. In many case it's not what we want.
BUT, the model seems not a good place to get multiple data from server. You can do that using Ember.RSVP.all with multiple promises. but you also need to consider link-to. I'm not sure what is the best practice
to get multiple data in a route and wait them all prepared before rendering template. If anyone has a good solution, Please tell me!
For your situation, I think you can use different route to do this. After all I think something like "Welcome, foo#example.com" is a top bar for all of the pages, right? Then you can put it in ApplicationRoute, and render account info in application.hbs template.
I'm using the render controller extensively in my app and am having trouble understanding the logic around Controller creation.
The code in question uses this (cut-down) template (using emblem.js):
.span4
render "learningNeeds" # models loaded in learningNeeds controller
.span8
render "notices" student.room.notices # student is defined on the top-level controller
render "observations" # models loaded in observations controller
and the setupController for the template's Route:
App.ParentRoute = Ember.Route.extend
setupController: (controller, model) ->
console.log "ParentRoute setupController"
controller.set('student', model.get('students').objectAt(0))
#set('controller.controllers.observations.showFilters', true) # this works
#set('controller.controllers.learning_needs.showFilters', true) # this works
#set('controller.controllers.notices.showAdd', true) # this doesn't work
App.currentUser = model
I'm setting the content of the learning_needs and observations controllers in observers within their respective controllers, so I'm not passing in any model to the render call in the template.
With the notices controller I'm passing in the student.room.notices as the 2nd parameter to the render call.
Now the issue is that the I'm seeing different notices controllers when I render the template to that in the Parent setupController method. That is, they have different ember ids. The controller at #set('controller.controllers.notices.showAdd', true) is different to that rendered by the template.
If I remove the student.room.notices model from the template and just use `render "notices" then the same controller is used and I can set the showAdd property and have it display in the template. The problem then is it doesn't contain any models.
The relevant docs say the render view helper will Get (or generate) the singleton instance of AuthorController but this doesn't seem the case for me.
Can anyone shed any light on this behaviour?
thanks,
Martin
I think you should use property bindings.
In NoticesController:
showAdd: Ember.computed.alias('parentController.noticesShowAdd'
In setupController:
controller.set('noticesShowAdd', true)
Then you don't have to worry about figuring out how to get a reference to the notices controller.
Note, if render is called inside an each, you may need to use target instead of parentController.