I need to figure out which element was removed from my Knockout observableArray. Please see my jsFiddle.
I can subscribe to the change, but it only returns value, which is the current array after the add or remove.
self.selectedDataPointOptions.subscribe(function(value) {
// how can I see which one was added or removed?
alert(value);
});
Knockout includes ko.utils.compareArrays
which you can use to compare one array to another. Here's a helper function that notifies for each added or removed item in the array:
ko.observableArray.fn.subscribeArrayChanged = function(addCallback, deleteCallback) {
var previousValue = undefined;
this.subscribe(function(_previousValue) {
previousValue = _previousValue.slice(0);
}, undefined, 'beforeChange');
this.subscribe(function(latestValue) {
var editScript = ko.utils.compareArrays(previousValue, latestValue);
for (var i = 0, j = editScript.length; i < j; i++) {
switch (editScript[i].status) {
case "retained":
break;
case "deleted":
if (deleteCallback)
deleteCallback(editScript[i].value);
break;
case "added":
if (addCallback)
addCallback(editScript[i].value);
break;
}
}
previousValue = undefined;
});
};
Here it is in action: http://jsfiddle.net/mbest/Jq3ru/
Beginning with Knockout 3.0, you can use the arrayChange
event to do this more easily. More info is here: http://blog.stevensanderson.com/2013/10/08/knockout-3-0-release-candidate-available/
The proposed solution is cool, and works, but it involves cloning the array every time there is a change, then doing a compare, which is probably O(n^2).
Here is another solution: It means including another js file... but if you want some better performance, this will provide it:
https://github.com/bobwold/betterObservableArray
This replacement for observableArray (which is basically just a clone of observable array, with some extra code) uses the knockout subscription framework, and adds "add" and "remove" subscriptions.
Sample Usage:
var presidents = ko.betterObservableArray();
presidents.subscribe(presidentAdded, this, "add");
presidents.subscribe(this.presidentRemoved, this, "remove");
...
function presidentAdded(president) {
};
function presidentRemoved (president) {
};
...
Michael Best's solution (subscribeArrayChanged) works very well for me too. But I need to use it from typescript and for this reason I wrote a little define source (d.ts), in a different source from original 'knockout.d.ts' for using it in a comfortable way in typescript source code.
custom knockoutext.d.ts file:
/// <reference path="knockout.d.ts" />
interface KnockoutObservableArray<T> extends KnockoutObservableArrayFunctions<T> {
subscribeArrayChanged(addCallback: (T) => void , deleteCallback: (T) => void );
}
Little sample code snippet:
data[0].Properties.subscribeArrayChanged(
(value: Meta.Data.Property) => {
console.log('add callback called');
},
(value: Meta.Data.Property) => {
console.log('delete callback called');
}
);