我编写了一个自定义绑定处理程序来将我的viewmodel数据绑定到highcharts图表。这实际上有两部分,一部分绑定了高图所需的初始配置,第二部分将系列绑定到图表。
这是bindingHandler
代码
ko.bindingHandlers.highchart = {
update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
var value = valueAccessor();
var valueUnwrapped = ko.unwrap(value);
console.log ('update',element.id,valueUnwrapped);
if(allBindings.get('series')){
var series = allBindings.get('series');
var seriesUnwrapped = ko.unwrap(series);
if(!$.isArray(seriesUnwrapped)){
seriesUnwrapped = [seriesUnwrapped];
}
console.log('seriesUnwrapped',element.id,seriesUnwrapped)
valueUnwrapped.series = seriesUnwrapped;
}
$(element).highcharts(valueUnwrapped);
}
}
现在我为此设置了2个测试,第一个按预期工作。它将图表与多个系列绑定,当我添加到绑定到series
的可观察数组时,它只更新一次图表。查看this fiddle并在单击“添加”按钮时观察控制台。你得到的输出是
更新容器对象{chart = {...}}
seriesUnwrapped container [Object {name =“Scenario0”,color =“red”,data = [9]},Object {name =“Scenario1”,color =“green”,data = [9]}]
表示我们只完成了上述代码一次。
现在检查我的第二小提琴:http://jsfiddle.net/8j6e5/9/。这略有不同,因为highcharts初始配置是computed
可观察的,系列也是如此。当您单击此处的“添加”按钮时,您将看到绑定执行两次:
更新container2对象{chart = {...},xAxis = {...},series = [1]}
seriesUnwrapped container2 [Object {name =“Scenario2”,color =“blue”,data = [2]}]
update container2 Object {chart = {...},xAxis = {...}}
seriesUnwrapped container2 [Object {name =“Scenario2”,color =“blue”,data = [2]}]
我猜测在我的highcharts绑定处理程序中使用allBindings.get('series')
我设置了它的依赖关系,并且当两个绑定更改其执行highcharts绑定两次。我的问题是,有没有办法阻止这种情况,或者以任何其他方式编写此功能,以免发生这种情况?
答案 0 :(得分:3)
我不确定这会对你有什么帮助,因为上面评论中的nemesv答案似乎非常接近你想要达到的目标,即。停止双重更新。
然而,我花了一点时间,所以我会告诉你我想出了什么,并希望它有所帮助。
我不知道nemesv提到的peek()方法(很棒的提示),所以我根据计算结果等调查了两次更新的原因。
我看到你的self.breakdownChart正在访问currentScenario observable,当我把它作为测试删除时,第二次更新没有发生。
所以这让我思考,为什么你需要在那里进行x轴设置。
所以我在你的场景中添加了一个新属性来返回当前的场景名称
self.name='Scenario' + self.number;
然后对于基本场景,将其更改为“Base Scenario”以确保标题仅针对该系列正确显示。
为确保图例/轴正确,我在图表对象中添加了一个名为baseSeriesName的新属性
self.breakdownChart = ko.computed(function(){
return {
baseSeriesTitle: baseScenario.name,
并将其设置为baseScenario的名称。
最后,要在BindingHandler中将所有内容绑定在一起,我在那里更新xAxis:
//set the xAxis titles, only add the second title if different from the base
valueUnwrapped.xAxis={
categories: [valueUnwrapped.baseSeriesTitle, valueUnwrapped.baseSeriesTitle!=seriesUnwrapped[0].name ? seriesUnwrapped[0].name:'']
}
这是一些重构,但它实现了你的目标;希望它有所帮助。
哦,我还在视图模型中添加了一个mapType observable,并在图表定义中使用了它(insightChart computed),以测试如果图表在不同的observable上刷新并且它仍然初始化时不会发生双重更新正确 - 所以小提琴显示chartType更新,没有双重更新。
答案 1 :(得分:3)
你得到两个更新,因为Knockout会在它们的依赖项发生变化时立即更新计算的observable,并且你的绑定有两个依赖项,每个依赖项都会依次更新。
解决此问题的一种方法是使用一种技术来延迟绑定的更新。一种简单的方法是使用Deferred Updates plugin,如下所示:http://jsfiddle.net/mbest/8j6e5/15/
延迟更新使用setTimeout
执行更新,这意味着更新是异步发生的。如果您希望它与特定更新同步,则可以使用ko.tasks.processImmediate
:
ko.tasks.processImmediate(function() {
self.scenarios.push(newScenario);
self.currentScenario(newScenario);
});