Ember handlebars doesn't recognize a RecordArray that was passed


#1

Hello, I’m fighting with a reading-list Ember app. Basically, I’m looping on the books handlebar over a RecordArray called model, that according to Ember doesn’t exist.

This is the code:

Router.map(function() {
  this.route('index', {path: '/'});
  this.resource('books');
  this.route('show', {path: '/books/:book_id'});
  this.route('reviews', function() {
    this.route('new');
  });
  this.route('genre', {path: '/genres/:genre_id'});
});

books.hbs

<ul class="list-unstyled books">
    {{#each model as |book|}}
      {{book-details book=book}}
    {{/each}}
</ul>


{{outlet}}

book.js router

import Ember from 'ember';

export default Ember.Route.extend({
  model: function() {
    return Ember.RSVP.hash({
      model: this.store.find('book'),
      authors: this.store.find('author'),
      genres: this.store.find('genre')
    })
  }
});

books.js controller

import Ember from 'ember';

export default Ember.Controller.extend({
  model: function() {
    return this.get('model.model');
  }.property('model.model'),
  genres: function() {
    return this.get('model.genres');
  }.property('model.genres'),
  authors: function() {
    return this.get('model.authors');
  }.property('model.authors')
});

When visiting /books the app doesn’t work and it displays to the console:

Uncaught Error: Assertion Failed: The value that #each loops over must be an Array. You passed {model: <DS.RecordArray:ember434>, authors: <DS.RecordArray:ember444>, genres: <DS.RecordArray:ember454>}

It makes no sense. It is complainig about each not looping over an Array, but it recognizes model as a RecordArray. I need to use model as the name of the array because I also call all of these controllers/routes/templates from other parts of app using render

Thanks


#2

Your model hook is returning an object, not an array, and your override of model in the controller isn’t working. (the error is showing you that the template is getting your original object which contains the array, not the array itself.)

I would change your model hook to

model: function() {
    return Ember.RSVP.hash({
        books: this.store.find('book'),
        authors: this.store.find('author'),
        genres: this.store.find('genre')
    });
},

setupController: function(controller, models) {
    controller.setProperties(models);
}

Setup your controller only like

import Ember from 'ember';
export default Ember.Controller;

and then access it in your template like

 <ul class="list-unstyled books">
    {{#each books as |book|}}
         {{book-details book=book}}
    {{/each}}
</ul>
```
From what I understand, this is the most forward-looking approach for upcoming routable components.

Alternatively, I believe you could leave out the `setupController` override and your controller code, and just access the books like
````html
 <ul class="list-unstyled books">
    {{#each model.books as |book|}}
         {{book-details book=book}}
    {{/each}}
</ul>
```