[英]In Ember, is there a way to update a component without a full re-render/route transition
[英]EmberJS, polling, update route's model, re-render component
我一直在寻找更新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');
}
});
在这个实验中,我使用夹具:
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”字段的值)。
这样做的正确方法是什么? 我一直在尝试使用setInterval并调用Route的refresh()方法,但到目前为止还没有成功。
谢谢你的帮助!,拉卡
添加(我在这里添加了我的附加注释以进行格式化)。
我在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未定义。 我打算在Route对象上调用'refresh'方法,因为我希望重新执行模型钩子。 如何从setInterval函数获取对IndexRoute实例的引用?
这是触发刷新的正确/最佳方式,顺便说一句?
(并且,根据下面的Oliver的建议,我还在控制器中的'update'函数中添加了观察('model')。所以现在就是这样:
App.BarChartComponent = Ember.Component.extend({
classNames: ['chart'],
model: null,
chart: BarChart(),
didInsertElement: function() {
...
},
update: function() {
...
}.observes('model')
});
附加2(对EmberJS的回应,轮询,更新路线的模型,重新渲染组件 )
得到它了! 谢谢。
现在对于更新用例(后端中的元素数保持不变,id保持不变,只有“金额”随时间变化)。 我将setInterval块修改为:
setInterval(function () {
App.Sales.FIXTURES.forEach(function(elem) {
elem.amount = elem.amount + 5;
});
console.log('z');
}, 1500);
现在的问题是,BarChartComponent中观察“model。@ each”的“update”方法永远不会被调用(好像我在BarChartComponent中没有听到我在夹具元素中所做的更改)。
我需要添加哪些指令?
附加3( EmberJS的详细信息,轮询,更新路线的模型,重新渲染组件 ):
我将IndexController的定义添加到我的代码中,只是为了确认我对FIXTURE中元素的更改至少是由Controller听到的(它是)。
所以,现在的问题是组件也能听到这种变化。 怎么样? 我应该从我的控制器调用一些“渲染”功能来要求组件重绘吗?
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
实际上是一个类定义,而不是一个实例。
对于您的特定情况,这里有一些重要的事项需要注意, 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.[]')
你只需要观看模型。 没有?
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')
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.