Nested routes loads the parent model - ember.js

I have a nested route structure like this:
App.Router.map(function() {
this.resource('user', {path: '/user/:user_id'}, function() {
this.route('followers', {path: '/followers'});
});
});
when I hit the user/123/followers route I would expect that it automatically fetch the model from user/123/followers, but it just fetches the user model from user/123 again. What do I need to add so it fetches the right data for the route?

Each route have your own model, and this isn't propaged, by default.
So App.UserRoute model, returns the current model like expected:
App.User.find(params.user_id)
But because App.UserFollowersRoute have your own model hook, then you have to provided it.
You can do this easily using the modelFor.
App.UserFollowersRoute = Ember.Route.extend({
model: function() {
return this.modelFor('user');
}
});
The modelFor look for a model from a named route. So modelFor('user'), will retrieve the model from App.UserRoute.
And in your user/followers template, you will have the current user, in the current context:
<script type="text/x-handlebars" data-template-name="user/followers">
<h2>{{name}} followers:</h2>
<ul>
{{#each followers}}
<li>{{name}}</li>
{{/each}}
</ul>
</script>
Here a sample with this working

Ember will automatically call User.find(123) when you hit /user/123/... because that is the default model hook for App.UserRoute. If you want to fetch additional data when the followers route is accessed, define a model hook for App.UserFollowersRoute:
App.UserFollowersRoute = Ember.Route.extend({
model: function() {
user = this.controllerFor('user');
// Now find and return the list of followers
}
});

Related

Ember Route with renderTemplate and two render calls overrides original model

I have an outlet in application.hbs called 'sidebar'. This outlet is used in some routes to render additional info using a component called 'sidebar-info'. In those routes I use renderTemplate to render stuff in the appropriate outlets. For example:
renderTemplate: function(controller, model) {
this.render('components/sidebar-info', {
into: 'application',
outlet: 'sidebar',
model: Ember.Object.create({
title: this.get('i18n').t('signup'),
detailsComponent: 'signup-help'
})
});
this.render('sign-up');
},
This is components/sidebar-info template:
<div class="title">
<h1>{{model.title}}</h1>
</div>
{{#if model.detailsComponent}}
<div class="details">
{{component model.detailsComponent}}
</div>
{{/if}}
When the route template (not the component one) is being rendered, the model defined by the route is overwritten by the model sent to the component. If the original model was something like this:
original_model = {
field_1: 1,
field_2: 2
}
Then using model.field_1 becomes undefined in the context of the template while model.title is available.
Why is the model being overwritten?
I am using Ember 2.2.0
It seems this is the correct behaviour. According to the Route API, this is the explanation of the controller and model options sent to the render method:
controller [String|Object]
the controller to use for this template, referenced by name or as a
controller instance. Defaults to the Route's paired controller
model [Object]
the model object to set on options.controller. Defaults to the
return value of the Route's model hook
This means that setting only the model option will set the model on the Route's paired controller because that is the default option.controller. This means we need either to create a dummy controller that only works to receive the model.
I have tested this and it works as expected.

adding second model to route makes first undefined

In my current Ember setup, I retrieve a store for the Index Route. This works fine.
App.IndexRoute = Ember.Route.extend({
model: function(){
var store = this.store.find('index');
return store;
}
});
However, I wish to create a custom form object for the same route, and therefore following the advice of this SO answertried to return two models for the Index Route like this, however, I now get the error
Error while processing route: index that is not defined ReferenceError: that is not defined
New Code
App.IndexRoute = Ember.Route.extend({
model: function(){
return Ember.RSVP.hash({
store: this.store.find('index'),
customform: App.CustomForm.create()
});
}
});
How can I add a second model to this route?
Update
The index model had a date property that I was using to sort the items in the index model
App.IndexController = Ember.ArrayController.extend({
sortProperties: ['date'],
sortAscending: false,
I was originally displaying the index model with this in the html
{{#each item in arrangedContent}}
<li> {{some-component id=item.customid date=item.date data=item.junk}} </li>
{{/each}}
By adding the second model, whether or not i use the store to create a record, I get this error and the data from the store doesn't load in the html
Error while processing route: index undefined is not a function TypeError: undefined is not a function
Also, I don't actually need to persist the second model I'm trying to add, so I don't desire to make it a store. In the SO answer I linked to, second models were added that weren't persisted.
It looks like you should be using the store to create your new custom form record:
App.IndexRoute = Ember.Route.extend({
model: function(){
return Ember.RSVP.hash({
store: this.store.find('index'),
customform: this.store.createRecord('customForm')
});
}
});
You're going to want to create your customForm through your store:
App.IndexRoute = Ember.Route.extend({
model: function() {
return Ember.RSVP.hash({
store: this.store.find('index'),
customForm: this.store.createRecord('customForm')
});
}
});

Use of serialize hook in ember routes

What is the use of serialize hook in ember route class?
App.PostRoute = Ember.Route.extend({
model: function(params) {
return this.store.find('post', params.post_id);
},
serialize: function(post) {
return { post_id: post.get('id') };
}
});
Ember Documentation says:
If your dynamic segment ends in _id, the default model hook will convert the first part into a model class on the application's namespace (post becomes App.Post). It will then call find on that class with the value of the dynamic segment.
The default serialize hook will pull the dynamic segment with the id property of the model object.
But i am not able to understand the use of serialize hook in route class
The serialize method determines what to use as parameter for the provided entity.
Example.
Say you have the following user model, with the following properties.
id
username
email
Now if you have a list of users, and you want to link to a show user details page, you might use a loop like this.
{{#each users}}
{{#link-to user.show this }} {{username}} {{/link-to}}
{{/each}}
So when Ember sees this link-to helper i will convert it to a link, which might look like this
elvar
Now the default behavior here is to use the id as a parameter, which is what your own example shows, i picks the id from the model. We can change this with the serializer method.
Lets say that instead of using the id, we want to use the username as a parameter.
App.UserShowRoute= Ember.Route.extend({
model: function(params) {
return this.store.find('user', params.user);
},
serialize: function(user) {
return { user: user.get('username') };
}
});
Now the link-to helper will yield the following instead.
elvar

Emberjs: controller and route not getting along

The example will represent it best, I suppose. So, I have a defined route with a model property, which displays the appropriate image, based on id in url. This worked:
App.DetailsRoute = Ember.Route.extend({
model: function(params) {
return App.Images.find(params.image_id);
}
});
However, I wanted to add an action and... when I set up the controller, the page did not have access to the model part. Controller:
App.DetailsController = Ember.Controller.extend({
saveToServer: function(){
//alert(JSON.stringify());
alert('hi');
}
});
So at this time it's like this: either the model is set and stuff gets displayed and controller doesn't work OR controller works and model not.
Why is this happening?

Specify controller and model on a view that doesn't have a router

I have a simple app that is using ember-data to load from a RESTful web service and display the data using the route to specify the model.
App.AreasRoute = Ember.Route.extend({
model: function() {
return App.Area.find();
}
});
Then I can render the data in the handlebars template using {{#each content}}
But I want to have a second area of data from a different model displayed on the page as well. I started by creating a View and then rendering the view as part of my application template using {{view App.AnotherView}} which correctly renders the view.
However, this view doesn't have a route and therefore I have nowhere to tell it where to get it's data from. How do I do this?
The best place to load additional content is in the setupController hook of the route.
For example, if you define your route as
App.AreasRoute = Ember.Route.extend({
model: function() {
return App.Area.find();
},
setupController: function(controller) {
controller.set('someArea', App.Area.find('area_id'));
}
});
Then the Area model with id area_id can be accessed by {{someArea}} in your template.