diff --git a/src/ng/rootScope.js b/src/ng/rootScope.js index df8ddcf6d4cc..d6064862a2eb 100644 --- a/src/ng/rootScope.js +++ b/src/ng/rootScope.js @@ -353,11 +353,13 @@ function $RootScopeProvider() { * - `newVal` contains the current value of the `watchExpression` * - `oldVal` contains the previous value of the `watchExpression` * - `scope` refers to the current scope - * @param {boolean=} objectEquality Compare for object equality using {@link angular.equals} instead of - * comparing for reference equality. + * @param {boolean=|function()} objectEquality Compare for object equality using {@link angular.equals} instead of + * comparing for reference equality. If a function is passed, it will be used as a replacement for {@link angular.equals}. + * @param {function()} copier Replacement function for {@link angular.copy} to save value into oldVal for next + change event. * @returns {function()} Returns a deregistration function for this listener. */ - $watch: function(watchExp, listener, objectEquality) { + $watch: function(watchExp, listener, objectEquality, copier) { var get = $parse(watchExp); if (get.$$watchDelegate) { @@ -370,7 +372,9 @@ function $RootScopeProvider() { last: initWatchVal, get: get, exp: watchExp, - eq: !!objectEquality + eq: !!objectEquality, + equals: isFunction(objectEquality) ? objectEquality : equals, + copy: isFunction(copier) ? copier : copy }; lastDirtyWatch = null; @@ -763,12 +767,12 @@ function $RootScopeProvider() { if (watch) { if ((value = watch.get(current)) !== (last = watch.last) && !(watch.eq - ? equals(value, last) + ? watch.equals(value, last) : (typeof value === 'number' && typeof last === 'number' && isNaN(value) && isNaN(last)))) { dirty = true; lastDirtyWatch = watch; - watch.last = watch.eq ? copy(value, null) : value; + watch.last = watch.eq ? watch.copy(value, null) : value; watch.fn(value, ((last === initWatchVal) ? value : last), current); if (ttl < 5) { logIdx = 4 - ttl; diff --git a/test/ng/rootScopeSpec.js b/test/ng/rootScopeSpec.js index ec9fc80786d0..6bfb6121eaa3 100644 --- a/test/ng/rootScopeSpec.js +++ b/test/ng/rootScopeSpec.js @@ -458,6 +458,61 @@ describe('Scope', function() { expect(log).toEqual([]); })); + it('should use custom equals and copy functions', + inject(function($rootScope) { + var log = []; + var oldLog = []; + + function logger(newVal, oldVal) { + log.push(newVal); + oldLog.push(oldVal); + } + + var watched = "ABC"; + var watchedFn = function() { + return watched; + }; + + // Comparator returns true if string starts with same character + var comparator = function(newVal, oldVal) { + if (oldVal === newVal) return true; + if (oldVal === undefined || newVal === undefined) return false; + if (newVal.length === oldVal.length === 0) return true; + if (newVal.length > 0 && oldVal.length > 0 && oldVal[0] === newVal[0]) { + return true; + } + return false; + }; + + // Copier add " copy" to value + var copier = function(value) { + if (value !== undefined) { + return value + " copy"; + } + return undefined; + }; + + $rootScope.$watch(watchedFn, logger, comparator, copier); + + $rootScope.$digest(); + expect(log).toEqual(['ABC']); + expect(oldLog).toEqual(['ABC']); + log = []; + oldLog = []; + + watched = "DEF"; + $rootScope.$digest(); + expect(log).toEqual(['DEF']); + expect(oldLog).toEqual(['ABC copy']); + log = []; + oldLog = []; + + watched = "DZZ"; + $rootScope.$digest(); + expect(log).toEqual([]); + expect(oldLog).toEqual([]); + })); + describe('$watch deregistration', function() {