Подпишитесь на наблюдаемый массив только для новой или удаленной записи

Итак, да, я могу подписаться на наблюдаемый массив:

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

Проблема состоит в том, что newVal, переданная функции, - это весь массив. В любом случае, я могу получить только дельту? Скажите добавленный или удаленный элемент?

Ответ 1

Как и в KnockoutJS 3.0, существует опция arrayChange подписки на 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!");

В приведенном выше обратном вызове аргумент изменений будет массивом объектов изменения, например:

[ 
   { 
      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");

Ответ 2

Поскольку я не мог найти информацию об этом в другом месте, я добавлю ответ, как использовать это с помощью TypeScript.

Ключевым моментом здесь было использование интерфейса KnockoutArrayChange как TEvent для подписки. Если вы этого не сделаете, он попытается использовать другую (не общую) подписку и будет жаловаться на статус, индекс и значение, не существующее.

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

Ответ 3

Чтобы обнаруживать события 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);

Оригинальная функция push сохраняется в закрытии, затем накладывается на оболочку, которая позволяет мне делать что-либо, что я хочу, с нажатым элементом до или после, он помещается в массив.

Аналогичный шаблон для remove().

Ответ 4

Я использую подобный, но другой подход, отслеживайте, был ли элемент инструментом в самом элементе:

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

Но это действительно утомительно, и шаблон повторяется в моем коде

Ответ 5

Нет, о которых я знаю. Хочешь знать, что я делаю? Я использую предыдущую переменную для хранения значения, что называется selectedItem

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

Таким образом, когда что-то происходит с моим наблюдаемым массивом, я знаю, какой элемент был добавлен.

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

Это действительно многословно, и если ваш массив хранит много видов данных, вам нужно будет иметь какие-то флаги, которые помогут вам узнать, что делать с вашими сохраненными переменными...

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

Важно отметить, что вы могли бы знать, какой элемент был добавлен, если вы знаете, были ли использованы push или unshift. Просто просмотрите последний элемент массива или первый и вуаля.

Ответ 6

Попробуйте vm.myArray().arrayChanged.subscribe(function(eventArgs))

У этого есть добавленное значение, когда элемент добавлен, и удаленное значение, когда элемент удален.