I have a very simple toy app using Rails as an API and Ember 1.8.1 with CLI for the client.
I have a typical sidebar setup where when you click the item, it displays next to the list. Everything works fine until you refresh the page with a list item on the page (a url that hits the package route), I get the following error:
Uncaught Error: Assertion Failed: The value that #each loops over must be an Array. You passed <sm-client@model:package::ember387:63>
packages/index.hbs
<div class='sidebar'> <ul>
{{#each package in model}}
<li>
{{#link-to 'package' package}}
{{package.name}}
{{/link-to}}
</li>
{{else}}
<li>No contacts found.</li>
{{/each}}
</ul>
</div>
application.hbs
<h2 id="title">App</h2>
{{link-to 'Packages' 'packages'}}
{{link-to 'Home' 'index'}}
{{outlet 'sidebar'}}
{{outlet}}
package.hbs
<dl>
<dt><strong>Name</strong></dt>
<dd>{{model.name}}</dd>
<dt><strong>Description</strong></dt>
<dd>{{model.description}}</dd>
<ul><strong>Tournaments</strong></ul>
{{#each tournament in model.tournaments}}
<li>
{{tournament.name}}
</li>
{{/each}}
</dl>
router.js
import Ember from "ember";
import config from "./config/environment";
var Router = Ember.Router.extend({
location: config.locationType
});
Router.map(function() {
this.resource("packages", function() {
this.resource("package", {path: "/:package_id"}); });
});
export default Router;
routes/package.js
import Ember from 'ember';
export default Ember.Route.extend({
model: function(params) {
return this.store.find('package', params.package_id);
},
renderTemplate: function() {
this.render();
this.render('packages/index', {
into: 'application',
outlet: 'sidebar'
});
}
});
routes/packages/index.js
import Ember from 'ember';
export default Ember.Route.extend({
model: function(){
return this.store.find('package');
}
});
models/package.js
import DS from 'ember-data';
export default DS.Model.extend({
name: DS.attr('string'),
description: DS.attr('string'),
tournaments: DS.hasMany('tournament',{
async: true,
inverse: 'tournamentPackage'
})
});
models/tournament.js import DS from 'ember-data';
export default DS.Model.extend({
name: DS.attr('string'),
buyIn: DS.attr('string'),
attempts: DS.attr('string'),
description: DS.attr('string'),
tournamentPackage: DS.belongsTo('package', {
async: true
})
});
If I comment out {{outlet 'sidebar'}} and visit a package route directly and refresh, it works fine. I'm sure that on reload it's trying to loop through my singular model from the package route in the sidebar. Other threads have mentioned not to return multiple models on dynamic segments so I'm not sure what to do.
Side note: I'm trying to avoid using controllers as I've heard that Ember will move that logic to other pieces of the framework, but if the solution is to use controllers I have no issue using one.
Your problem lays in routes/package.js
file. Examine what you are doing in the model
hook:
model: function(params) {
return this.store.find('package', params.package_id);
}
You are fetching one package from the API. You have not defined setupController
, therefore the result from the model
hook is automatically set on model
property of your controller (PackageController
as default). After that, you make an explicit call to renderTemplate
and render current template (package.hbs
) AND additional package/index.hbs
. This additional template render as follows:
{{#each package in model}}
(...)
{{/each}}
So, what is your model? Your model have not changed. It is still this.store.find('package', params.package_id)
, so a single package
. Rendering multiple templates in one route still uses one, current, controller.
So, how can you obtain what you want? Using {{outlet}}
in your packages/index.hbs
. You will need to change your templates, but while you enter package
route, both index
and package
controller are active (and both templates are active). Render list of packages as your sidebar in your packages/index.hbs
file, at the end add {{outlet}}
and see what you got.
Please refer to Routing in Ember guides for more info.