只订阅可观察数组以获取新的或已删除的条目

时间:2021-03-27 08:13:05

So yes I can subscribe to an observable array:

是的,我可以订阅一个可观察的数组:

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

The problem is the newVal passed to the function is the entire array. Is there anyway I can get only the delta part? Say the added or removed element?

问题是传递给函数的newVal是整个数组。我可以只得到delta部分吗?添加或删除元素?

6 个解决方案

#1


112  

As of KnockoutJS 3.0, there's an arrayChange subscription option on ko.observableArray.

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

In the above callback, the changes argument will be an array of change objects like this:

在上面的回调中,changes参数将是如下所示的更改对象数组:

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

For your specific problem, you want to be notified of new or removed items. To implement that using Knockout 3, it'd look like this:

对于您的特定问题,您希望被通知新的或删除的项目。要使用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


7  

Since I couldn't find any info on this elsewhere, I'll add a reply for how to use this with TypeScript.

由于我在其他地方找不到关于这个的任何信息,我将添加一个如何使用这个与打字稿。

The key here was to use the KnockoutArrayChange interface as TEvent for subscribe. If you don't do that, it'll try to use the other (non-generic) subscribe and will complain about status, index, and value not existing.

这里的关键是使用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


1  

In order to only detect push() and remove() events, and not moving items, I put a wrapper around these observable array functions.

为了只检测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);

The original push function is stored in a closure, then is overlayed with a wrapper that allows me do do anything I want with the pushed item before, or after, it is pushed onto the array.

原始的push函数存储在一个闭包中,然后与一个包装器重叠,该包装器允许我在推入项之前或之后对其进行任何操作。

Similar pattern for remove().

删除()类似的模式。

#4


0  

I am using a similar but different approach, keep track whether an element has been instrumented in the element itself:

我正在使用一种类似但不同的方法,跟踪是否在元素本身中检测了一个元素:

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

But it is really tedious and the pattern repeated across my code

但这真的很乏味,而且模式在我的代码中重复出现

#5


-1  

None that I know of. Wanna know what I do? I use a previous variable to hold the value, something called selectedItem

据我所知没有。想知道我做什么吗?我使用一个先前的变量来保存值,叫做selectedItem

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

So that way, when something happens to my observable array, I know which item was added.

这样,当我的可观察数组发生变化时,我就知道添加了哪个项。

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

This is really verbose, and assuming your array holds many kinds of data, you would need to have some sort of flags that helps you know what to do with your saved variables...

这非常冗长,假设您的数组包含许多类型的数据,那么您将需要一些标志来帮助您知道如何处理保存的变量……

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

An important thing to notice is that you might know which item was added if you know whether push or unshift was used. Just browse the last item of the array or the first one and voila.

需要注意的一件重要的事情是,如果知道使用了push还是unshift,您可能知道添加了哪些项。只需浏览数组的最后一项或第一个和voila。

#6


-1  

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

尝试vm.myArray().arrayChanged.subscribe(函数(eventArgs))

That has the added value when an item is added, and the removed value when an item is removed.

当添加一个项时,它具有附加的值,并且移除项时移除的值。

#1


112  

As of KnockoutJS 3.0, there's an arrayChange subscription option on ko.observableArray.

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

In the above callback, the changes argument will be an array of change objects like this:

在上面的回调中,changes参数将是如下所示的更改对象数组:

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

For your specific problem, you want to be notified of new or removed items. To implement that using Knockout 3, it'd look like this:

对于您的特定问题,您希望被通知新的或删除的项目。要使用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


7  

Since I couldn't find any info on this elsewhere, I'll add a reply for how to use this with TypeScript.

由于我在其他地方找不到关于这个的任何信息,我将添加一个如何使用这个与打字稿。

The key here was to use the KnockoutArrayChange interface as TEvent for subscribe. If you don't do that, it'll try to use the other (non-generic) subscribe and will complain about status, index, and value not existing.

这里的关键是使用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


1  

In order to only detect push() and remove() events, and not moving items, I put a wrapper around these observable array functions.

为了只检测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);

The original push function is stored in a closure, then is overlayed with a wrapper that allows me do do anything I want with the pushed item before, or after, it is pushed onto the array.

原始的push函数存储在一个闭包中,然后与一个包装器重叠,该包装器允许我在推入项之前或之后对其进行任何操作。

Similar pattern for remove().

删除()类似的模式。

#4


0  

I am using a similar but different approach, keep track whether an element has been instrumented in the element itself:

我正在使用一种类似但不同的方法,跟踪是否在元素本身中检测了一个元素:

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

But it is really tedious and the pattern repeated across my code

但这真的很乏味,而且模式在我的代码中重复出现

#5


-1  

None that I know of. Wanna know what I do? I use a previous variable to hold the value, something called selectedItem

据我所知没有。想知道我做什么吗?我使用一个先前的变量来保存值,叫做selectedItem

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

So that way, when something happens to my observable array, I know which item was added.

这样,当我的可观察数组发生变化时,我就知道添加了哪个项。

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

This is really verbose, and assuming your array holds many kinds of data, you would need to have some sort of flags that helps you know what to do with your saved variables...

这非常冗长,假设您的数组包含许多类型的数据,那么您将需要一些标志来帮助您知道如何处理保存的变量……

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

An important thing to notice is that you might know which item was added if you know whether push or unshift was used. Just browse the last item of the array or the first one and voila.

需要注意的一件重要的事情是,如果知道使用了push还是unshift,您可能知道添加了哪些项。只需浏览数组的最后一项或第一个和voila。

#6


-1  

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

尝试vm.myArray().arrayChanged.subscribe(函数(eventArgs))

That has the added value when an item is added, and the removed value when an item is removed.

当添加一个项时,它具有附加的值,并且移除项时移除的值。