2017-08-04 23 views
1

を変更するときに呼び出されないサブスクライブこのコードを取る:ノックアウトは、観察可能な配列

var koEvents = new ko.subscribable(); 
 

 
var viewModel = function() { 
 
    var self = this; 
 

 
    self.data = ko.observableArray([{ 
 
     valid: true 
 
    }, { 
 
     valid: true 
 
    }]); 
 

 
    self.isValid = ko.computed(function() { 
 
     var isValid = true; 
 
     ko.utils.arrayForEach(self.data(), function(item) { 
 
     console.log(item.valid); 
 
     if (!item.valid) { 
 
      isValid = false; 
 
      return; 
 
     }; 
 
     }); 
 
     return isValid; 
 
    }, this).subscribe(function(newValue) { 
 
     alert("Subscribe called!"); 
 
     koEvents.notifySubscribers(newValue, "dataChanged"); 
 
    }.bind(this)); 
 

 
    return { 
 
     data: self.data, 
 
     isValid: self.isValid, 
 
    }; 
 
} 
 

 
var vm = new viewModel(); 
 
ko.applyBindings(vm, document.getElementById("container")); 
 

 
vm.data()[0].valid = false;
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script> 
 
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
 

 
<div id="container"> 
 
    <div data-bind="text: isValid ? 'valid': 'invalid'"> 
 
    </div> 
 
</div>

私は2つの質問を持っている...

  1. をするとき、私self.isValid、呼び出されないのはなぜこれを行うvm.data()[0].valid = false;
  2. 最初にisValidがtrueで、その後falseに設定されたときにサブスクライブ(alert("Subscribe called!");)が呼び出されないのはなぜですか?これは私のコードで2回呼び出されると思います。

おかげ

答えて

2

あり、そのコードを持ついくつかの問題がありますが、あなたが求めてきたものに関連する主な問題は、観察可能な配列内のオブジェクト上の非観測可能なプロパティ(valid)を変更することがあるということです観測可能な配列は変更されず、オブジェクト内のオブジェクトのプロパティだけが変更されます。当然、通知はありません。通知が必要な場合は、validプロパティを監視する必要があります(これは、監視可能でなければならないことを意味します)。

その他の問題:

  1. ノックアウトの問題の1つは時々はあなたのための観測/ computedsをアンラップが、彼らは表現  —の一部なら、それはしないことですあなたは(()で)それをしなければならない。

    <div data-bind="text: isValid() ? 'valid': 'invalid'"></div> 
    <!-- ------------------------^^       --> 
    

    あなたのコードがisValid(ない012かどうかをテストしていました)は真実でした。それは関数参照であるため、常にそうです。

    識別子が式の一部でない場合、KOは自動アンラッピングを行いません。例えば、これは動作します

    <!-- Works --> 
    <div data-bind="visible: isValid">...</div> 
    

    これはない:

    <!-- Doesn't work --> 
    <div data-bind="visible: !isValid">...</div> 
    

    isValidが計算/観察可能である場合)。

  2. self.isValidサブスクリプションハンドルに設定していますが、計算されたものではありません。これは、チェーンを過ぎたためです。

    self.isValid = ko.computed(function() { 
        // ... 
    }, this); // <=== End the assignment here 
    self.isValid.subscribe(function(newValue) { 
        // ... 
    }.bind(this)); 
    
  3. をあなたはself = thisを使用したが、その後もcomputedthisを渡すとsubscribebindを使用している:あなたは購読その後、computedへの通話終了後に割り当てを完了する必要がある、と:-) 。これは無害ですが、無意味です。どちらか一方が必要なものです。

  4. VMコンストラクタの戻り値として別個の新しいオブジェクトを作成する必要はありません。あなたはすでにオブジェクト(newによって作成されたオブジェクト)を持っています。

これらはさまざまな変更が加えられた例です。最初のエントリにvalidプロパティは800ms後falseに設定されています:

var koEvents = new ko.subscribable(); 
 

 
var viewModel = function() { 
 
    this.data = ko.observableArray([{ 
 
     valid: ko.observable(true) 
 
    }, { 
 
     valid: ko.observable(true) 
 
    }]); 
 

 
    this.isValid = ko.computed(function() { 
 
     var isValid = true; 
 
     ko.utils.arrayForEach(this.data(), function(item) { 
 
     console.log(item.valid()); 
 
     if (!item.valid()) { 
 
      isValid = false; 
 
      return; 
 
     }; 
 
     }); 
 
     return isValid; 
 
    }, this); 
 
    this.isValid.subscribe(function(newValue) { 
 
     alert("Subscribe called!"); 
 
     koEvents.notifySubscribers(newValue, "dataChanged"); 
 
    }); 
 
} 
 

 
var vm = new viewModel(); 
 
ko.applyBindings(vm, document.getElementById("container")); 
 

 
setTimeout(function() { 
 
    vm.data()[0].valid(false); 
 
}, 800);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script> 
 
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
 

 
<div id="container"> 
 
    <div data-bind="text: isValid() ? 'valid' : 'invalid'"></div> 
 
</div>

+0

ありがとうございました! ...よく私はフィドルの代わりにスタックスニペットを使用するように言われました...だから、通常、私はフィドルを "答え"の新しいフィドルリンクをポストして更新するでしょう...しかし、私はどのようにコードを更新することができません疑問にそれをしないで? – MojoDK

+0

@MojoDK:できません。それをやむを得ない場合、最善の策は、最初の発言の下に2番目のスニペットを置くことです。「私はXの答えに何かしようとしましたが、まだ動作していません。 (そして、必要なものをカバーする答えが出たら、もう一度それを取り除くことができます。)それを実行して、すでに存在している問題(質問は移動することを目的としたものではありません)に制限することが重要です。この場合、彼らはそうだったので、それはうまくいったでしょう。喜んで助けた! –