J B
J B

Reputation: 400

Computed property in Ember based on async data

I'm trying to use a computed property based on the values from an async, hasMany model property, but cannot get it to display in my view.

MyApp.Foo = DS.Model.extend({

    title: DS.attr('string'),
    peeps: DS.hasMany('peep', { async: true });

});

MyApp.Peep = DS.Model.extend({

    name: DS.attr('string'),
    email: DS.attr('string')

}); 

MyApp.Foo.FIXTURES = [

    { id: 1, title: 'nice', peeps: [1,2] }

];

MyApp.Peep.FIXTURES = [

    { id: 1, name: 'mypeep', email: '[email protected]' },
    { id: 2, name: 'mypeep2', email: '[email protected]' }

];

MyApp.FooController = EmberObjectController.extend({

    showPeeps: function() {

        // This one works for this test data. 
        // return [{name: 'baz', email: 'bar'}];

        var peepList = this.get('content.peeps.[]').then(function(c) {

            // This one does not work, even for this test data.
            return {name: 'baz', email: 'bar'}];

        });

    }.property('content.peeps.[]');

});

In my view, something along the lines of:

{#each peep in controller.showPeeps}}{{peep.name}}{{/each}}

I can see all the data in the "then()" using console.log(), and as it indicates in the code comments, it works if I take the return out of the "then()" - but then the real data is empty because it is returned as async. If I try to make it non-async, I get

Uncaught TypeError: Cannot call method 'resolve' of undefined

I've tried many variants of the computed property code (using @each, using model.peeps - all of which correctly show the data in console.log(), but not in the view. In the view, it is always undefined unless I just return dummy data outside of the then() - which displays correctly)

What am I missing?

Upvotes: 6

Views: 4129

Answers (1)

GJK
GJK

Reputation: 37369

Don't treat the hasMany relationship as a promise, treat it as an array. That's the whole point of DS.PromiseArray. If you just want the users, don't even bother with the computed property, just use peeps in your template. But, if you need to convert the data somehow, use map.

showPeeps: function() {
    return this.get('peeps').map(function(peep) {
        return { name: peep.name, email: peep.email };
    });
}.property('peeps.@each')

Also, don't watch the [] property. That only updates when an item is added or removed from the array. Your array contents aren't changing, the contents of the contents are changing. You should watch the @each property instead. You also don't need to add [] to the end of the property name, and you don't need to prefix the property with content..

Upvotes: 8

Related Questions