Skip to content
This repository was archived by the owner on Feb 22, 2018. It is now read-only.

Commit a3c31ce

Browse files
committed
feat(scope): add $watchSet API
Allows watching a set of expressions. If any one expression changes then the reaction function fires.
1 parent 533980d commit a3c31ce

File tree

2 files changed

+110
-0
lines changed

2 files changed

+110
-0
lines changed

lib/core/scope.dart

+41
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,47 @@ class Scope implements Map {
185185
return () => _watchers.remove(watcher);
186186
}
187187

188+
/**
189+
* A variant of [$watch] where it watches a collection of [watchExpressios]. If any
190+
* one expression in the collection changes the [listener] is executed.
191+
*
192+
* * [watcherExpressions] - `List<String|(Scope scope){}>`
193+
* * [Listener] - `(List newValues, List previousValues, Scope scope)`
194+
*/
195+
$watchSet(List watchExpressions, [Function listener, String watchStr]) {
196+
if (watchExpressions.length == 0) return () => null;
197+
198+
var lastValues = new List(watchExpressions.length);
199+
var currentValues = new List(watchExpressions.length);
200+
201+
if (watchExpressions.length == 1) {
202+
// Special case size of one.
203+
return $watch(watchExpressions[0], (value, oldValue, scope) {
204+
currentValues[0] = value;
205+
lastValues[0] = oldValue;
206+
listener(currentValues, lastValues, scope);
207+
});
208+
}
209+
var deregesterFns = [];
210+
var changeCount = 0;
211+
for(var i = 0, ii = watchExpressions.length; i < ii; i++) {
212+
deregesterFns.add($watch(watchExpressions[i], (value, oldValue, __) {
213+
currentValues[i] = value;
214+
lastValues[i] = oldValue;
215+
changeCount++;
216+
}));
217+
}
218+
deregesterFns.add($watch((s) => changeCount, (c, o, scope) {
219+
listener(currentValues, lastValues, scope);
220+
}));
221+
return () {
222+
for(var i = 0, ii = deregesterFns.length; i < ii; i++) {
223+
deregesterFns[i]();
224+
}
225+
};
226+
}
227+
228+
188229
$watchCollection(obj, listener, [String expression, bool shallow=false]) {
189230
var oldValue;
190231
var newValue;

test/core/scope_spec.dart

+69
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,75 @@ main() {
404404
});
405405

406406

407+
describe(r'$watchSet', () {
408+
var scope;
409+
beforeEach(inject((Scope s) => scope = s));
410+
411+
it('should skip empty sets', () {
412+
expect(scope.$watchSet([], null)()).toBe(null);
413+
});
414+
415+
it('should treat set of 1 as direct watch', () {
416+
var lastValues = ['foo'];
417+
var log = '';
418+
var clean = scope.$watchSet(['a'], (values, oldValues, s) {
419+
log += values.join(',') + ';';
420+
expect(s).toBe(scope);
421+
expect(oldValues).toEqual(lastValues);
422+
lastValues = new List.from(values);
423+
});
424+
425+
scope.a = 'foo';
426+
scope.$digest();
427+
expect(log).toEqual('foo;');
428+
429+
scope.$digest();
430+
expect(log).toEqual('foo;');
431+
432+
scope.a = 'bar';
433+
scope.$digest();
434+
expect(log).toEqual('foo;bar;');
435+
436+
clean();
437+
scope.a = 'xxx';
438+
scope.$digest();
439+
expect(log).toEqual('foo;bar;');
440+
});
441+
442+
it('should detect a change to any one in a set', () {
443+
var lastValues = ['foo', 'bar'];
444+
var log = '';
445+
var clean = scope.$watchSet(['a', 'b'], (values, oldValues, s) {
446+
log += values.join(',') + ';';
447+
expect(oldValues).toEqual(lastValues);
448+
lastValues = new List.from(values);
449+
});
450+
451+
scope.a = 'foo';
452+
scope.b = 'bar';
453+
scope.$digest();
454+
expect(log).toEqual('foo,bar;');
455+
456+
scope.$digest();
457+
expect(log).toEqual('foo,bar;');
458+
459+
scope.a = 'a';
460+
scope.$digest();
461+
expect(log).toEqual('foo,bar;a,bar;');
462+
463+
scope.a = 'A';
464+
scope.b = 'B';
465+
scope.$digest();
466+
expect(log).toEqual('foo,bar;a,bar;A,B;');
467+
468+
clean();
469+
scope.a = 'xxx';
470+
scope.$digest();
471+
expect(log).toEqual('foo,bar;a,bar;A,B;');
472+
});
473+
});
474+
475+
407476
describe(r'$destroy', () {
408477
var first = null, middle = null, last = null, log = null;
409478

0 commit comments

Comments
 (0)