2012-04-24 8 views
6

サービスから戻ってくるアイテムの配列があります。私はすべてのItemインスタンスに対して計算された観測値を定義しようとしているので、私の本能はプロトタイプに置くように指示します。計算された観察用KnockoutJSで実行可能なプロトタイプのオブザーバブルが計算されていますか?

1例:システムは、ポイントを算出するが、ユーザは、計算された値を上書きすることを選択することができます。ユーザーがオーバーライドを削除した場合に備えて、計算された値を使用可能にする必要があります。また、ユーザーが割り当てたポイントと計算されたポイントを合算して合計を集計する必要があります。

私は次の操作を実行するためにマッピングを使用しています:

var itemsViewModel; 
var items = [ 
    { 'PointsCalculated' : 5.1 }, 
    { 'PointsCalculated' : 2.37, 'PointsFromUser' : 3 } 
]; 

var mapping = { 
    'Items' : { 
     create : function(options) { 
      return new Item(options.data); 
     } 
    } 
}; 

var Item = function(data) { 
    var item = this; 
    ko.mapping.fromJS(data, mapping, item); 
}; 

Item.prototype.Points = function() { 
    var item = this; 
    return ko.computed(function() { 
     // PointsFromUser may be 0, so only ignore it if the value is undefined/null 
     return (item.PointsFromUser != null) ? item.PointsFromUser : item.PointsCalculated; 
    }); 
}; 

ko.mapping.fromJS(items, mapping, itemsViewModel); 

それが今で動作する方法を、私は計算し、観察を返すように無名関数を呼び出す必要があります。これは、各バインディングに対して計算されたオブザーバブルの新しいインスタンスを作成するように見えます。これは、プロトタイプに置くことのほとんどの点を打ち消します。そして、私が観察可能なものにアクセスするたびに、使用する括弧の数を解読しなければならないのはちょっと面倒です。

でもやや壊れやすいです。私はコード内でポイント()にアクセスしようとすると、それがDOMWindowに、代わりにアイテムのポイント()のコンテキストに変化するので、私は

var points = 0; 
var p = item.Points; 
if (p && typeof p === 'function') { 
    points += p(); 
} 

を行うことはできません。

私はマッピングで()を作成中に計算を置けば、私はコンテキストをキャプチャすることができますが、その後、各オブジェクトインスタンスのメソッドのコピーがありますが。

私はマイケル・ベストのGoogleグループのポスト(http://groups.google.com/group/knockoutjs/browse_thread/thread/8de9013fb7635b13)を見つけました。このプロトタイプは、 "有効化"された新しい計算された観測値を返します。私は何が "活性化"(多分Objs?)と呼んでいるのか分かりませんでしたが、オブジェクトごとに一度はそれが起こっていると推測しています。この時点で

は、私は、公開ドキュメントで利用可能何を過ぎだと考えているが、私はまだソースから何が起こっているのか解読まで働いています。

答えて

7

あなたはJavaScriptクラスの各インスタンスにko.computed関数のインスタンスを持たせたくないと言いますが、実際にはkoの機能がどのように構築されているのかは実際には分かりません。 ko.computedまたはko.observableを使用すると、通常はクラスインスタンス間で共有されたくない内部のプライベート変数への特定のメモリポインタが作成されます(まれにありますが)。

私はこのような何かを:それから(あなたのMyInheritedClassの各インスタンスにインスタンス機能する必要があります)計算された観測のために私はそうのようなextenderでそれらを宣言

var Base = function(){ 
    var extenders = []; 

    this.extend = function(extender){ 
     extenders.push(extender); 
    }; 

    this.init = function(){ 
     var self = this; // capture the class that inherits off of the 'Base' class 

     ko.utils.arrayForEach(extenders, function(extender){ 

      // call each extender with the correct context to ensure all 
      // inheriting classes have the same functionality added by the extender 
      extender.call(self); 
     }); 
    }; 
}; 

var MyInheritedClass = function(){ 
    // whatever functionality you need 

    this.init(); // make sure this gets called 
}; 

// add the custom base class 
MyInheritedClass.prototype = new Base(); 

MyInheritedClass.prototype.extend(function(){ 

    // custom functionality that i want for each class 
    this.something = ko.computed(function() { 
     return 'test'; 
    }); 
}); 

あなたの例とは、簡単に行うことができ、上記で定義Baseクラスを考える:

var Item = function(data) { 
    var item = this; 

    ko.mapping.fromJS(data, mapping, item); 

    this.init(); // make sure this gets called 
}; 
Item.prototype = new Base(); 

Item.prototype.extend(function() { 
    var self = this; 

    this.Points = ko.computed(function() { 

     // PointsFromUser may be 0, so only ignore it if the value is undefined/null 
     return (self.PointsFromUser != null) ? 
       self.PointsFromUser : self.PointsCalculated; 
    }); 
}; 

その後、あなたItemクラスのすべてのインスタンスがPoints性質を持つことになり、それが正しくインスタンスごとko.computedロジックを処理します。

+0

ありがとうございました。私は.extend()の目的がちょうどクリックされたと思う。これは私のスコープ/ダブル関数呼び出しの問題をうまく解決し、Knockoutが実際の計算されたオブザーバブルをプロトタイプに残さないようにあなたの言葉を取り上げる。 –

+0

eric、より糖度の高いバージョンを提供できますか?既にプロトタイプのチェーン設定を行っているchildClass = BaseClass.extend(function(){/*...*/})のようなもの?各クラスインスタンスのために手動で行うのはちょっと変です... – fbuchinger

+0

基本的には、継承されたコンストラクターに「拡張」静的関数を置くことができない理由はありません。 ' SubClass.extend = function(エクステンダー){SubClass.prototype.extend(エクステンダー); }; ' – ericb

0
Item.prototype.Points = function() { 
var item = this; 
return ko.computed(function() { 
    // PointsFromUser may be 0, so only ignore it if the value is undefined/null 
    return (item.PointsFromUser != null) ? item.PointsFromUser : item.PointsCalculated; 
}); 

}

0
Item.prototype.extend(function() { 
var scope = this 
this.Points = ko.computed(function() { 
    return (this.PointsFromUser != null) ? 
      this.PointsFromUser : this.PointsCalculated; 
}, scope); 
}; 
関連する問題