1 ko.observableArray = function (initialValues) {
2 initialValues = initialValues || [];
4 if (typeof initialValues != 'object' || !('length' in initialValues))
5 throw new Error("The argument passed when initializing an observable array must be an array, or null, or undefined.");
7 var result = ko.observable(initialValues);
8 ko.utils.setPrototypeOfOrExtend(result, ko.observableArray['fn']);
9 return result.extend({'trackArrayChanges':true});
12 ko.observableArray['fn'] = {
13 'remove': function (valueOrPredicate) {
14 var underlyingArray = this.peek();
15 var removedValues = [];
16 var predicate = typeof valueOrPredicate == "function" && !ko.isObservable(valueOrPredicate) ? valueOrPredicate : function (value) { return value === valueOrPredicate; };
17 for (var i = 0; i < underlyingArray.length; i++) {
18 var value = underlyingArray[i];
19 if (predicate(value)) {
20 if (removedValues.length === 0) {
21 this.valueWillMutate();
23 removedValues.push(value);
24 underlyingArray.splice(i, 1);
28 if (removedValues.length) {
29 this.valueHasMutated();
34 'removeAll': function (arrayOfValues) {
35 // If you passed zero args, we remove everything
36 if (arrayOfValues === undefined) {
37 var underlyingArray = this.peek();
38 var allValues = underlyingArray.slice(0);
39 this.valueWillMutate();
40 underlyingArray.splice(0, underlyingArray.length);
41 this.valueHasMutated();
44 // If you passed an arg, we interpret it as an array of entries to remove
47 return this['remove'](function (value) {
48 return ko.utils.arrayIndexOf(arrayOfValues, value) >= 0;
52 'destroy': function (valueOrPredicate) {
53 var underlyingArray = this.peek();
54 var predicate = typeof valueOrPredicate == "function" && !ko.isObservable(valueOrPredicate) ? valueOrPredicate : function (value) { return value === valueOrPredicate; };
55 this.valueWillMutate();
56 for (var i = underlyingArray.length - 1; i >= 0; i--) {
57 var value = underlyingArray[i];
59 underlyingArray[i]["_destroy"] = true;
61 this.valueHasMutated();
64 'destroyAll': function (arrayOfValues) {
65 // If you passed zero args, we destroy everything
66 if (arrayOfValues === undefined)
67 return this['destroy'](function() { return true });
69 // If you passed an arg, we interpret it as an array of entries to destroy
72 return this['destroy'](function (value) {
73 return ko.utils.arrayIndexOf(arrayOfValues, value) >= 0;
77 'indexOf': function (item) {
78 var underlyingArray = this();
79 return ko.utils.arrayIndexOf(underlyingArray, item);
82 'replace': function(oldItem, newItem) {
83 var index = this['indexOf'](oldItem);
85 this.valueWillMutate();
86 this.peek()[index] = newItem;
87 this.valueHasMutated();
92 // Note that for browsers that don't support proto assignment, the
93 // inheritance chain is created manually in the ko.observableArray constructor
94 if (ko.utils.canSetPrototype) {
95 ko.utils.setPrototypeOf(ko.observableArray['fn'], ko.observable['fn']);
98 // Populate ko.observableArray.fn with read/write functions from native arrays
99 // Important: Do not add any additional functions here that may reasonably be used to *read* data from the array
100 // because we'll eval them without causing subscriptions, so ko.computed output could end up getting stale
101 ko.utils.arrayForEach(["pop", "push", "reverse", "shift", "sort", "splice", "unshift"], function (methodName) {
102 ko.observableArray['fn'][methodName] = function () {
103 // Use "peek" to avoid creating a subscription in any computed that we're executing in the context of
104 // (for consistency with mutating regular observables)
105 var underlyingArray = this.peek();
106 this.valueWillMutate();
107 this.cacheDiffForKnownOperation(underlyingArray, methodName, arguments);
108 var methodCallResult = underlyingArray[methodName].apply(underlyingArray, arguments);
109 this.valueHasMutated();
110 // The native sort and reverse methods return a reference to the array, but it makes more sense to return the observable array instead.
111 return methodCallResult === underlyingArray ? this : methodCallResult;
115 // Populate ko.observableArray.fn with read-only functions from native arrays
116 ko.utils.arrayForEach(["slice"], function (methodName) {
117 ko.observableArray['fn'][methodName] = function () {
118 var underlyingArray = this();
119 return underlyingArray[methodName].apply(underlyingArray, arguments);
123 ko.exportSymbol('observableArray', ko.observableArray);