Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/382.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 自定义敲除绑定意外触发两次_Javascript_Knockout.js_Bindinghandlers - Fatal编程技术网

Javascript 自定义敲除绑定意外触发两次

Javascript 自定义敲除绑定意外触发两次,javascript,knockout.js,bindinghandlers,Javascript,Knockout.js,Bindinghandlers,我已经编写了一个自定义绑定处理程序,将viewmodel数据绑定到highcharts图表。这实际上有两个部分,一个绑定highcharts所需的初始配置,第二个绑定系列到图表 下面是bindingHandler代码 现在我为此设置了两个测试,第一个测试按预期工作。它将一个图表与多个系列绑定,当我添加到绑定到该系列的可观察数组时,它只会更新图表一次。单击add按钮时,查看并观看控制台。您将得到的输出是 更新容器对象{chart={…} 序列展开容器[Object{name=Scenario0,c

我已经编写了一个自定义绑定处理程序,将viewmodel数据绑定到highcharts图表。这实际上有两个部分,一个绑定highcharts所需的初始配置,第二个绑定系列到图表

下面是bindingHandler代码

现在我为此设置了两个测试,第一个测试按预期工作。它将一个图表与多个系列绑定,当我添加到绑定到该系列的可观察数组时,它只会更新图表一次。单击add按钮时,查看并观看控制台。您将得到的输出是

更新容器对象{chart={…} 序列展开容器[Object{name=Scenario0,color=red,data=[9]},Object{name=Scenario1,color=green,data=[9]}]

这表明我们只看过上面的代码一次

现在检查我的副手:。这与highcharts的初始配置略有不同,因为highcharts的初始配置是一个计算的可观察配置,序列也是如此。单击此按钮上的“添加”按钮时,您将看到绑定执行了两次:

更新container2对象{chart={…},xAxis={…},series=[1]} 序列展开的容器2[对象{name=Scenario2,color=blue,data=[2]}] 更新container2对象{chart={…},xAxis={…} 序列展开的容器2[对象{name=Scenario2,color=blue,data=[2]}]


我猜在highcharts绑定处理程序中使用allBindings.get'series时,我设置了一个对它的依赖关系,当两个绑定都更改时,我会执行两次highcharts绑定。我的问题是,是否有任何方法可以停止此操作,或以任何其他方式编写此功能以避免发生这种情况?

我不确定这是否会对您有所帮助,因为上面评论中的nemesv回答似乎非常接近您想要实现的目标,即停止双重更新

然而,我已经花了一点时间在它上面,所以我将向你展示我的想法,希望它能有所帮助

我不知道nemesv提到的peek方法有多棒,所以我研究了为什么它会根据计算结果更新两次

我看到你的self.breakdownhart正在访问可观察的currentScenario,当我将其作为测试删除时,第二次更新没有发生

这让我思考,为什么你需要在x轴设置中使用它

因此,我在场景中添加了一个新属性,以返回当前场景名称

 self.name='Scenario' + self.number;
然后,对于基本场景,将其更改为基本场景,以确保仅该系列的标题正确显示

为了确保图例/轴是正确的,我向图表对象添加了一个名为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:'']
        }   
这是一点重构,但它实现了您的目标;希望能有帮助


哦,我还向视图模型中添加了一个chartType observable,并在图表定义分解图computed中使用它来测试如果图表在不同的observable上刷新,并且它仍然正确初始化,则不会发生双重更新-因此小提琴显示图表类型更新,不需要双重更新。

您会得到两次更新,因为淘汰更新会在其依赖项更改时立即计算可观察项,并且您的绑定有两个依赖项,每个依赖项依次更新

解决这个问题的一种方法是使用一种技术来延迟绑定的更新。一种简单的方法是使用,如下所示:

延迟更新使用setTimeout执行更新,这意味着更新是异步进行的。如果希望对特定更新进行同步,可以使用ko.tasks.processImmediate:


您必须决定何时调用更新函数。因此,当绑定属性更改或序列绑定属性更改时。然后使用peek而不是ko.unwrap:var seriesUnwrapped=series.peek;或var valueUnwrapped=value.peek;在调用peek之前,您当然需要检查值或序列是否真的可以观察到。@nemesv-这是一个非常好的开始,仅此一项就解决了双重调用问题。然而,在做了那个简单的更改之后,我的第一个小提琴将不再更新,因为它绑定到一个计算序列,而是一个静态highchart属性。你已经有了三分之二的答案。如果你用var valueUnwrapped=ko.isObservablevalue这个值来回答这个问题?value.peek:值;它解决了这两个问题。但是如果绑定为highchart:yourProp,series:otherProp,并且只有yourProp更改,而otherProp没有更改,那么它将无法正确更新图表。。。
       //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:'']
        }   
ko.tasks.processImmediate(function() {
    self.scenarios.push(newScenario);
    self.currentScenario(newScenario);
});