Nested routes and array - ember.js

In my app I have the following setup:
Router
this.resource('types');
this.resource('type', {path: 'types/:type_id'})
When a user navigates to types he gets a list with all the different types. When he clicks on a link he navigates to the specific type:page. Here I would like to show an array of products. Each type has an array of products. I tried to get the products doing so:
this.resource('types');
this.resource('type', {path: 'types/:type_id'}, function(){
this.resource('products', {path: '/products'});
});
Router
model: function(){
return this.store.find('product');
}
but that didn't work. I also tried with the params but that doesn't work.
model: function(params){
return this.store.find('product', {id: params_id});
}
Templates
Type-template
<h3>{{name}}</h3>
<hr>
{{outlet}}
Product-template
{{#each}}
{{name}}
{{/each}}
But nothing gets loaded in the template. I don't know if this is the way to go. I had some success with removing the nested route and simply loading the two models in the afterModel hook on the typeController, but that doesn't give me access to some other models, linked to the product.
It's very frustrating that some "easy" things, like loading an array of products that belong to a type, is such a hassle.
Edit
What I try to achief is that when you visit the homepage you can
click a link "types" that takes you to the url ..../types and shows you a list of all the types. No problem there.
When you click on a type it takes you to types/type_id (e.g. types/1) and show you some info about the specific type (that works too).
On that same page I want to show a list of all the products associated with this type. Here is where I'm struggling
Models
type
name: DS.attr('string'),
products: DS.hasMany('product', {async: true})
product
name: DS.attr('string'),
prodcuts: DS.belongsTo('type', {async: true})
I tried this first by passing two models on the same route as suggested in this question. That works fine to some extend, but I want to put an action and computed property on each of the products and because the models are loaded in the afterModel hook, they don't get updated. I thought the way to go was to input a nested resource that returns me all of the products based on the type_id but I can't get that to work somehow.

Related

How to add dynamic dropdown to template without changing model?

So I had a route: /tournaments/setup/:tournament_id in my ember app, and it displayed various fields from a model.
But then I find that I'll need other models on the same page. For example, suppose I want the list of all players, so that I can make a dropdown for selecting players to join a tournament.
I can pass an object:
this.transitionTo('tournaments.setup', {tournament: tournament, players: players});
and that works once I change the handlebars template to reflect the change of context.
But now the URL is wrong. The URL is /tournaments/setup/undefined. I'm sure there is a way to explicitly handle this also, but I don't know what it is ...
... and I feel like I'm losing the path. Is there a more conventional way to do what I'm doing?
Update: I've found that I can get the URL to work by adding an id:
this.transitionTo('tournaments.setup', {id: tournament.id, tournament: tournament, players: players});
but I'm still wondering if I'm doing this the right way.
What you want to do is load the models in your route and stick them in a controller to user them. I usually do this in the beforeModel hook. So in your App.TournamentsSetupRoute do something like this:
App.TournamentSetupRoute = Ember.Route.extend({
beforeModel: function() {
var self = this;
var players = this.store.find('player');
players.then(function() {
self.controllerFor('players').set('model',players);
});
}
});
So now, when ever this route is entered, the players will be fetched from your API and stored in a controller. In your controller, just add the players controller to needs so you can access it.
App.TournamentSetupController = Ember.ObjectController.extend({
needs: ['players']
});
You can access the players models anywhere in your controller by doing this.get('controllers.players.model); and iterate over it in your template like so:
<select>
{{#each player in controllers.players.model}}
<option>{{player.name}}</option>
{{/each}}
</select>
Hope that helps! I haven't tested the above code, so there may be a few typos, but it should help get ya there.

Why can I not iterate my model in my template?

I've been recently playing with Ember.js utilizing Ember CLI and I am running into an issue with a very simple application I cannot seem to get around.
I have set up an Ember Data fixture adapter with a simple model "Post" which contains two string properties--title & content. I've then proceeded to map a route like so:
Router.map(function() {
this.resource('posts', {path: '/'});
});
Then create a router for posts which simply returns the model data:
export default Ember.Route.extend({
model: function() {
this.store.find('post');
}
});
My template simply iterates through all the posts in the model like so:
{{#each post in model}}
<h3>{{post.title}}</h3>
<p>{{post.content}}</h3>
{{/each}}
The Ember browser extension properly shows my two test posts in the Data tab like so:
But for some reason the template simply will not render the model data. My application.hbs file does contain the appropriate {{outlet}} which I've tested by adding some dummy text into the post.hbs file. This text shows up properly.
Any idea why my model will not display properly would be greatly appreciated. Thanks!
Unless you made an error while typing your code into StackOverflow, your issue is that you're not actually returning anything in your model hook. Change this:
this.store.find('post');
To this:
return this.store.find('post');

How to pass parameters to an Ember Route

Please see: http://emberjs.jsbin.com/xakok/1/edit
How do I do the following? The categories display. When user clicks on a category, I want to bring up a list of links that belong to the category that was clicked. Ember seems to be by-passing my LinkRoute all together. Thanks
When you provide a model to the link-to helper it will skip the model hook (it built the url based on the model, and assumes that's the model that would be used for that route).
That being said you need to handle the case where you refresh the page instead of hitting the page using the link-to.
Solving the first, we can now assume the category model is being sent to the links route as its model. So we can update the template to iterate over the links on the category sent in. (you could also say each link in model.links, where the category is your model).
{{#each link in links}}
{{link.title}}<br/>
{{/each}}
But you need to be able to handle the case where we refresh the page as well. So we change the link route to mimic the behavior and return the same type of model the link-to is passing in.
App.LinkRoute = Ember.Route.extend({
model: function(params) {
return this.store.find('category', params.category_id);
}
});
Lastly, using the fixture adapter, when you define a hasMany or belongsTo as 3 or [1,2,3] you need to specify those relationships as async.
App.Category = DS.Model.extend({
name: DS.attr('string'),
links: DS.hasMany('link', {async:true})
});
Example: http://emberjs.jsbin.com/fexelera/1/edit
Lastly, thanks for providing source and all that was necessary for your problem, the jsbin really helps people answer questions easily.

Nested routes causing data reload/replacement?

Posted this on the emberjs forums, but SO seems more appropriate.
Hi! I have two routes called classyears and classyear. They're nested like so:
this.resource('classyears', function(){
this.resource('classyear', { path: '/classyear/:classyear_id'});
});
Posterkiosk.ClassyearsRoute = Ember.Route.extend({
model: function() {
return Posterkiosk.Classyear.find();
}
});
Posterkiosk.ClassyearRoute = Ember.Route.extend({
model: function(model) {
return Posterkiosk.Classyear.find(model.classyear_id);
}
});
My templates are:
Classyears:
<div class="yearList">
{{#each item in model}}
{{#linkTo 'classyear' item}}{{item.id}}{{/linkTo}}
{{/each}}
</div>
{{outlet}}
Classyear:
<div class="transformContainer">
{{trigger sizeComposites}}
{{name}}
{{#each students}}
{{partial student}}
{{/each}}
</div>
(The "trigger" helper is from another SO post. The issue was happening prior to adding it, though)
I'm using the Ember-model RESTAdapter. When I load /classyear/:classyear_id, it looks like classyear is rendering its data twice. Once with the correctly-loaded data, and once with no data loaded. The order appears to be random. If the no-data option happens last, it wipes out the correctly-loaded data, leaving a blank page. Vice-versa, and the page content displays just fine.
Any thoughts?
/edit 2: More info:
It looks as though the 0-record reply is from classyears loading. So, it's likely that the zero-record reply is actually just zero records in my hasMany field "students".
If I load /classyears (no class year specified), it only loads once, to get the class year options. If I then click on a class year, it doesn't reload classyears unless I refresh the page, at which time, it loads both, and if the classyears load (a findall) finishes second, it displays no data on the page (other than the classyears template, correctly populated, at the top).
So... maybe my classyears model isn't handling the hasMany field correctly?
I feel like I'm getting closer, but still not sure what's up.
First of all you need to specify a model for a Student, like so:
Posterkiosk.Student = Ember.Model.extend({
id: Ember.attr(),
name: Ember.attr(),
imageUrl: Ember.attr(),
gradyear: Ember.attr()
});
Posterkiosk.Student.adapter = fixtureAdapter;
Now, in your example you are setting the key for the has many to students, but students is an array of objects, not id's, so create a property called student_ids, and pass an array of ids, now that is your key.
Posterkiosk.Classyear = Ember.Model.extend({
students: Ember.hasMany('Posterkiosk.Student', {key: 'student_ids'})
});
If you set embedded: true, then your Classyears server response should come back like this:
{
classyears: [
{..},
{..}
],
students: [
{..},
{..}
]
}
Otherwise, EM would make a separate call to the endpoint on the Student model, and get that data based on the student_ids property.
See the working jsbin.
Tip: RC.7+ removed the underscore from partials, plus the partial name should be in quotes..

How do you access the properties of a related EmberJS object in a template?

I have defined these two objects in Ember:
App.Course = DS.Model.extend({
name: DS.attr('string'),
students: DS.hasMany('App.Student'),
courseComponents: DS.hasMany('App.CourseComponent')
});
App.CourseComponent = DS.Model.extend({
course: DS.belongsTo('App.Course'),
component: DS.attr('string')
});
I've created some fixture data for testing purposes and my goal is to display a list of courses. When a course is clicked, it should then display all the components that make up that course below.
So far it's all working (routes show the correct id for the course, etc, etc) but I cannot access the 'component' property in my Course's related courseComponent objects. The only property I can access is the 'id'.
How can I configure it so I can do something like:
{{#each component in courseComponents}}
{{component.component}}
{{/each}}
It simply returns an empty string. The only thing I can output is the component's id with:
{{#each component in courseComponents}}
{{component.id}}
{{/each}}
How can I access related object properties in a template?
Edit:
JSFiddle with my code:
http://jsfiddle.net/3bGN4/256/
In the end it turned out I was using a broken (I guess?) build of ember-data. I never really thought to check since I pulled it from the EmberJS site this morning via the starter kit.
Outputting properties of related objects is now working as I'd have expected.