EmberJS,轮询,更新路线模型,重新渲染组件 [英] EmberJS, polling, update route's model, re-render component

查看:39
本文介绍了EmberJS,轮询,更新路线模型,重新渲染组件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在寻找更新路线模型的机制,并且让Component(从与该路线相关的模板中调用)对该事件做出反应,然后重新呈现.

I've been looking for mechanism to update the model of a Route, and has the Component (called from within the template associated with that route) reacts to that event, and re-render itself.

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

So I have the index template like this (I pass in the model of the IndexController, which to my understanding is just a proxy to IndexRoute -- I don't have IndexController defined, by the way):

<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文件中实现的,如下所示:

My component is implemented in a separate JS file, like this:

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生成图形.

The BarChart() function is simply returns a function object that performs the DOM manipulation to generate the graph using D3.

我的IndexRoute的定义如下:

My IndexRoute is defined like this:

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

在此实验过程中,我使用夹具:

During this experiment, I use 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}
];

我需要实现一种机制,以定期轮询商店并更新Route的模型,并使EmberJS的魔力再次调用render函数(在BarChart组件中分配给"chart"字段的值).

I need to implement a mechanism to periodically poll the store and update the model of the Route, and has EmberJS's magic invoke again the render function (the value assigned to "chart" field in the BarChart component).

做到这一点的正确方法是什么?我一直在尝试使用setInterval并调用Route的refresh()方法,但到目前为止尚未成功.

What's the correct way to do that? I've been trying to use setInterval and calling refresh() method of the Route, but have not been successful so far.

感谢您的帮助!,拉卡

添加(我在此处添加了有关格式的其他注释).

ADDITION (I put my additional comment here for the formatting).

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

I added the call to setInterval in my app.js, like this:

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是未定义的.我打算在Route对象上调用'refresh'方法,因为我希望重新执行模型挂钩.如何从setInterval函数获取对IndexRoute实例的引用?

But I'm getting JavaScript error, telling me that App.IndexRoute is undefined. I intend to call the 'refresh' method on the Route object because I'm hoping the model hook to be re-executed. How do I obtain a reference to instance of IndexRoute from my setInterval function?

这是触发刷新的正确/最佳方法吗,顺便说一句?

Is this the correct / best way to trigger the refresh, btw?

(并且,按照下面的Oliver的建议,我还在控制器的"update"函数中添加了observes('model').所以现在就像这样:

(and, following the suggestion from Oliver below, I also added observes('model') to my 'update' function in the controller. So it is like this now:

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

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


添加2(响应 EmberJS,轮询,更新路由的模型,重新渲染组件)

知道了!谢谢.

现在用于更新用例(后端中的元素数保持不变,id保持不变,只有数量"随时间变化).我将setInterval块修改为:

Now for the updating use case (the number of elements in the backend stays the same, the ids stay the same, only the "amount" changes over time). I modified setInterval block to this:

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

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

现在的问题是,BarChartComponent中观察"model.@ each"的"update"方法从未被调用(就像BarChartComponent没听到我对灯具元素所做的更改一样).

The problem now, the "update" method in BarChartComponent that observes "model.@each" never gets called (as if the changes I did in the elements of the fixture wasn't heard by the BarChartComponent).

我需要添加什么说明?

添加3(有关 EmberJS,轮询,更新路由的详细信息模型,重新渲染组件):

我在代码中添加了IndexController的定义,只是为了确认我对FIXTURE中的元素所做的更改至少已被Controller听到(确实如此).

I added the definition of IndexController to my code, just to confirm that my changes to the elements in the FIXTURE was heard at least by the Controller (it is).

因此,现在的问题是组件也听到了更改.如何?我应该从控制器中调用一些渲染"功能来要求组件重绘吗?

So, the problem now is making that change is also heard by the Component. How? Should I call some "render" function from my controller to ask the component to redraw itself?

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

推荐答案

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

App.IndexRoute is actually a class definition, not an instance.

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

For your particular case there are some important things to note here, find('type') returns the all filter which automatically updates as you add/remove items from the store. So you could just call find again anywhere in the code (for that type), and it would automatically update your collection. Additionally you would want to control the updating at the route level, that way you don't keep updating when you aren't in scope.

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

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

Additionally, for your component, you'd want to watch the array, not just the model itself (since the model reference won't update, meaning the observes method wouldn't be called). You would do something like this

watchingForModelChange: function(){

}.observes('model.[]')  

这篇关于EmberJS,轮询,更新路线模型,重新渲染组件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆