web-dev-qa-db-ja.com

新規または削除されたエントリのみの監視可能配列にサブスクライブする

はい、観測可能な配列をサブスクライブできます。

vm.myArray = ko.observableArray();
vm.myArray.subscribe(function(newVal){...});

問題は、関数に渡されるnewValが配列全体であることです。とにかく、デルタ部分のみを取得できますか? addedまたはremoved要素を言う?

74
Gelin Luo

KnockoutJS 3.0では、ko.observableArrayに arrayChangeサブスクリプションオプション があります。

var myArray = ko.observableArray(["Alpha", "Beta", "Gamma"]);

myArray.subscribe(function(changes) {

    // For this example, we'll just print out the change info
    console.log(changes);

}, null, "arrayChange");

myArray.Push("newitem!");

上記のコールバックでは、changes引数は次のような変更オブジェクトの配列になります。

[ 
   { 
      index: 3, 
      status: 'added', 
      value: 'newitem!' 
   }
]

特定の問題については、新しいアイテムまたは削除されたアイテムの通知を受け取りたい。 Knockout 3を使用して実装するには、次のようになります。

myArray.subscribe(function(changes) {

    changes.forEach(function(change) {
        if (change.status === 'added' || change.status === 'deleted') {
            console.log("Added or removed! The added/removed element is:", change.value);
        }
    });

}, null, "arrayChange");
122

他の場所でこれに関する情報を見つけることができなかったため、TypeScriptでこれを使用する方法についての返信を追加します。

ここで重要なのは、サブスクライブのTEventとしてKnockoutArrayChangeインターフェイスを使用することでした。そうしないと、他の(非汎用)サブスクライブを使用しようとし、ステータス、インデックス、および存在しない値について文句を言います。

class ZoneDefinition {
    Name: KnockoutObservable<String>;
}

class DefinitionContainer
{
    ZoneDefinitions: KnockoutObservableArray<ZoneDefinition>;
    constructor(zoneDefinitions?: ZoneDefinition[]){
        this.ZoneDefinitions = ko.observableArray(zoneDefinitions);
        // you'll get an error if you don't use the generic version of subscribe
        // and you need to use the KnockoutArrayChange<T> interface as T
        this.ZoneDefinitions.subscribe<KnockoutArrayChange<ZoneDefinition>[]>(function (changes) {
            changes.forEach(function (change) {
                if (change.status === 'added') {
                    // do something with the added value
                    // can use change.value to get the added item
                    // or change.index to get the index of where it was added
                } else if (change.status === 'deleted') {
                    // do something with the deleted value
                    // can use change.value to get the deleted item
                    // or change.index to get the index of where it was before deletion
                }
            });
        }, null, "arrayChange");
}
7
MPavlak

Push()およびremove()イベントのみを検出し、アイテムを移動しないように、これらの監視可能な配列関数の周りにラッパーを配置します。

_var trackPush = function(array) {
    var Push = array.Push;
    return function() {
        console.log(arguments[0]);
        Push.apply(this,arguments);
    }
}
var list = ko.observableArray();
list.Push = trackPush(list);
_

元のプッシュ関数はクロージャーに保存され、ラッパーでオーバーレイされます。これにより、プッシュされたアイテムが配列にプッシュされる前または後に、プッシュされたアイテムで必要な処理を実行できます。

remove()の同様のパターン。

1
Hal Noyes

同様のアプローチを使用していますが、要素自体に要素が装備されているかどうかを追跡します。

myArray.subscribe(function(array){
  $.each(array, function(id, el) {
    if (!el.instrumented) {
      el.instrumented = true;
      el.displayName = ko.computed(function(){
        var fn = $.trim(el.firstName()), ln = $.trim(el.lastName());
        if (fn || ln) {
          return fn ? (fn + (ln ? " " + ln : "")) : ln;
        } else {
          return el.email();
        }
      })
    }
  });
})

しかし、それは本当に退屈で、コード全体でパターンが繰り返されます

0
Gelin Luo