Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit aaab4ca

Browse files
committed
feat($scope): Add the ability for a watcher to be restored
Add the function property `restore` to `scope.$watch`, `scope.$watchCollection` and `scope.$watchGroup` returning function. If the watcher was deregister, then calling the `restore` function restores the watcher in its original position. If the watcher is deregistered, then calling `restore` is a no-op.
1 parent 087b515 commit aaab4ca

File tree

2 files changed

+163
-9
lines changed

2 files changed

+163
-9
lines changed

src/ng/rootScope.js

+31-9
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,8 @@ function $RootScopeProvider() {
387387
* @param {boolean=} [objectEquality=false] Compare for object equality using {@link angular.equals} instead of
388388
* comparing for reference equality.
389389
* @returns {function()} Returns a deregistration function for this listener.
390+
* The property `restore` of the returning function is a function that allows restoring the
391+
* watcher once it was deregistered.
390392
*/
391393
$watch: function(watchExp, listener, objectEquality, prettyPrintExpression) {
392394
var get = $parse(watchExp);
@@ -419,14 +421,23 @@ function $RootScopeProvider() {
419421
array.unshift(watcher);
420422
incrementWatchersCount(this, 1);
421423

422-
return function deregisterWatch() {
424+
return extend(function deregisterWatch() {
423425
var index = binarySearch(array, watcher.id);
424426
if (index >= 0) {
425427
array.splice(index, 1);
426-
incrementWatchersCount(scope, -1);
427428
lastDirtyWatch = null;
429+
incrementWatchersCount(scope, -1);
428430
}
429-
};
431+
}, {
432+
restore: function() {
433+
var index = binarySearch(array, watcher.id);
434+
if (index < 0) {
435+
array.splice(-index - 1, 0, watcher);
436+
lastDirtyWatch = null;
437+
incrementWatchersCount(scope, 1);
438+
}
439+
}
440+
});
430441
},
431442

432443
/**
@@ -468,9 +479,13 @@ function $RootScopeProvider() {
468479
self.$evalAsync(function() {
469480
if (shouldCall) listener(newValues, newValues, self);
470481
});
471-
return function deregisterWatchGroup() {
482+
return extend(function deregisterWatchGroup() {
472483
shouldCall = false;
473-
};
484+
}, {
485+
restore: function() {
486+
shouldCall = true;
487+
}
488+
});
474489
}
475490

476491
if (watchExpressions.length === 1) {
@@ -505,11 +520,17 @@ function $RootScopeProvider() {
505520
}
506521
}
507522

508-
return function deregisterWatchGroup() {
509-
while (deregisterFns.length) {
510-
deregisterFns.shift()();
523+
return extend(function deregisterWatchGroup() {
524+
forEach(deregisterFns, function(deregisterFn) {
525+
deregisterFn();
526+
});
527+
}, {
528+
restore: function() {
529+
forEach(deregisterFns, function(deregisterFn) {
530+
deregisterFn.restore();
531+
});
511532
}
512-
};
533+
});
513534
},
514535

515536

@@ -1387,5 +1408,6 @@ function $RootScopeProvider() {
13871408
}
13881409
return -(low + 1);
13891410
}
1411+
13901412
}];
13911413
}

test/ng/rootScopeSpec.js

+132
Original file line numberDiff line numberDiff line change
@@ -604,6 +604,138 @@ describe('Scope', function() {
604604
});
605605

606606

607+
describe('watch reregistration', function() {
608+
it('should be possible to reregister a watcher', inject(function($rootScope, log) {
609+
var w1 = $rootScope.$watch(log.fn('watch1'), noop);
610+
var w2 = $rootScope.$watch(log.fn('watch2'), noop);
611+
var w3 = $rootScope.$watch(log.fn('watch3'), noop);
612+
613+
$rootScope.$digest();
614+
expect(log).toEqual(['watch1', 'watch2', 'watch3', 'watch1', 'watch2', 'watch3']);
615+
log.reset();
616+
617+
$rootScope.$digest();
618+
expect(log).toEqual(['watch1', 'watch2', 'watch3']);
619+
log.reset();
620+
621+
w1();
622+
$rootScope.$digest();
623+
expect(log).toEqual(['watch2', 'watch3']);
624+
log.reset();
625+
626+
w1.restore();
627+
$rootScope.$digest();
628+
expect(log).toEqual(['watch1', 'watch2', 'watch3']);
629+
log.reset();
630+
631+
w2();
632+
$rootScope.$digest();
633+
expect(log).toEqual(['watch1', 'watch3']);
634+
log.reset();
635+
636+
w2.restore();
637+
$rootScope.$digest();
638+
expect(log).toEqual(['watch1', 'watch2', 'watch3']);
639+
log.reset();
640+
641+
w3();
642+
$rootScope.$digest();
643+
expect(log).toEqual(['watch1', 'watch2']);
644+
log.reset();
645+
646+
w3.restore();
647+
$rootScope.$digest();
648+
expect(log).toEqual(['watch1', 'watch2', 'watch3']);
649+
log.reset();
650+
}));
651+
652+
653+
it('should not add multiple times the same watcher when calling multiple times `restore`', inject(function($rootScope, log) {
654+
var w1 = $rootScope.$watch(log.fn('watch1'), noop);
655+
var w2 = $rootScope.$watch(log.fn('watch2'), noop);
656+
var w3 = $rootScope.$watch(log.fn('watch3'), noop);
657+
658+
$rootScope.$digest();
659+
log.reset();
660+
661+
w1();
662+
$rootScope.$digest();
663+
log.reset();
664+
w1.restore();
665+
w1.restore();
666+
$rootScope.$digest();
667+
expect(log).toEqual(['watch1', 'watch2', 'watch3']);
668+
log.reset();
669+
670+
w1();
671+
$rootScope.$digest();
672+
log.reset();
673+
w1.restore();
674+
w1();
675+
w1.restore();
676+
$rootScope.$digest();
677+
expect(log).toEqual(['watch1', 'watch2', 'watch3']);
678+
log.reset();
679+
}));
680+
681+
it('should be possible to reregister a watcher from watchGroup', inject(function($rootScope, log) {
682+
var w = $rootScope.$watchGroup([log.fn('watch1'), log.fn('watch2'), log.fn('watch3')], noop);
683+
684+
$rootScope.$digest();
685+
expect(log).toEqual(['watch1', 'watch2', 'watch3', 'watch1', 'watch2', 'watch3']);
686+
log.reset();
687+
688+
$rootScope.$digest();
689+
expect(log).toEqual(['watch1', 'watch2', 'watch3']);
690+
log.reset();
691+
692+
w();
693+
$rootScope.$digest();
694+
expect(log).toEqual([]);
695+
log.reset();
696+
697+
w.restore();
698+
$rootScope.$digest();
699+
expect(log).toEqual(['watch1', 'watch2', 'watch3']);
700+
log.reset();
701+
702+
w.restore();
703+
$rootScope.$digest();
704+
expect(log).toEqual(['watch1', 'watch2', 'watch3']);
705+
log.reset();
706+
}));
707+
708+
it('should be possible to reregister a watcher from watchCollection', inject(function($rootScope, log) {
709+
$rootScope.obj = [0, 1, 2];
710+
var w = $rootScope.$watchCollection('obj', log.fn('watch!'));
711+
712+
$rootScope.$digest();
713+
expect(log).toEqual(['watch!']);
714+
log.reset();
715+
716+
$rootScope.$digest();
717+
expect(log).toEqual([]);
718+
log.reset();
719+
720+
$rootScope.obj.push(3);
721+
$rootScope.$digest();
722+
expect(log).toEqual(['watch!']);
723+
log.reset();
724+
725+
w();
726+
$rootScope.obj.push(4);
727+
$rootScope.$digest();
728+
expect(log).toEqual([]);
729+
log.reset();
730+
731+
w.restore();
732+
$rootScope.$digest();
733+
expect(log).toEqual(['watch!']);
734+
log.reset();
735+
}));
736+
});
737+
738+
607739
describe('$watchCollection', function() {
608740
var log, $rootScope, deregister;
609741

0 commit comments

Comments
 (0)