Ember.js:计算属性中的promise

时间:2016-09-01 14:56:04

标签: ember.js promise

首先:我知道这不是在计算属性中拥有promise的理想方式。但是在我的设置中它最适合。我目前使用Ember 1.8.0-beta.1来兼容。

我想要完成的是:

  • 让所有的周游戏包括所需的颜色
  • 制作他们的链接

在我的控制器中:

weeknumbersChoicesWithColor: function () {
    var weeknumberChoices = this.get('weeknumbersChoices');
    var yearnumber = this.get('yearnumber');
    var self = this;

    var promises = [];
    weeknumberChoices.forEach(function (weeknumber) {
        var promise = self.store.findQuery('order', {'weeknumber': weeknumber, 'yearnumber': yearnumber}).then(function(orders){
            return orders.set('weeknumber', weeknumber);
        });
        promises.push(promise);
    });

    return Ember.RSVP.all(promises).then(function(result){

        result.forEach(function(weekOrders){
            // ... do something to get weeknumer and color

            return {
                weeknumber: weeknumber,
                color: color
            };
        });
    });
}.property('yearnumber', 'weeknumber'),

在我的模板中:

{{#each weeknumbersChoicesWithColor}}
     <li>{{#link-to 'orders' (query-params weeknumber=this.weeknumber)}}{{this.weeknumber}}{{/link-to}}</li>
{{/each}}

我的模板会出现此错误:Uncaught Error: Assertion Failed: The value that #each loops over must be an Array. You passed {_id: 131, _label: undefined, _state: undefined, _result: undefined, _subscribers: } 这当然是因为承诺还没有完成。当我将它们包裹在{{#if weeknumbersChoicesWithColor.isFulfilled}}块中时,它也不起作用。

当我没有返回一个promise时,它确实有效,但是在控制器中使用一个Ember.run.later设置一个属性,但这对我来说似乎有很多黑客攻击并且不会一直有效。

2 个答案:

答案 0 :(得分:1)

您需要使用map功能。

return result.map(function(weekOrders){
            // ... do something to get weeknumer and color

            return {
                weeknumber: weeknumber,
                color: color
            };
        });

答案 1 :(得分:1)

特别为此目的,Ember有PromiseProxies。 Here您可以阅读如何将单个对象包装到代理中,以便在

模板中正确使用
{{#if myPromiseProxy.isFulfilled}}
  // do stuff
{{/if}}

here是您实际需要的ArrayProxy。

以下是一些相关代码:

weeknumbersChoicesWithColor: function () {
    var ArrayPromiseProxy = Ember.ArrayProxy.extend(Ember.PromiseProxyMixin);
    var weeknumberChoices = this.get('weeknumbersChoices');
    var yearnumber = this.get('yearnumber');
    var self = this;

    var promises = [];
    weeknumberChoices.forEach(function (weeknumber) {
        var promise = self.store.findQuery('order', {'weeknumber': weeknumber, 'yearnumber': yearnumber}).then(function(orders){
            return orders.set('weeknumber', weeknumber);
        });
        promises.push(promise);
    });

    promises = Ember.RSVP.all(promises).then(function(result){

        result.forEach(function(weekOrders){
            // ... do something to get weeknumer and color

            return {
                weeknumber: weeknumber,
                color: color
            };
        });
    });
    return ArrayPromiseProxy.create({
        promise: promises
    });
}.property('yearnumber', 'weeknumber'),

然后在模板中:

{{#if weeknumbersChoicesWithColor.isFulfilled}}
    {{#each weeknumbersChoicesWithColor}}
        <li>{{#link-to 'orders' (query-params weeknumber=this.weeknumber)}}{{this.weeknumber}}{{/link-to}}</li>
    {{/each}}
{{/if}}

Ember实际上具有您可以使用的ArrayPromiseProxy实现,因此您不必每次都使用PromiseProxyMixin扩展ArrayProxy DS.PromiseArray。但由于它的主要用例是处理模型数据,因此它保存在ember-data命名空间中,我通常只使用自己的版本,因为并非所有项目都使用Ember Data。

要清除您对此错误发生原因的想法,首先我必须添加RSVP.all(someArrayOfPromises)是一个对象而不是一个数组。此对象在解析时将其result属性设置为数组的值,但不应将其视为数组本身。代理用于包装RSVP对象执行的实际结果,并添加便利属性以检查执行状态并根据当前的承诺状态响应相应的显示逻辑。 ArrayProxy还会将一些Array方法映射到其content属性,该属性在实例化时为null,并在RSVP.all结算时成为实际数组。