我有一个Ember Data模型,我正在尝试根据async hasMany关系的属性执行计算属性。出于某种原因,它似乎永远不会重新计算。我该怎么做呢?
代码:
export default DS.Model.extend({
splits: DS.hasMany('split', { async: true }),
amount: Ember.reduceComputed('splits.@each.amount', {
initialValue: 0,
addedItem: function(accValue, split) { return accValue + split.get('amount'); },
removedItem: function(accValue, split) { return accValue - split.get('amount'); }
})
/* Neither of these work either.
amount: Ember.computed.sum('splits.@each.amount') // This doesn't work
amount: Ember.computed('splits.@each.amount', function() {
return this.get('splits').reduce(function(pValue, split) {
return pValue + split.get('amount');
}, 0);
})
*/
});
失败的测试(预期1350
,得到0
):
import { test, moduleForModel } from 'ember-qunit';
import Transaction from 'my-app/models/transaction';
moduleForModel('transaction', 'Unit - Transaction Model', {
needs: ['model:split']
});
test('amount', function() {
var transaction = this.subject();
var store = this.store();
transaction.get('splits').addObjects([
store.createRecord('split', { amount: 250 }),
store.createRecord('split', { amount: 1000 })
]);
equal(transaction.get('amount'), 1250);
});
答案 0 :(得分:5)
您的hasMany属性是异步的,因此它是一个承诺,其值必须可以使用然后方法访问。
transaction.get('splits').then(function(splits) {
split = store.createRecord('split', { amount: 250 }),
splits.pushObject(split);
split = store.createRecord('split', { amount: 1000 })
splits.pushObject(split);
});
答案 1 :(得分:3)
首先,这与承诺无关。 Ember-Data有很多关系返回PromiseArray
个对象。 PromiseArray
从ArrayProxy
延伸。 ArrayProxy
是一种异步填充和数组的方法,同时仍能够立即绑定到它。 ArrayProxy
不指定应如何填充数组,因此PromiseArray
使用承诺的事实无关紧要。与任何其他阵列一样绑定到ArrayProxy
。当内容发生变化时(无论出于何种原因),您的绑定将会更新。
既然我们已经解决了这个问题,那么你做错了就是使用Ember计算助手错了。例如,Ember.comptued.sum
应该添加一个数字数组。像这样:
numbers: [1,2,3,4,5],
sum: Ember.computed.sum('numbers')
Ember负责处理@each
以及所有废话。但你没有直号,你有对象。所以你需要使用Ember.reduceComputed
(或类似的东西)。你正在使用它,但你使用了错误的密钥。你加上.@each.amount
,这不是恩伯所期待的。所以Ember默默地失败了,因为在幕后,它正在观看splits.@each.amount.@each
财产。如果您想使用reduceComputed
,您可以执行以下操作:
amount: Ember.reduceComputed('splits', { ... })
但我从未使用reduceComputed
,我喜欢保持简单,所以试试这个:
amount: function() {
return this.get('splits').reduce(function(sum, split) {
return sum + split.get('amount');
}, 0);
}.property('splits.@each.amount')
很抱歉答案很长,但我想解释一下我的解决方案,而不仅仅是解决问题。这是早期的,所以如果我搞砸了一些语法,请告诉我。但我认为你应该得到主要的想法。 :)
编辑:我把一个小的JSBin放在一起模拟你正在做的事情。你可以找到它here。您会看到objects
属性是未解析的PromiseArray
,就像您从Ember-Data hasMany关系中得到的那样。单击“解析”按钮后,承诺将解析,ArrayProxy
更新以及计算的总更新。
答案 2 :(得分:0)
试试这种方式
DS.Model.extend({
splits: DS.hasMany('split', { async: true }),
splitAmountAry:Ember.computed.mapBy('amount'),
amount:Ember.computed.sum('splitAmountAry')
})