0

ビューモデル データをハイチャート チャートにバインドするカスタム バインディング ハンドラーを作成しました。これには実際には 2 つの部分があり、1 つはハイチャートに必要な初期構成をバインドし、2 つ目は系列をチャートにバインドします。

ここに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、チャートが一度だけ更新されます。このフィドルを見て、「追加」ボタンをクリックするときにコンソールを見てください。得られる出力は

update container Object { chart={...}}
seriesUnwrapped container [Object { name="Scenario0", color="red", data=[9]}, Object { name="Scenario1", color="green",データ=[9]}]

上記のコードを 1 回だけ実行したことを示します。

次に、2 番目のフィドルを確認してください: http://jsfiddle.net/8j6e5/9/computedシリーズと同様に、ハイチャートの初期構成は観察可能であるため、これはわずかに異なります。これで「追加」ボタンをクリックすると、バインディングが 2 回実行されることがわかります。

update container2 Object { 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]}]

ハイチャートバインディングハンドラー内で使用allBindings.get('series')して依存関係を設定し、両方のバインディングが変更されたときに、ハイチャートバインディングを2回実行していると推測しています。私の質問は、これを停止する方法、またはこれが起こらないようにこの機能を他の方法で書く方法はありますか?

4

2 に答える 2

3

上記のコメントのnemesvの回答は、あなたが達成したいものに非常に近いように見えるため、これが役立つかどうかはわかりません。二重更新を停止します。

しかし、私はそれに少し時間を費やしたので、とにかく私が思いついたことをお見せし、それが役に立てば幸いです.

ここでフィドル

nemesv が言及した peek() メソッドについては知りませんでした (素晴らしいヒント)。そのため、計算などに基づいて 2 回更新される理由を調べました。

あなたの self.breakdownChart が currentScenario オブザーバブルにアクセスしていることがわかりました。テストとしてそれを削除したところ、2 番目の更新は発生しませんでした。

それで、なぜ 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 オブザーバブルも追加し、それをチャート定義 (計算された breakdownChart) で使用して、チャートが別のオブザーバブルで更新され、まだ正しく初期化されている場合に二重更新が発生しないことをテストしました。フィドルは、二重の更新なしで chartType の更新を示しています。

于 2014-02-11T16:36:44.733 に答える
3

Knockout は、依存関係が変更されるとすぐに計算されたオブザーバブルを更新し、バインディングには 2 つの依存関係があり、それぞれが順番に更新されるため、2 つの更新を取得します。

これを解決する 1 つの方法は、バインディングの更新を遅らせる手法を使用することです。これを行う簡単な方法は、ここに示すようにDeferred Updates プラグインを使用することです: http://jsfiddle.net/mbest/8j6e5/15/

Deferred Updates を使用setTimeoutして更新を実行します。つまり、更新は非同期で行われます。特定の更新に対して同期させたい場合は、次を使用できますko.tasks.processImmediate

ko.tasks.processImmediate(function() {
    self.scenarios.push(newScenario);
    self.currentScenario(newScenario);
});            
于 2014-02-11T18:34:55.153 に答える