"Success" or "Complete" method for Ember Data collection retrieval


#1

In my app I have a 1 to M relationship modeled like so:

Social.Message = DS.Model.extend({
    created: DS.attr("date"),
    text: DS.attr("string"),
    metrics: DS.hasMany("Social.Metric"),
});

Social.Metric = DS.Model.extend({
    label: DS.attr('string'),
    value: DS.attr('number'),
    message: DS.belongsTo('Social.Message'),
});

When Ember Data makes a call to retrieve messages, the data packet looks like this:

[
    {
        "id": 13, 
        "created": "2013-05-20T21:35:56Z"
        "text": "You got to let the roots grow deep, and stop worrying about the leaves", 
        "metrics": [
            "reach-13", 
            "click-13"
        ]
    }
]

We’re using sideloading to then retrieve the metrics, and the return data for that looks like this:

[
    {
        id: "reach-13",
        value: 3,
        label: "reached"
    },
    {
        id: "reply-13",
        value: 2,
        label: "reply"
    },
]

This process is working great, with no flaws. But because there might be a large number of messages, each of which has a collection of metrics, the time to display metrics can be 3 or more seconds. On each message I’d like to add a loading spinner in place of the metrics, then remove it once the metrics for that message have returned. I’ve got the spinner added, but can’t figure out how to remove it once the collection of metrics has returned to the client.

Does Ember have an event or method on the Controller that fires when an entire collection of data is returned to the client?

I know that the Model lifecycle has hooks like this, but I don’t care about the individual models, I’m looking for something higher up, for the entire set of metrics (for each message)

Here’s a quick screencast of what’s happening right now.


#2

I might be wrong, most likely, but perhaps you could try to create a computed that watches for metrics.@each.isLoaded. Something like this:

Social.Message = DS.Model.extend({
    created: DS.attr("date"),
    text: DS.attr("string"),
    metrics: DS.hasMany("Social.Metric"),
    metricsAreLoaded: function() {
        var notLoadedMetrics = this.get('metrics').filter(function(metric) {
            return metric.get('isLoaded') == false;
        });
        return notLoadedMetrics == 0;
    }.property('metrics.@each.isLoaded')
});

then in Handlebars

{{#if message.metricsAreLoaded}}
    <!-- display content -->
{{else}}
    <!-- display spinner -->
{{/if}}

I’m not really sure about this tho…


#3

Ah, that might just work. I’ll have a go at it. Thank you.


#4

The solution ended up being slightly different, but based on your response.

metricsAreLoaded: function(){
    var isReady = false;

    this.get('metrics').forEach(function(metric) {
        isReady = isReady || metric.get('isLoaded');
    });

    return isReady;
}.property('metrics.@each.isLoaded')

<div {{bindAttr class=":metrics post.metricsAreLoaded::is-loading"}}>
    {{#if post.metricsAreLoaded}}
        {{ render "metric" post.metrics }}
    {{/if}}
</div>

Thanks for your help!