Ember.js 确保观察者每次运行循环触发一次

Ember.js 确保观察者每次运行循环触发一次,ember.js,Ember.js,我制作了一个图表组件,并希望在出现以下情况时进行渲染: 其数据属性发生变化 它被插入到DOM中 问题是,如果这两个事件都发生,图表将呈现两次 以下是组件: App.BarChartComponent = Ember.Component.extend({ classNames: ['chart'], chart: BarChart().margin({left: 40, top: 40, bottom: 80, right: 40}), didInsertElement: func

我制作了一个图表组件,并希望在出现以下情况时进行渲染:

  • 数据
    属性发生变化
  • 它被插入到DOM中
  • 问题是,如果这两个事件都发生,图表将呈现两次

    以下是组件:

    App.BarChartComponent = Ember.Component.extend({
      classNames: ['chart'],
    
      chart: BarChart().margin({left: 40, top: 40, bottom: 80, right: 40}),
    
      didInsertElement: function() {
        Ember.run.once(this, 'update');
      },
    
      update: function() {
        if (this.get('isLoaded')) {
          d3.select(this.$()[0])
            .data([ this.get('data') ])
            .call(this.get('chart'));
        }
      }.observes('data')
    });
    
    我这样使用它(它在公司模板中呈现)

    控制器如下所示(更改路线会更新
    CompaniesController
    模型):

    我现在没有时间做一个JSFIDLE,但是除了一种情况外,其他一切都按照预期工作:我从
    索引
    路径开始,然后加载一个模型,然后返回
    索引
    路径。此时,将加载上一个路由的数据(例如公司A、B和C),但由于我在
    索引
    路由上,因此不会渲染组件。现在,如果我点击一条新路线(比如D、E、F公司),下面是发生的情况(据我所知):

    • 在承诺达成、新公司成立之前,一切都不会发生
    • 一旦加载,就会呈现
      公司
      模板。这将在我的组件中触发
      didInsertElement
      ,并运行
      update
      功能
    • my
      CompanyController
      中的
      data
      computed属性将再次计算,并触发其更改事件
    • my component中的
      update
      方法观察
      数据中的更改,并重新渲染自身
    因此,图表会呈现两次,一次是使用旧数据,一次是使用新数据。如果它是瞬间的,也许这无关紧要,但因为它有一个平滑的动画,所以它是显而易见的


    我原以为使用
    Ember.run.once
    可以防止这种情况发生,但我想不会,或者我用错了。看起来我需要的不仅仅是检查模型是否加载,还要检查控制器是否完成了内容交换。如果有任何想法,我将不胜感激

    在进入索引路由时,我手动清除控制器上的
    内容
    属性:

    App.IndexRoute = Ember.Route.extend({
      setupController: function(controller, model) {
        this.controllerFor('monthlyReport').set('content', null);
        this.controllerFor('companies').set('content', null);
      }
    });
    

    Ember.run.once
    Ember.run.scheduleOnce('actions',…)
    相同,因为渲染视图时需要执行更新方法,因为d3将更改渲染的dom。也许安全的方法是使用
    Ember.run.scheduleOnce('afterRender',this,'update')
    App.CompaniesController = Ember.ArrayController.extend({
      data: function() {
        if (!this.get('model.isLoaded')) {return;}
    
        var data = this.map(function(company) {
          return {
            category: company.get('name'),
            count: company.get('newContracts'),
          };
        });
    
        return data;
      }.property('model')
    });
    
    App.IndexRoute = Ember.Route.extend({
      setupController: function(controller, model) {
        this.controllerFor('monthlyReport').set('content', null);
        this.controllerFor('companies').set('content', null);
      }
    });