Skip to content

Commit 0a8b316

Browse files
committed
$watch should optionally skip listener exec
- if initRun param is set to false, listener doesn't execute - the oldValue should equal newValue during the initial execution - added docs - added specs
1 parent ba554ee commit 0a8b316

File tree

2 files changed

+57
-5
lines changed

2 files changed

+57
-5
lines changed

src/Scope.js

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -165,22 +165,40 @@ function createScope(parent, providers, instanceCache) {
165165
}
166166
},
167167

168-
$watch: function(watchExp, listener, exceptionHandler) {
168+
169+
/**
170+
* Registers `listener` as a watcher of the `watchExp` and executes it (optional, see `initRun`
171+
* flag). Afterwards `listener` is executed every time the result of `watchExp` changes.
172+
*
173+
* The `listener` function will be called with two parameters `newValue` and `oldValue`.
174+
*
175+
* @param {Function|string} watchExp Expression that yields results. Can be an angular string
176+
* expression or a function.
177+
* @param {Function|string} listener Function (or angular string expression) that gets called
178+
* every time the value of the `watchExp` changes.
179+
* @param {Function} exceptionHanlder Handler that gets called when listeners throws an
180+
* exception.
181+
* @param {boolean} [initRun=true] Flag that prevents the first execution of the listener upon
182+
* registration.
183+
*/
184+
$watch: function(watchExp, listener, exceptionHandler, initRun) {
169185
var watch = expressionCompile(watchExp),
170-
last = {};
186+
last = watch.call(instance);
171187
listener = expressionCompile(listener);
172-
function watcher(){
188+
function watcher(firstRun){
173189
var value = watch.call(instance),
190+
// we have to save the value because listener can call ourselves => inf loop
174191
lastValue = last;
175-
if (last !== value) {
192+
if (firstRun || lastValue !== value) {
176193
last = value;
177194
instance.$tryEval(function(){
178195
return listener.call(instance, value, lastValue);
179196
}, exceptionHandler);
180197
}
181198
}
182199
instance.$onEval(PRIORITY_WATCH, watcher);
183-
watcher();
200+
if (isUndefined(initRun)) initRun = true;
201+
if (initRun) watcher(true);
184202
},
185203

186204
$onEval: function(priority, expr, exceptionHandler){

test/ScopeSpec.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,40 @@ describe('scope/model', function(){
9696
model.$eval();
9797
expect(count).toEqual(1);
9898
});
99+
100+
it('should run listener upon registration by default', function() {
101+
var model = createScope();
102+
var count = 0,
103+
nameNewVal = 'crazy val 1',
104+
nameOldVal = 'crazy val 2';
105+
106+
model.$watch('name', function(newVal, oldVal){
107+
count ++;
108+
nameNewVal = newVal;
109+
nameOldVal = oldVal
110+
});
111+
112+
expect(count).toBe(1);
113+
expect(nameNewVal).not.toBeDefined();
114+
expect(nameOldVal).not.toBeDefined();
115+
});
116+
117+
it('should not run listener upon registration if flag is passed in', function() {
118+
var model = createScope();
119+
var count = 0,
120+
nameNewVal = 'crazy val 1',
121+
nameOldVal = 'crazy val 2';
122+
123+
model.$watch('name', function(newVal, oldVal){
124+
count ++;
125+
nameNewVal = newVal;
126+
nameOldVal = oldVal
127+
}, undefined, false);
128+
129+
expect(count).toBe(0);
130+
expect(nameNewVal).toBe('crazy val 1');
131+
expect(nameOldVal).toBe('crazy val 2')
132+
});
99133
});
100134

101135
describe('$bind', function(){

0 commit comments

Comments
 (0)