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

时间:2013-09-25 16:33:06

标签: ember.js

我制作了一个图表组件,我想让它在下列任何一种情况下呈现:

  1. data属性更改
  2. 将其插入DOM
  3. 问题是,如果这两个事件都发生,图表会被渲染两次。

    这是组件:

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

    我正在使用它(它在公司模板中呈现)

    {{bar-chart data=controller.controllers.companies.data
                isLoaded=controller.controllers.companies.model.isLoaded}}
    

    控制器看起来像这样(更改路径更新CompaniesController模型):

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

    我现在没有时间制作一个jsfiddle,但除了一种情况外,一切都按预期工作:我从index路线开始,然后加载模型,然后返回到index路线。此时,数据将加载前一个路由(比如公司A,B和C),但因为我在index路由上,所以组件未被渲染。现在,如果我点击路线(比如公司D,E,F),这就是发生的事情(据我所知):

    • 在承诺结算并加载新公司之前,没有任何事情发生。
    • 加载后,companies模板即会呈现。这会在我的组件中触发didInsertElement,并运行update函数。
    • 我的data中的CompaniesController计算属性再次计算,触发其更改事件。
    • 我的组件中的update方法会观察data中的更改并重新呈现自己。

    因此,图表会呈现两次,一次是旧数据,一次是新数据。如果它是瞬间的,也许没关系,但因为它有一个平滑的动画,它是显而易见的。

    我认为使用Ember.run.once可以防止这种情况发生,但我猜不会 - 或者我使用它不正确。看起来我需要的是不仅要检查模型是否已加载,还要检查控制器是否已完成交换其内容。我非常感谢任何想法!

1 个答案:

答案 0 :(得分:0)

我最后在输入索引路径时手动清除控制器上的content属性:

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