6

I have to access a property that is two level's deep on my controller, but the [] only can access one level deep via the emberjs guide.

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);
},

Above, I have my model which is basically fetching all records in a pagination format in the contractf model. Then I set up my controller and loop through all those models and bind a sale_price property that goes into it's relationship to get the sale_price in the correct model relation.

Now in my template, I have this:

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.
}),

Basically just gives me a number that is easily format-able. As you can see it depends on the selectedItems (which is basically the model, but filters by a property). So I have to go into each model item and find that sale_price I property I set and if it changes, this computed property will update. Reading Ember's guide, I couldn't do selectedItems.[].dealers_sched_id.sale_price because it only goes one level deep.

I thought setting a property on setupController would fix that issue, but it doesn't seem to because I'm still getting NaN as the sale_price value.

Now if I set a setTimeout function for 500 ms, it populates fine.. How do I get it defined on page load?

Thank you for any help.

4

2 回答 2

20

为什么会存在这个问题

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

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

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

如果你不能用 N 根蜡烛做蛋糕,那就做 N 个蛋糕,每人一根蜡烛

但有时您的业务要求您必须达到或更高级别。

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

比如说,你有 Foo、Bar 和 Baz 模型并且想要依赖

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

这是您需要创建的计算属性链:

  • barsArrays: computed('foos.@each.bars')-映射foosbars您将拥有一系列条形图。
  • bars: computed('barsArrays.[]')-- 将其展平以接收一系列条形图。
  • bazesArrays: computed('bars.@each.bazes')-映射barsbazes
  • bazes: computed('bazesArrays.[]')——压扁bazesArrays
  • bazesNames: computed('bazes.@each.name')-映射bazesname

如何让链条变短

请注意,您可以通过依赖关系数组这一事实来缩短此链(但不一定提高性能),bar.bazes该关系数组永远不会被不同的数组替换(仅其内容发生变化,但数组对象保持不变)。

  • bazesArrays: computed('foos.@each.bars')--foos按映射bars,展平,然后按 映射bazes。您将拥有一系列 baze。
  • bazes: computed('bazesArrays.[]')——压扁bazesArrays
  • bazesNames: computed('bazes.@each.name')-映射bazesname

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

于 2016-03-15T14:22:00.103 回答
0
model.forEach(function(item) {
  item.set('sale_price', item.get('dealers_sched_id.sale_price'));
});

在这里的这一行中,您实际上是在尝试创建一个别名,这是正确的想法,因为它是一个“模型级别”的关注点。您将在控制器级别执行此操作。

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

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

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

当您查看提供给您的两个答案时,涉及计算属性,请理解这两种方法都可以工作......当承诺解决时,它们将计算和重新计算。

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

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

于 2016-03-15T14:28:50.683 回答