EmberJS,轮询,更新路线的模型,重新渲染组件

时间:2014-07-20 19:56:54

标签: ember.js model controller routes refresh

我一直在寻找更新Route模型的机制,并让Component(在与该路由关联的模板中调用)对该事件作出反应,然后重新渲染自己。

所以我有这样的索引模板(我传入了IndexController的模型,据我所知,它只是IndexRoute的代理 - 顺便说一句,我没有定义IndexController):

<script type="text/x-handlebars" id="index">
  Below is the bar-chart component
  <br/>
  {{bar-chart model=model}}
</script>

我的组件模板如下:

<script type="text/x-handlebars" data-template-name="components/bar-chart">
</script>

我的组件是在一个单独的JS文件中实现的,如下所示:

App.BarChartComponent = Ember.Component.extend({
  classNames: ['chart'],
  model: null,
  chart: BarChart(),
  didInsertElement: function() {
    Ember.run.once(this, 'update');
  },

  update: function() {
    var data = this.get('model').map(function(sales) {
      return sales.get('amount');
    });

    d3.select(this.$()[0]).selectAll('div.h-bar')
      .data(data)
      .call(this.get('chart'));
  }
}); 

BarChart()函数只返回一个函数对象,该对象执行DOM操作以使用D3生成图形。

我的IndexRoute定义如下:

App.IndexRoute = Ember.Route.extend({
  model: function() {
    return this.store.find('sales');
  }
});

在这个实验中,我使用fixture:

App.Sales = DS.Model.extend({
  amount: DS.attr('number') 
});

idx = 1;

App.Sales.FIXTURES = [
  {id: idx++, amount: 2}, {id: idx++, amount: 6}, {id: idx++, amount: 12}, 
  {id: idx++, amount: 17}, {id: idx++, amount: 8}
];

我需要实现一种机制来定期轮询商店并更新路线的模型,并让EmberJS的魔法再次调用渲染功能(分配给&#34;图表&#34;字段的值BarChart组件)。

这样做的正确方法是什么?我一直在尝试使用setInterval并调用Route的refresh()方法,但到目前为止还没有成功。

感谢您的帮助! 拉嘎


ADDITION(我在这里添加了我的附加注释以进行格式化)。

我在app.js中添加了对setInterval的调用,如下所示:

setInterval(function () { 
  App.Sales.FIXTURES.shift();
  App.Sales.FIXTURES.push({
    id: idx++,
    amount: Math.round(Math.random() * 20)
  });

  App.IndexRoute.refresh();
}, 1500);

但是我收到了JavaScript错误,告诉我App.IndexRoute未定义。我打算打电话给'刷新&#39; Route对象上的方法,因为我希望重新执行模型钩子。如何从setInterval函数获取对IndexRoute实例的引用?

这是触发刷新的正确/最佳方式,btw?

(并且,根据以下Oliver的建议,我还在控制器中的更新功能中添加了观察(&#39;型号&#39;)。现在就像这样:< / p>

App.BarChartComponent = Ember.Component.extend({
  classNames: ['chart'],
  model: null,
  chart: BarChart(),
  didInsertElement: function() {
    ...
  },

  update: function() {
    ...
  }.observes('model')
}); 

附加2(对EmberJS, polling, update route's model, re-render component的回复)

知道了! THX。

现在对于更新用例(后端中的元素数保持不变,ID保持不变,只有&#34;金额&#34;随时间变化)。我将setInterval块修改为:

setInterval(function () { 
  App.Sales.FIXTURES.forEach(function(elem) {
    elem.amount = elem.amount + 5;
  });

  console.log('z');
}, 1500);

现在的问题,&#34;更新&#34; BarChartComponent中观察&#34;模型的方法。@ each&#34;永远不会被调用(好像我在BarChartComponent没有听到过夹具元素所做的更改)。

我需要添加哪些指示?


附加3(EmberJS, polling, update route's model, re-render component的详细信息):

我在我的代码中添加了IndexController的定义,只是为了确认我至少听到了对FIXTURE中元素的更改(它是)。

所以,现在的问题是组件也能听到这种变化。怎么样?我应该打电话给#34;渲染&#34;从我的控制器函数请求组件重绘自己?

App.IndexController = Ember.ArrayController.extend({
  totalAmount: function() {
    console.log("iiii");
    var total = 0;
    this.forEach(function(sales) {
      console.log("a... " + sales.get('amount'));
      total += sales.get('amount');
    });
    return total;
  }.property('@each.amount')
});

2 个答案:

答案 0 :(得分:11)

App.IndexRoute实际上是一个类定义,而不是一个实例。

对于您的特定情况,此处需要注意一些重要事项,find('type')会返回all过滤器,该过滤器会在您添加/删除商店中的商品时自动更新。因此,您可以再次在代码中的任何位置(对于该类型)调用find,它会自动更新您的集合。另外,您可能希望控制路由级别的更新,这样当您不在范围内时就不会继续更新。

App.IndexRoute = Ember.Route.extend({
  model: function() {
    return this.store.find('sales');
  },
  setupController: function(controller, model){
    this._super(controller, model); // do the default implementation since I'm overriding this func
    this.startRefreshing();
  },
  startRefreshing: function(){
    this.set('refreshing', true);
    Em.run.later(this, this.refresh, 30000);
  },
  refresh: function(){
    if(!this.get('refreshing'))
      return;
    this.store.find('sales')
    Em.run.later(this, this.refresh, 30000);
  },
  actions:{
    willTransition: function(){
      this.set('refreshing', false);
    }
  }
});

示例:http://emberjs.jsbin.com/OxIDiVU/825/edit

此外,对于您的组件,您需要观察数组,而不仅仅是模型本身(因为模型引用不会更新,这意味着不会调用观察方法)。你会做这样的事情

watchingForModelChange: function(){

}.observes('model.[]')  

答案 1 :(得分:0)

您只需要观看模型。否?

update: function() {
  var data = this.get('model').map(function(sales) {
    return sales.get('amount');
  });

  d3.select(this.$()[0]).selectAll('div.h-bar')
    .data(data)
    .call(this.get('chart'));
}.property('model')
相关问题