Can't get data from a computed property with ember-model

1.6k views Asked by At

I am making an app with ember.js and ember-model

I have a model named Plugin defined as follows:

Eme.Plugin = Ember.Model.extend
  id: Ember.attr()
  name: Ember.attr()
  description: Ember.attr()
  downloads: Ember.attr()
  tags: Ember.attr()

Eme.Plugin.url = "/api/v1/plugins"
Eme.Plugin.adapter = Ember.RESTAdapter.create()
Eme.Plugin.collectionKey = 'plugins'

I want show the most downloaded in index.hbs ( i use ember-rails)

And i fetch data in IndexRoute 's setupController hook:

Eme.IndexRoute = Em.Route.extend

  setupController: (controller, model)->
    console.log Eme.Plugin.findAll().toArray()
    controller.set 'plugins', Eme.Plugin.findAll()

Output :

[nextObject: function, firstObject: undefined, lastObject: undefined, contains: function, getEach: function…]

But in chrome console i execute Eme.Plugin.findAll().toArray(), i got the results as follows:

[{
  __ember1377710636537: "ember404"
  __ember1377710636537_meta: Meta
  _dirtyAttributes: Array[0]
  _reference: Object
  _super: undefined
  get _data: function() {}
  isLoaded: true
  isNew: false
  set _data: function(value) {}
  __proto__: Object
}, {
  ...
}, {
  ...
}]

In my IndexController have a computed property:

Eme.IndexController = Em.Controller.extend

  mostDownloads:(->
    # console.log @get('plugins').slice(0, 3)
    @get('plugins').slice(0, 3)
  ).property('plugins')

and i iterate the mostDownloads but there is nothing to show, however when i output {{plugins.length}}, i can't get the count of all my data

Who can give a hand to me?

2

There are 2 answers

1
narkeeso On BEST ANSWER

Plugins looks like an array and would need to use the .@each iterator like so:

Eme.IndexController = Em.Controller.extend({
    // Code
}).property('plugins.@each')

Here is documentation on @each http://emberjs.com/guides/object-model/computed-properties-and-aggregate-data/

Regarding your array length, I've never had much luck using .length, for length I usually do

plugins.get('length')

Hope that helps!

1
intuitivepixel On

I propose two changes to make you app working.

First

I assume since it's called plugins (plural) the call to .findAll() returns an array of plugins for this to work you should change your controller type to be an ArrayController. Then because you are using @ aka. this in your computed property you should use the fat arrow => to have the right reference to this, so the resulting IndexController should look like:

Eme.IndexController = Em.ArrayController.extend

  mostDownloads:(=>
    # console.log @get('content').slice(0, 3)
    @get('content').slice(0, 3)
  ).property('content.[]')

Notice also that we observe content.[] this will trigger whenever the content array changes, items added or removed etc. you could also use content.@each but this is better suited for when you need to observe changes to the properties of a plugin record in the array, e.g. [email protected].

Second

Now change also how you set the plugins collection on your controller, you should rather set the controller's content property since this is what it is for:

Eme.IndexRoute = Em.Route.extend

  setupController: (controller, model)->
    # console.log Eme.Plugin.findAll().toArray()
    controller.set 'content', Eme.Plugin.findAll()

This line console.log Eme.Plugin.findAll().toArray() will not work the way you expect because when you call it it will give you a promise back and not the array that is still underway (async...).

And a last change, to print out the plugins length, use the afterModel hook of your IndexRoute, since this is the right time when the model promise has being resolved (the async operation has given back control to your app).

Eme.IndexRoute = Em.Route.extend
  ...
  afterModel: (plugins, transition) ->
    console.log plugins.get 'length'
  ...

Hope it helps.