Ember js @each一层深,但我有两个深层关系

时间:2016-03-15 12:23:14

标签: ember.js computed-properties

我必须访问我控制器上两层深的属性,但[]只能通过emberjs指南深入访问一级。

model(params) {
    params.paramMapping = {
        page: "page",
        perPage: "per_page",
        total_pages: "pages"
    };

    return this.findPaged('contractf', params);
},

setupController(controller, model) {
    model.forEach(function(item) {
        item.set('sale_price', item.get('dealers_sched_id.sale_price'));
    });

    controller.set('content', model);
},

上面,我的模型基本上是在contractf模型中以分页格式获取所有记录。然后我设置我的控制器并遍历所有这些模型,并绑定一个sale_price属性进入它的关系,以获得正确的模型关系中的sale_price。

现在在我的模板中,我有这个:

new_suggested_price: Ember.computed('selectedItems', 'selectedItems.[].sale_price', function() {
    var ret = 0;

    this.get('selectedItems').filterBy('car_used', 'N').forEach(function(contract){
        var salePrice = contract.get('sale_price');

        if (salePrice) {
            ret += (salePrice*100);
        }
    });

    return ret/100; // We *100/100, so we avoid a floating point calc error.
}),

基本上只给我一个易于格式化的数字。正如您所看到的,它取决于selectedItems(基本上是模型,但是属性过滤)。所以我必须进入每个模型项并找到我设置的sale_price I属性,如果它发生变化,这个计算属性将更新。阅读Ember的指南,我无法selectedItems.[].dealers_sched_id.sale_price,因为它只有一层深。

我认为在setupController上设置一个属性可以解决这个问题,但它似乎并不是因为我仍然将NaN作为sale_price值。

现在,如果我将setTimeout函数设置为500毫秒,它会填充正常。如何在页面加载时定义它?

感谢您的帮助。

2 个答案:

答案 0 :(得分:16)

为什么会出现此问题

Ember API确实允许您在计算的属性依赖项中仅使用一级@each / []

这种限制可能是假设的,因为使用两个或更多@each级别会对内部观察者维护产生巨大的性能影响。

因此,您必须在CP依赖关系链中避免多个@each / []

如果你没有N个蜡烛的蛋糕,那么N个蛋糕每个蜡烛

但有时候你的生意会要求你达到或超过等级。

不要害怕!这可以通过一系列计算属性来实现,其中每个属性只有一个@each级别。

说,你有Foo,Bar和Baz模型,并希望依赖

foos.@each.bars.@each.bazes.@each.name

以下是您需要创建的一系列计算属性:

  • barsArrays: computed('foos.@each.bars') - foos地图bars。你将拥有一系列条形数组。
  • bars: computed('barsArrays.[]') - 展平它以接收一系列酒吧。
  • bazesArrays: computed('bars.@each.bazes') - bars地图bazes
  • bazes: computed('bazesArrays.[]') - 展平bazesArrays
  • bazesNames: computed('bazes.@each.name') - bazes地图name

如何缩短链条

请注意,依赖于bar.bazes是一个永远不会被其他数组替换的关系数组(只有其内容发生更改,但是数组)这一事实,您可以缩短此链(但不一定更高性能)对象保持不变)。

  • bazesArrays: computed('foos.@each.bars') - 按foos映射bars,展平,然后按bazes映射。你将拥有一系列bazes阵列。
  • bazes: computed('bazesArrays.[]') - 展平bazesArrays
  • bazesNames: computed('bazes.@each.name') - bazes地图name

这是一个有效的演示:http://emberjs.jsbin.com/velayu/4/edit?html,js,output

答案 1 :(得分:0)

model.forEach(function(item) {
  item.set('sale_price', item.get('dealers_sched_id.sale_price'));
});

在这一行中,你基本上是在尝试创建一个别名,这是正确的想法,因为它是一个"模型级"关注..你在控制器层面要做的事情。

您可以在模型定义上创建computed.alias('dealers_sched_id.sale_price'),并避免所有额外的计算属性层。

编辑:在您的情况下,我们正在处理异步关系

这意味着您需要注意,当关系承诺仍在解决时,您并不总是可以使用该值。你得到NaN的原因是belongsTo在技术上仍然是#34; loading" ...所以你尝试执行的任何同步功能都可能会失败。

当您查看提供给您的两个答案(涉及计算属性)时,请理解两个方法工作......他们将在承诺解决时计算并重新计算。

在您的代码中的某个位置,您可能正在尝试访问最终值,然后才真正为您准备好......可能是alert() console.log()或其中一个Ember的同步生命周期钩子(提示:setupController)?

另一种方法可能是在解决路线之前使用您的路线model()挂钩或afterModel()来询问dealers_sched_id物品......可能不太理想,但它会确保您在尝试使用这些值之前获得所需的所有数据。