2014-02-11 77 views
-1

我已經寫了一個自定義綁定處理程序,以將我的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並在點擊「添加」按鈕時觀看控制檯。你會得到的輸出是

更新容器對象{圖= {...}}
seriesUnwrapped容器[對象{名= 「Scenario0」,顏色= 「紅色」,數據= [9]} ,Object {name =「Scenario1」,color =「green」,data = [9]}]

表示我們已經完成了上述代碼一次。

現在檢查我的第二個小提琴:http://jsfiddle.net/8j6e5/9/。這與稍高一籌的初始配置是一個可觀察的computed稍有不同,該系列也是如此。當你點擊這個「添加」按鈕時,你會看到綁定被執行兩次:

update container2 Object {chart = {...},xAxis = {...},series = [ 1]}
series展開容器2 [Object {name =「Scenario2」,color =「blue」,data = [2]}]
update container2 Object {chart = {...},xAxis = {...} }
seriesUnwrapped container2的[對象名{= 「Scenario2」,顏色= 「藍色」,數據= [2]}]

我猜測,使用我highcharts內allBindings.get('series')結合處理程序予置建立對它的依賴關係,並且當兩個綁定都改變其執行兩次highcharts綁定的時候。我的問題是,是否有任何方法可以阻止此問題,或以其他方式編寫此功能以避免發生這種情況?

+1

您必須決定何時要調用您的更新函數。所以當你的綁定屬性發生變化時或者當'series'綁定屬性發生變化時。然後使用'peek()'而不是'ko.unwrap':'var seriesUnwrapped = series.peek();'或'var valueUnwrapped = value.peek();'你當然需要檢查'價值「或」系列「在對他們進行偷看之前確實是可觀察的。 – nemesv

+0

@nemesv - 這是一個非常好的開始,僅此一項就解決了雙重調用問題。然而,在做了簡單的更改之後,我的第一個小提琴不再更新(因爲它綁定到一個計算系列,但是是一個靜態高圖屬性)。你是一個非常好的答案的三分之二。 – Jamiec

+1

如果你使用值'var valueUnwrapped = ko.isObservable(value)來做到這一點? value.peek():value;'它解決了這兩個問題。但是當你的綁定是'highchart:yourProp,series:otherProp'和只有'yourProp'發生了變化,而'otherProp'不會再次它不會正確地更新你的圖表... – nemesv

回答

3

我不確定這會對你有幫助,因爲nemesv在上述評論中的回答似乎與你想達到的目標非常接近。停止雙重更新。

但是,我花了一些時間在上面,所以我會告訴你我想出了什麼,並希望它有幫助。

Fiddle here

我不知道這nemesv提到的PEEK()方法(偉大的小費),所以我看着它爲什麼被更新基礎上,computeds等

我看到兩次您的self.breakdownChart正在訪問當前的情景可觀察性,並且當我將其作爲測試移除時,第二次更新沒有發生。

因此,讓我想到,爲什麼你需要在那裏的X軸設置。

所以我增加了一個新的屬性,以您的方案,以返回當前場景名稱

self.name='Scenario' + self.number; 

然後爲基礎的情況下,把它改爲「基本方案」,以確保標題顯示正確的只是系列。

爲了保證傳說/軸是正確的,我添加了一個新的屬性稱爲baseSeriesName

self.breakdownChart = ko.computed(function(){ 
    return {  
     baseSeriesTitle: baseScenario.name, 

圖表對象並設置爲baseScenario的名字。

最後,以配合所有一起在BindingHandler,我在那裏更新X軸:

 //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觀察值,並在圖表定義(breakdownChart computed)中使用它來測試雙重更新不會發生,如果圖表刷新到不同的可觀察值並且它仍然正確初始化 - 所以小提琴顯示chartType更新,沒有雙重更新。

3

由於Knockout在其依賴關係發生更改時立即更新計算的observables,並且您的綁定具有兩個依賴項,每個依賴項依次更新,您會得到兩個更新。

解決此問題的一種方法是使用一種技術來延遲綁定的更新。一個簡單的方法是使用Deferred Updates plugin,如下所示:http://jsfiddle.net/mbest/8j6e5/15/

延期更新使用setTimeout執行更新,這意味着更新是異步發生的。如果您希望它是同步的特定更新,您可以使用ko.tasks.processImmediate

ko.tasks.processImmediate(function() { 
    self.scenarios.push(newScenario); 
    self.currentScenario(newScenario); 
});