Skip to content

Commit c90a711

Browse files
committed
feat(ChangeDetector): Add support for chained properties
1 parent 63494a7 commit c90a711

File tree

4 files changed

+70
-28
lines changed

4 files changed

+70
-28
lines changed

modules/change_detection/src/record.js

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -44,19 +44,19 @@ export class Record {
4444
@FIELD('final watchGroup:WatchGroup')
4545
@FIELD('final protoRecord:ProtoRecord')
4646
/// order list of all records. Including head/tail markers
47-
@FIELD('_next:Record')
48-
@FIELD('_prev:Record')
47+
@FIELD('next:Record')
48+
@FIELD('prev:Record')
4949
/// next record to dirty check
50-
@FIELD('_checkNext:Record')
51-
@FIELD('_checkPrev:Record')
50+
@FIELD('checkNext:Record')
51+
@FIELD('checkPrev:Record')
5252
// next notifier
53-
@FIELD('_notifierNext:Record')
53+
@FIELD('notifierNext:Record')
5454

55-
@FIELD('_mode:int')
56-
@FIELD('_context')
57-
@FIELD('_getter')
58-
@FIELD('_arguments')
55+
@FIELD('mode:int')
56+
@FIELD('context')
57+
@FIELD('getter')
5958
@FIELD('previousValue')
59+
@FIELD('currentValue')
6060
constructor(watchGroup/*:wg.WatchGroup*/, protoRecord:ProtoRecord) {
6161
this.protoRecord = protoRecord;
6262
this.watchGroup = watchGroup;
@@ -71,7 +71,8 @@ export class Record {
7171
this.getter = null;
7272
this.arguments = null;
7373
this.previousValue = null;
74-
this.currentValue = null;
74+
// `this` means that the record is fresh
75+
this.currentValue = this;
7576
}
7677

7778
check():boolean {
@@ -119,10 +120,9 @@ export class Record {
119120
}
120121
}
121122

122-
123123
// todo(vicb): compute this info only once in ctor ? (add a bit in mode not to grow the mem req)
124124
if (this.protoRecord.dispatchMemento === null) {
125-
// forward propagate to the next record
125+
this.next.setContext(this.currentValue);
126126
} else {
127127
// notify through dispatcher
128128
this.watchGroup.dispatcher.onRecordChange(this, this.protoRecord.dispatchMemento);
@@ -132,8 +132,6 @@ export class Record {
132132
}
133133

134134
setContext(context) {
135-
// use `this` as a marker for a fresh record
136-
this.currentValue = this;
137135
this.mode = MODE_STATE_PROPERTY;
138136
this.context = context;
139137
var factory = new FieldGetterFactory();

modules/change_detection/src/watch_group.js

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {ProtoRecord, Record} from './record';
22
import {FIELD} from 'facade/lang';
3+
import {ListWrapper} from 'facade/collection';
34

45
export class ProtoWatchGroup {
56
@FIELD('final headRecord:ProtoRecord')
@@ -19,16 +20,25 @@ export class ProtoWatchGroup {
1920
*/
2021
watch(expression:string,
2122
memento,
22-
shallow /*= false*/) // TODO(vicb): comment out when opt-params are supported
23+
shallow = false)
2324
{
24-
var protoRecord = new ProtoRecord(this, expression, memento);
25+
var parts = expression.split('.');
26+
var protoRecords = ListWrapper.createFixedSize(parts.length);
2527

26-
if (this.headRecord === null) {
27-
this.headRecord = this.tailRecord = protoRecord;
28-
} else {
29-
this.tailRecord.next = protoRecord;
30-
protoRecord.prev = this.tailRecord;
31-
this.tailRecord = protoRecord;
28+
for (var i = parts.length - 1; i >= 0; i--) {
29+
protoRecords[i] = new ProtoRecord(this, parts[i], memento);
30+
memento = null;
31+
}
32+
33+
for (var i = 0; i < parts.length; i++) {
34+
var protoRecord = protoRecords[i];
35+
if (this.headRecord === null) {
36+
this.headRecord = this.tailRecord = protoRecord;
37+
} else {
38+
this.tailRecord.next = protoRecord;
39+
protoRecord.prev = this.tailRecord;
40+
this.tailRecord = protoRecord;
41+
}
3242
}
3343
}
3444

modules/change_detection/test/change_detector_spec.js

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ export function main() {
1717
it('should do simple watching', function() {
1818
var person = new Person('misko', 38);
1919
var pwg = new ProtoWatchGroup();
20-
pwg.watch('name', 'name', false); // TODO(vicb): remove opt shallow when supported
21-
pwg.watch('age', 'age', false);
20+
pwg.watch('name', 'name');
21+
pwg.watch('age', 'age');
2222
var dispatcher = new LoggingDispatcher();
2323
var wg = pwg.instantiate(dispatcher);
2424
wg.setContext(person);
@@ -33,18 +33,53 @@ export function main() {
3333
cd.detectChanges();
3434
expect(dispatcher.log).toEqual(['name=Misko', 'age=1']);
3535
});
36+
37+
it('should watch chained properties', function() {
38+
var address = new Address('Grenoble');
39+
var person = new Person('Victor', 36, address);
40+
var pwg = new ProtoWatchGroup();
41+
pwg.watch('address.city', 'address.city', false);
42+
var dispatcher = new LoggingDispatcher();
43+
var wg = pwg.instantiate(dispatcher);
44+
wg.setContext(person);
45+
var cd = new ChangeDetector(wg);
46+
cd.detectChanges();
47+
expect(dispatcher.log).toEqual(['address.city=Grenoble']);
48+
dispatcher.clear();
49+
cd.detectChanges();
50+
expect(dispatcher.log).toEqual([]);
51+
address.city = 'Mountain View';
52+
cd.detectChanges();
53+
expect(dispatcher.log).toEqual(['address.city=Mountain View']);
54+
});
55+
3656
});
3757
});
3858
}
3959

4060
class Person {
41-
constructor(name:string, age:number) {
61+
constructor(name:string, age:number, address:Address = null) {
4262
this.name = name;
4363
this.age = age;
64+
this.address = address;
65+
}
66+
67+
toString():string {
68+
var address = this.address == null ? '' : ' address=' + this.address.toString();
69+
70+
return 'name=' + this.name +
71+
' age=' + this.age.toString() +
72+
address;
73+
}
74+
}
75+
76+
class Address {
77+
constructor(city:string) {
78+
this.city = city;
4479
}
4580

46-
toString() {
47-
return 'name=' + this.name + ' age=' + this.age.toString();
81+
toString():string {
82+
return this.city;
4883
}
4984
}
5085

modules/facade/pubspec.yaml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
name: facade
22
environment:
33
sdk: '>=1.4.0'
4-
dependencies:
54
dev_dependencies:
65
test_lib:
76
path: ../test_lib

0 commit comments

Comments
 (0)