diff options
Diffstat (limited to 'src/ng/rootScope.js')
| -rw-r--r-- | src/ng/rootScope.js | 51 |
1 files changed, 43 insertions, 8 deletions
diff --git a/src/ng/rootScope.js b/src/ng/rootScope.js index 2bb965bb..ce0f8ad5 100644 --- a/src/ng/rootScope.js +++ b/src/ng/rootScope.js @@ -398,30 +398,40 @@ function $RootScopeProvider(){ * {@link ng.$rootScope.Scope#$digest $digest} cycle. Any shallow change within the * collection will trigger a call to the `listener`. * - * @param {function(newCollection, oldCollection, scope)} listener a callback function that is - * fired with both the `newCollection` and `oldCollection` as parameters. - * The `newCollection` object is the newly modified data obtained from the `obj` expression - * and the `oldCollection` object is a copy of the former collection data. - * The `scope` refers to the current scope. + * @param {function(newCollection, oldCollection, scope)} listener a callback function called + * when a change is detected. + * - The `newCollection` object is the newly modified data obtained from the `obj` expression + * - The `oldCollection` object is a copy of the former collection data. + * Due to performance considerations, the`oldCollection` value is computed only if the + * `listener` function declares two or more arguments. + * - The `scope` argument refers to the current scope. * * @returns {function()} Returns a de-registration function for this listener. When the * de-registration function is executed, the internal watch operation is terminated. */ $watchCollection: function(obj, listener) { var self = this; - var oldValue; + // the current value, updated on each dirty-check run var newValue; + // a shallow copy of the newValue from the last dirty-check run, + // updated to match newValue during dirty-check run + var oldValue; + // a shallow copy of the newValue from when the last change happened + var veryOldValue; + // only track veryOldValue if the listener is asking for it + var trackVeryOldValue = (listener.length > 1); var changeDetected = 0; var objGetter = $parse(obj); var internalArray = []; var internalObject = {}; + var initRun = true; var oldLength = 0; function $watchCollectionWatch() { newValue = objGetter(self); var newLength, key; - if (!isObject(newValue)) { + if (!isObject(newValue)) { // if primitive if (oldValue !== newValue) { oldValue = newValue; changeDetected++; @@ -487,7 +497,32 @@ function $RootScopeProvider(){ } function $watchCollectionAction() { - listener(newValue, oldValue, self); + if (initRun) { + initRun = false; + listener(newValue, newValue, self); + } else { + listener(newValue, veryOldValue, self); + } + + // make a copy for the next time a collection is changed + if (trackVeryOldValue) { + if (!isObject(newValue)) { + //primitive + veryOldValue = newValue; + } else if (isArrayLike(newValue)) { + veryOldValue = new Array(newValue.length); + for (var i = 0; i < newValue.length; i++) { + veryOldValue[i] = newValue[i]; + } + } else { // if object + veryOldValue = {}; + for (var key in newValue) { + if (hasOwnProperty.call(newValue, key)) { + veryOldValue[key] = newValue[key]; + } + } + } + } } return this.$watch($watchCollectionWatch, $watchCollectionAction); |
