Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
480 views
in Technique[技术] by (71.8m points)

javascript - Ember async computed property returns undefined

I am attempting to set a property to the value of a model's async, hasMany relationship. But I'm not able to return any value within the then function.

App.Athlete = DS.Model.extend({
    name: DS.attr('string'),
    age: DS.attr('number'),
    splits: DS.hasMany('split', {async: true}),
    times: DS.hasMany('time', {async: true}),
});

App.Time = DS.Model.extend({
    athlete: DS.belongsTo('athlete', {async:true}),
    race: DS.belongsTo('race', {async: true}),
    time: DS.attr('string'),
});

App.Split = DS.Model.extend({
    distance: DS.attr('string'),
    time: DS.attr('string'),
    athlete: DS.belongsTo('athlete', {async:true}),
    race: DS.belongsTo('race', {async: true}),
});

My issue lies in an ObjectController for an Athlete where I am attempting to set the Time hasMany array as a property. Outside of the then callback function I am able to return values normally. However, within the then callback, all values return undefined/not at all. In addition, using console.log I am consistently able to see that the code is being executed.

Here is that method:

time: function() {
    var raceid= '1';
    this.get('times').then(function(times) {  // returns undefined in this scope
        console.log(times.get('length'));     // consistently displays
        times.forEach(function(time) {
            time.get('race').then(function(timerace) {
                if(timerace.get('id')===raceid) {
                    console.log('match');     // consistently diplays
                    console.log(time.get('time')); // consistently displays
                    return time.get('time'); // returns undefined/not at all
                }
            });
        });
    });
}.property('time.@each.time'),

While the above function always returns undefined, the function below (a part of the same controller) works consistently without error.

sortedSplits: function(){
    var self = this,
    raceid = '1',
    splits = this.get('splits');
    // filter each split by race
    this.get('splits').filter(function(split) {
        // retrieve race split belongsTo
        split.get('race').then(function(race) {
            // compare race
            return race.get('id') === thisrace; 
        });
    });
    splits = splits.sortBy('m');
    return splits;                // returns correctly
}.property('splits.@each.m'),

After looking at it for 6 hours, I no longer know where to look for the issue. I do not understand where this issue is coming from. Would someone else happen to know where that issue can arise from?

Note: My issue is similar to that of Computed property in Ember based on async data although I have not had any luck with that solution.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You aren't returning anything to the computed property, you are returning something to the callback function which is handed off to any chained promises, but that still wouldn't help had you returned the promise, since returning a promise to a computed property doesn't automatically resolve the promise and use the result at the value of the computed property.

Your current computed property is essentially doing this:

time: function() {
    var raceid= '1';
    this.get('times').then(function(times) {  // returns undefined in this scope
        console.log(times.get('length'));     // consistently displays
        times.forEach(function(time) {
            time.get('race').then(function(timerace) {
                if(timerace.get('id')===raceid) {
                    console.log('match');     // consistently diplays
                    console.log(time.get('time')); // consistently displays
                    return time.get('time'); // returns undefined/not at all
                }
            });
        });
    });
  // I'm not returning anything so
  return undefined;
}.property('time.@each.time'),

In this situation it's easiest to use an observer and set the property (although it looks like you were accidentally watching time, instead of times)

time: null,
timWatcher: function() {
    var raceid= '1',
        self = this;
    this.get('times').then(function(times) {  // returns undefined in this scope
        console.log(times.get('length'));     // consistently displays
        times.forEach(function(time) {
            time.get('race').then(function(timerace) {
                if(timerace.get('id')===raceid) {
                    console.log('match');     // consistently diplays
                    console.log(time.get('time')); // consistently displays
                    self.set('time', time.get('time')); // set property to time value
                }
            });
        });
    });
}.observes('times.@each.time'), //times, not time

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...