Abonnieren Sie das beobachtbare Array nur für neue oder entfernte Einträge

75

Also ja, ich kann ein beobachtbares Array abonnieren:

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

Das Problem ist newVal, dass an die Funktion das gesamte Array übergeben wird. Kann ich trotzdem nur den Delta-Teil bekommen? Sagen Sie das hinzugefügte oder entfernte Element?

Gelin Luo
quelle

Antworten:

126

Ab KnockoutJS 3.0 gibt es eine ArrayChange-Abonnementoption für ko.observableArray.

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!");

Im obigen Rückruf ist das Änderungsargument ein Array von Änderungsobjekten wie folgt:

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

Für Ihr spezifisches Problem möchten Sie über neue oder entfernte Elemente informiert werden . Um dies mit Knockout 3 zu implementieren, sieht es folgendermaßen aus:

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");
Judah Gabriel Himango
quelle
1
Wie ist der Status einer "modifizierten" Person?
beauXjames
Ich verstehe nicht, was Sie fragen, wenn Sie "modifizierte Person" sagen.
Judah Gabriel Himango
individual == Instanz von Änderungen == change ['hinzugefügt', 'gelöscht', '???', '???', ... ???]
beauXjames
2
Wenn Sie fragen, wie die Benachrichtigung lautet, wenn ein einzelnes Element geändert wurde, eines der Elemente im Array, lautet die Antwort "Keine". Sie werden nur über Umzüge und Ergänzungen informiert.
Judah Gabriel Himango
4
Aus der Dokumentation geht hervor, dass das Verschieben von Elementen auch eine hinzugefügte oder gelöschte Änderung signalisiert. myArray.reverse(); // [{ index: 0, moved: 1, status: 'deleted', value: 'Alpha' },{ index: 1, moved: 0, status: 'added', value: 'Alpha' }] Möglicherweise sollte der Status "Hinzufügen" und "Gelöscht" ohne die Eigenschaft "Verschieben" überprüft werden.
Paul
7

Da ich an anderer Stelle keine Informationen dazu finden konnte, werde ich eine Antwort hinzufügen, wie dies mit TypeScript verwendet werden kann.

Der Schlüssel hier war, die KnockoutArrayChange-Schnittstelle als TEvent zum Abonnieren zu verwenden. Wenn Sie dies nicht tun, wird versucht, das andere (nicht generische) Abonnement zu verwenden, und es wird sich über Status, Index und Wert beschweren, die nicht vorhanden sind.

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");
}
MPavlak
quelle
1

Um nur Ereignisse zu erkennen push()und remove()keine Elemente zu verschieben, habe ich diese beobachtbaren Array-Funktionen mit einem Wrapper versehen.

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);

Die ursprüngliche Push-Funktion wird in einem Verschluss gespeichert und dann mit einem Wrapper überlagert, mit dem ich mit dem Push-Element alles tun kann, was ich möchte, bevor oder nachdem es auf das Array verschoben wird.

Ähnliches Muster für remove().

Hal Noyes
quelle
0

Ich verwende einen ähnlichen, aber anderen Ansatz. Verfolgen Sie, ob ein Element im Element selbst instrumentiert wurde:

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();
        }
      })
    }
  });
})

Aber es ist wirklich langweilig und das Muster wiederholt sich in meinem Code

Gelin Luo
quelle
Um sich eine Eigenschaft zu sichern, können Sie Folgendes verwenden: if (! ('DisplayName' in el)) {}
GrantDG
-1

Keine, von denen ich weiß. Willst du wissen was ich tue? Ich benutze eine vorherige Variable, um den Wert zu halten, etwas, das genannt wirdselectedItem

vm.selectedItem = ko.observable({});
function addToArray(item) { vm.selectedItem(item); vm.myArray.push(item); }

Auf diese Weise weiß ich, wenn etwas mit meinem beobachtbaren Array passiert, welches Element hinzugefügt wurde.

vm.myArray.subscribe(function(newArray) { var addedItem = vm.selectedItem(item); ... }

Dies ist sehr ausführlich und vorausgesetzt, Ihr Array enthält viele Arten von Daten, benötigen Sie eine Art Flags, mit denen Sie wissen, was Sie mit Ihren gespeicherten Variablen tun sollen ...

vm.myArray.subscribe(function(newArray) {
  if ( wasUpdated )
    // do something with selectedItem
  else
    // do whatever you whenever your array is updated
}

Es ist wichtig zu wissen, dass Sie möglicherweise wissen, welches Element hinzugefügt wurde, wenn Sie wissen, ob es verwendet wurde pushoder unshiftnicht. Durchsuchen Sie einfach das letzte Element des Arrays oder das erste und voila.

jjperezaguinaga
quelle
Ich verwende einen anderen Ansatz: Verfolgen Sie, ob ein Element im Element selbst instrumentiert wurde. Siehe meine Antwort oben
Gelin Luo
-2

Versuchen vm.myArray().arrayChanged.subscribe(function(eventArgs))

Dies hat den Mehrwert, wenn ein Artikel hinzugefügt wird, und den entfernten Wert, wenn ein Artikel entfernt wird.

Rudy
quelle