【问题标题】:How can I do an Ember.js computed property on an Ember Data model based on an async relationship?如何基于异步关系在 Ember 数据模型上执行 Ember.js 计算属性?
【发布时间】:2014-07-14 01:53:09
【问题描述】:

我有一个 Ember 数据模型,我正在尝试基于异步 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);
});

【问题讨论】:

    标签: ember.js ember-data


    【解决方案1】:

    您的 hasMany 属性是异步的,因此它是一个承诺,并且它的值必须可以通过 then 方法访问。

    transaction.get('splits').then(function(splits) {
    
      split = store.createRecord('split', { amount: 250 }),
      splits.pushObject(split);
    
      split = store.createRecord('split', { amount: 1000 })
      splits.pushObject(split);
    
    });
    

    【讨论】:

    • 那么没有DataBoundPromises,我可以在模板中使用amount吗?
    • @Kerrick,我添加了第三个选项以使其与模板一起使用。我想,这就是你要找的。我想,这就是 DataBoundPromise 让它开箱即用的情况。
    • 实际上,我只是试了一下,在没有任何amountPromisePromiseProxyMixin 的模板中使用{{amount}} 似乎工作得很好,使第1 点为假,第3 点没有必要。看起来整个问题就是您在第 2 点中提到的关于在测试中使用 .then 的问题。
    • 是的,你是对的。使用 splits.@each 可确保根据加载的项目计算属性并正确处理结果。
    【解决方案2】:

    呵呵,我打了一个相当长的答案,才意识到你做错了什么,然后因为没有意识到这一点而笑自己。 :) 我已经很久没有使用 Ember-Data 了,但这就是我所拥有的。

    首先,这与承诺无关。 Ember-Data hasMany 关系返回 PromiseArray 对象。 PromiseArray 扩展自 ArrayProxyArrayProxy 是一种异步填充和数组的方法,同时仍然能够立即绑定到它。 ArrayProxy not 没有指定您应该如何填充数组,因此,PromiseArray 使用承诺这一事实是无关紧要的。绑定到ArrayProxy,就像绑定任何其他数组一样。当内容更改时(无论出于何种原因),您的绑定都会更新。

    既然我们已经解决了这个问题,那么您做错的就是错误地使用了 Ember 计算的帮助器。例如,Ember.comptued.sum 应该添加一个数字数组。像这样的:

    numbers: [1,2,3,4,5],
    sum: Ember.computed.sum('numbers')
    

    Ember 会为您处理 @each 和所有这些废话。但是你没有直数,你有对象。所以你需要使用Ember.reduceComputed(或类似的东西)。您正在使用它,但是您使用了错误的密钥。您添加了 .@each.amount,这不是 Ember 所期望的。所以 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 会更新,您计算的总更新也会随之更新。

    【讨论】:

    • 确实,这里使用Ember.computed.sum 似乎是错误的。但是,在尝试了您的计算属性(在功能上等同于我的问题中的第三次尝试)之后,它仍然无法正常工作。似乎真正缺少的拼图是@ppcano 提出的使用.then 访问测试中的拆分。因此,虽然您肯定会因为指出 Ember.computed.sum 的错误用法而获得支持,但我必须将答案和赏金奖励给 @ppcano,因为您的回答本身并不能帮助测试通过。
    • 另外,带有依赖键 'splits.@each.amount'reduceComputed 在我使用 .then 后似乎确实有效。
    【解决方案3】:

    试试这个方法

    DS.Model.extend({
        splits: DS.hasMany('split', { async: true }),
        splitAmountAry:Ember.computed.mapBy('amount'),
        amount:Ember.computed.sum('splitAmountAry')
    })
    

    【讨论】:

      猜你喜欢
      • 2014-04-01
      • 2014-12-21
      • 2014-01-07
      • 1970-01-01
      • 2023-04-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多