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

Commit

Permalink
feat(scope): add $watchSet API
Browse files Browse the repository at this point in the history
Allows watching a set of expressions. If any one expression changes
then the reaction function fires.
  • Loading branch information
mhevery committed Nov 26, 2013
1 parent 533980d commit a3c31ce
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 0 deletions.
41 changes: 41 additions & 0 deletions lib/core/scope.dart
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,47 @@ class Scope implements Map {
return () => _watchers.remove(watcher);
}

/**
* A variant of [$watch] where it watches a collection of [watchExpressios]. If any
* one expression in the collection changes the [listener] is executed.
*
* * [watcherExpressions] - `List<String|(Scope scope){}>`
* * [Listener] - `(List newValues, List previousValues, Scope scope)`
*/
$watchSet(List watchExpressions, [Function listener, String watchStr]) {
if (watchExpressions.length == 0) return () => null;

var lastValues = new List(watchExpressions.length);
var currentValues = new List(watchExpressions.length);

if (watchExpressions.length == 1) {
// Special case size of one.
return $watch(watchExpressions[0], (value, oldValue, scope) {
currentValues[0] = value;
lastValues[0] = oldValue;
listener(currentValues, lastValues, scope);
});
}
var deregesterFns = [];
var changeCount = 0;
for(var i = 0, ii = watchExpressions.length; i < ii; i++) {
deregesterFns.add($watch(watchExpressions[i], (value, oldValue, __) {
currentValues[i] = value;
lastValues[i] = oldValue;
changeCount++;
}));
}
deregesterFns.add($watch((s) => changeCount, (c, o, scope) {
listener(currentValues, lastValues, scope);
}));
return () {
for(var i = 0, ii = deregesterFns.length; i < ii; i++) {
deregesterFns[i]();
}
};
}


$watchCollection(obj, listener, [String expression, bool shallow=false]) {
var oldValue;
var newValue;
Expand Down
69 changes: 69 additions & 0 deletions test/core/scope_spec.dart
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,75 @@ main() {
});


describe(r'$watchSet', () {
var scope;
beforeEach(inject((Scope s) => scope = s));

it('should skip empty sets', () {
expect(scope.$watchSet([], null)()).toBe(null);
});

it('should treat set of 1 as direct watch', () {
var lastValues = ['foo'];
var log = '';
var clean = scope.$watchSet(['a'], (values, oldValues, s) {
log += values.join(',') + ';';
expect(s).toBe(scope);
expect(oldValues).toEqual(lastValues);
lastValues = new List.from(values);
});

scope.a = 'foo';
scope.$digest();
expect(log).toEqual('foo;');

scope.$digest();
expect(log).toEqual('foo;');

scope.a = 'bar';
scope.$digest();
expect(log).toEqual('foo;bar;');

clean();
scope.a = 'xxx';
scope.$digest();
expect(log).toEqual('foo;bar;');
});

it('should detect a change to any one in a set', () {
var lastValues = ['foo', 'bar'];
var log = '';
var clean = scope.$watchSet(['a', 'b'], (values, oldValues, s) {
log += values.join(',') + ';';
expect(oldValues).toEqual(lastValues);
lastValues = new List.from(values);
});

scope.a = 'foo';
scope.b = 'bar';
scope.$digest();
expect(log).toEqual('foo,bar;');

scope.$digest();
expect(log).toEqual('foo,bar;');

scope.a = 'a';
scope.$digest();
expect(log).toEqual('foo,bar;a,bar;');

scope.a = 'A';
scope.b = 'B';
scope.$digest();
expect(log).toEqual('foo,bar;a,bar;A,B;');

clean();
scope.a = 'xxx';
scope.$digest();
expect(log).toEqual('foo,bar;a,bar;A,B;');
});
});


describe(r'$destroy', () {
var first = null, middle = null, last = null, log = null;

Expand Down

0 comments on commit a3c31ce

Please sign in to comment.