2012-04-15 4 views
54

現在、DOM要素のjQueryデータを使用して状態を保存しています。カスタムノックアウトバインディングのためにinitとupdateの間に状態を保存するための好ましい方法は何ですか?

ko.bindingHandlers.customValue = { 

    init: function init(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) { 
     var state = { isEditing: false };   
     $(element).focus(function focus() { 
      state.isEditing = true; 
     }).blur(function blur() { 
      state.isEditing = false;    
     }).data("customBinding", state); 

    }, 

    update: function update(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) { 
     // ignore if updating 
     if (!$(element).data("customBinding").isEditing) { 
      // handle update if they are not updating         
     } 
    } 

};​ 

domを必要としないバインドごとに状態を保存する場所がありますか?バインディングの各インスタンスの状態を格納するためにbindingContextを使用できますか?

+0

良い質問です。私はあなたのソリューションは非常に良いと思います。コードのその他の特性を考慮して、さらに強化されているかもしれません。 – Oybek

+1

私はそれをもう一度。すべてのバインドは特定のDOMノードに関連しているため、そのDOMノードにバインドされた関連データを格納することは有効な方法です。 – Niko

答えて

46

bindingContextが可能ですが、最初にバインディングがトリガーされたときにはinitからupdateにデータを渡すためにのみ可能です。次回はupdateが発火しても、それはもはや存在しません。

状態のこのタイプの保存する場所のための2つの選択肢は本当にあります:あなたが述べたように、要素に

1-。 jQueryの$.dataを使用するか、KOにはAPIを含めてko.utils.domData.get(element, key)ko.utils.domData.set(element, key, value)のようにすることができます。

2適切な場合は、このタイプの情報をビューモデルに入れます。 isEditingを示すフラグは、ビューモデルでは必ずしも適切ではありません。私は個人的に観察できるようにオフサブ観測として「メタデータ」のこのタイプを置くのが好き:

var name = ko.observable("Bob"); 
name.isEditing = ko.observable(false); 

あなたがnamename.isEditingに対して結合することができるだろう。あなたは、サブ観察可能な観察可能なその親(nameIsEditingが不要に縛ら新しいトップレベルのプロパティ

  • を続けて導入されていないよう

    • は、ビューモデルはかなりきれいに保つ:

      この

      は、いくつかの利点を持っていますなど)
    • ko.toJSONのようなものでJSONに変換すると、isEditingサブオブザーバブルは、親がアンラップされたときに削除されます。したがって、不要な値をサーバーに返送することはありません。
    • この場合、ビューモデル内の他の計算やUIの複数の要素に対してバインドすることができるという利点もあります。
  • +0

    私は何か不足していますが、isEditingをobservableとして宣言し、バインディングの更新機能でこのobservableの値をチェックした場合は、dependableObservableを作成し、isEditingの値をtrueに変更するとinit関数は、bounded observableの値を変更する直前に、isEditingはカスタムバインディングの更新関数を強制的に呼び出す変更をトリガーします。 isEditingを単純なJS変数として宣言すると、ソリューションは完全に機能します。 – Samuel

    +0

    なぜdomDataは$ .dataより優れていますか?それはコの一部か他の何らかの理由でですか? –

    7

    要素にデータを添付することは問題ありません。Knockoutは、このメソッドを内部的にコントロールフローバインディング(if、withなど)に使用します。

    もう1つの方法は、init関数を使用し、計算された観測値を使用して更新を処理することです。私はrepeatバインディングでこのメソッドを使用します。ここで重要な部品です:

    ko.bindingHandlers['repeat'] = { 
        'init': function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) { 
         ... 
         // set up persistent data 
         var lastRepeatCount = 0; 
         ... 
         ko.computed(function() { 
          var repeatCount = ko.utils.unwrapObservable(valueAccessor()); 
          ... 
          // Remove nodes from end if array is shorter 
          for (; lastRepeatCount > repeatCount; lastRepeatCount--) { 
           ... 
          } 
          ... 
          // Add nodes to end if array is longer (also initially populates nodes) 
          for (; lastRepeatCount < repeatCount; lastRepeatCount++) { 
           ... 
          } 
         }, null, {'disposeWhenNodeIsRemoved': placeholder}); 
         ... 
        } 
    }; 
    
    1

    私は、多くの場合、このパターンを使用します。

    define(['knockout'], function(ko) { 
        var interInstanceVariable = null; 
    
        function Tree(element) { 
        var privateInstanceVariable = null; 
    
        function privateInstanceMethod() {} 
    
        this.publicInstanceMethod = function() {} 
        } 
    
    
        ko.bindingHandlers.cannDendrogram = { 
        init: function(element, valueAccessor) { 
         $(element).data('tree', new Tree(element)); 
        }, 
        update: function(element, valueAccessor) { 
         var tree = $(element).data('tree'); 
         tree.publicMethod(); 
        } 
        }; 
    }); 
    
    1

    私はこの質問が古い実現が、私はアプローチを探して、ここでつまずいたので、私はもっと上のチップしようと思いました現代コメソッド。

    単にbindingContext。$ dataにプロパティを追加するだけで済みます。私は潜在的な衝突を避けるために迷惑な変数名 "___IsEditing"を選んだが、あなたはその考えを得る...

    ko.bindingHandlers.customValue = { 
    
    init: function init(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) { 
        bindingContext.$data.___IsEditing = false;   
        $(element).focus(function focus() { 
         bindingContext.$data.___IsEditing = true; 
        }).blur(function blur() { 
         bindingContext.$data.___IsEditing = false;    
        }).data("customBinding", state); 
    
    }, 
    
    update: function update(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) { 
        // ignore if updating 
        if (bindingContext.$data.___IsEditing) { 
         // handle update if they are not updating         
        } 
    } 
    

    };

    -2

    私は関数内の共通データを定義することによって、初期化および更新のための共通の範囲を作成する関数を使用。

    関連する問題