观察者总是迟到一个州

时间:2014-11-30 20:22:13

标签: ember.js

我有以下问题:http://emberjs.jsbin.com/goqera/13/我打印出所选的选项ID。 id在被检查属性更改时被触发的观察者中更新。

当您尝试它时,您将看到打印的ID总是来自之前的状态,而不是当前状态。活动计数是正确的,活动ID是一个状态...

// this computed property is correct and reflects the current checked options state
checkedOptions: Ember.computed.filterBy('model', 'checked', true),

// this observer is always one state behind
observeCheckedListOptions: function() {    
    this.set('checkedOptionIds', this.get('checkedOptions').mapBy('id'));
}.observes('model.@each.checked').on('init')

我相信观察者中的某些内容是错误的,因为计算属性checkedOptions是正确的。我做错了什么?

2 个答案:

答案 0 :(得分:2)

我不是run-loop专家,但我认为这种情况正在发生,因为您正在观察与您正在获得的属性不同的属性。因此,使用当前代码描述行为:

  1. 选中一个框,这是对model.@each.checked的更改,因此需要更新任何相关的计算属性,并且需要运行任何观察者。使用运行循环将此工作添加到队列中,计算属性更新和观察者有单独的队列。
  2. 首先,运行观察者队列 - 这会运行您的观察者,当您执行this.get('checkedOptions')时,您会获得更新前的值(因为该工作发生在较低优先级的队列中)
  3. 运行计算属性队列,根本无法帮助您。
  4. 因此,有了这些知识,您可以选择一些修复方法。不可删除的答案很好,如果你只使用计算属性,那么你不会被不同的队列抓住。另一种方法是观察你得到的属性,这样你的观察者只会在属性更新后才会触发:

    observeCheckedListOptions: function() {    
        this.set('checkedOptionIds', this.get('checkedOptions').mapBy('id'));
    }.observes('checkedOptions.@each').on('init')
    

    但是,我最喜欢的解决方案必须是使用另一个计算属性宏:

    checkedOptionIds: Ember.computed.mapBy('checkedOptions', 'id')
    

    虽然有一个问题,但这样做是一个真正的阵列和(令人讨厌的)把手拒绝呈现它(我仍然不知道为什么)所以你需要这样做以及模板中的内容:

    {{#each id in checkedOptionIds }}
        {{id}}
    {{/each}}
    

答案 1 :(得分:0)

不能确切地说是什么原因,但在你的情况下,我不明白为什么有必要使用只设置一个属性而不是计算一个属性的观察者(参见JSBin):

checkedOptionIds: function() {    
  return this.get('checkedOptions').mapBy('id');
}.property('checkedOptions.@each.checked')