diff --git a/modules/change_detection/src/record.js b/modules/change_detection/src/record.js index 2c5bfebb13..e490cd7d57 100644 --- a/modules/change_detection/src/record.js +++ b/modules/change_detection/src/record.js @@ -44,19 +44,19 @@ export class Record { @FIELD('final watchGroup:WatchGroup') @FIELD('final protoRecord:ProtoRecord') /// order list of all records. Including head/tail markers - @FIELD('_next:Record') - @FIELD('_prev:Record') + @FIELD('next:Record') + @FIELD('prev:Record') /// next record to dirty check - @FIELD('_checkNext:Record') - @FIELD('_checkPrev:Record') + @FIELD('checkNext:Record') + @FIELD('checkPrev:Record') // next notifier - @FIELD('_notifierNext:Record') + @FIELD('notifierNext:Record') - @FIELD('_mode:int') - @FIELD('_context') - @FIELD('_getter') - @FIELD('_arguments') + @FIELD('mode:int') + @FIELD('context') + @FIELD('getter') @FIELD('previousValue') + @FIELD('currentValue') constructor(watchGroup/*:wg.WatchGroup*/, protoRecord:ProtoRecord) { this.protoRecord = protoRecord; this.watchGroup = watchGroup; @@ -71,7 +71,8 @@ export class Record { this.getter = null; this.arguments = null; this.previousValue = null; - this.currentValue = null; + // `this` means that the record is fresh + this.currentValue = this; } check():boolean { @@ -119,10 +120,9 @@ export class Record { } } - // todo(vicb): compute this info only once in ctor ? (add a bit in mode not to grow the mem req) if (this.protoRecord.dispatchMemento === null) { - // forward propagate to the next record + this.next.setContext(this.currentValue); } else { // notify through dispatcher this.watchGroup.dispatcher.onRecordChange(this, this.protoRecord.dispatchMemento); @@ -132,8 +132,6 @@ export class Record { } setContext(context) { - // use `this` as a marker for a fresh record - this.currentValue = this; this.mode = MODE_STATE_PROPERTY; this.context = context; var factory = new FieldGetterFactory(); diff --git a/modules/change_detection/src/watch_group.js b/modules/change_detection/src/watch_group.js index 9c202c50f8..75914eed73 100644 --- a/modules/change_detection/src/watch_group.js +++ b/modules/change_detection/src/watch_group.js @@ -1,5 +1,6 @@ import {ProtoRecord, Record} from './record'; import {FIELD} from 'facade/lang'; +import {ListWrapper} from 'facade/collection'; export class ProtoWatchGroup { @FIELD('final headRecord:ProtoRecord') @@ -19,16 +20,25 @@ export class ProtoWatchGroup { */ watch(expression:string, memento, - shallow /*= false*/) // TODO(vicb): comment out when opt-params are supported + shallow = false) { - var protoRecord = new ProtoRecord(this, expression, memento); + var parts = expression.split('.'); + var protoRecords = ListWrapper.createFixedSize(parts.length); - if (this.headRecord === null) { - this.headRecord = this.tailRecord = protoRecord; - } else { - this.tailRecord.next = protoRecord; - protoRecord.prev = this.tailRecord; - this.tailRecord = protoRecord; + for (var i = parts.length - 1; i >= 0; i--) { + protoRecords[i] = new ProtoRecord(this, parts[i], memento); + memento = null; + } + + for (var i = 0; i < parts.length; i++) { + var protoRecord = protoRecords[i]; + if (this.headRecord === null) { + this.headRecord = this.tailRecord = protoRecord; + } else { + this.tailRecord.next = protoRecord; + protoRecord.prev = this.tailRecord; + this.tailRecord = protoRecord; + } } } diff --git a/modules/change_detection/test/change_detector_spec.js b/modules/change_detection/test/change_detector_spec.js index 91686c5fee..20599d9392 100644 --- a/modules/change_detection/test/change_detector_spec.js +++ b/modules/change_detection/test/change_detector_spec.js @@ -17,8 +17,8 @@ export function main() { it('should do simple watching', function() { var person = new Person('misko', 38); var pwg = new ProtoWatchGroup(); - pwg.watch('name', 'name', false); // TODO(vicb): remove opt shallow when supported - pwg.watch('age', 'age', false); + pwg.watch('name', 'name'); + pwg.watch('age', 'age'); var dispatcher = new LoggingDispatcher(); var wg = pwg.instantiate(dispatcher); wg.setContext(person); @@ -33,18 +33,53 @@ export function main() { cd.detectChanges(); expect(dispatcher.log).toEqual(['name=Misko', 'age=1']); }); + + it('should watch chained properties', function() { + var address = new Address('Grenoble'); + var person = new Person('Victor', 36, address); + var pwg = new ProtoWatchGroup(); + pwg.watch('address.city', 'address.city', false); + var dispatcher = new LoggingDispatcher(); + var wg = pwg.instantiate(dispatcher); + wg.setContext(person); + var cd = new ChangeDetector(wg); + cd.detectChanges(); + expect(dispatcher.log).toEqual(['address.city=Grenoble']); + dispatcher.clear(); + cd.detectChanges(); + expect(dispatcher.log).toEqual([]); + address.city = 'Mountain View'; + cd.detectChanges(); + expect(dispatcher.log).toEqual(['address.city=Mountain View']); + }); + }); }); } class Person { - constructor(name:string, age:number) { + constructor(name:string, age:number, address:Address = null) { this.name = name; this.age = age; + this.address = address; } - toString() { - return 'name=' + this.name + ' age=' + this.age.toString(); + toString():string { + var address = this.address == null ? '' : ' address=' + this.address.toString(); + + return 'name=' + this.name + + ' age=' + this.age.toString() + + address; + } +} + +class Address { + constructor(city:string) { + this.city = city; + } + + toString():string { + return this.city; } } diff --git a/modules/facade/pubspec.yaml b/modules/facade/pubspec.yaml index 000fd0515b..05e82b8433 100644 --- a/modules/facade/pubspec.yaml +++ b/modules/facade/pubspec.yaml @@ -1,7 +1,6 @@ name: facade environment: sdk: '>=1.4.0' -dependencies: dev_dependencies: test_lib: path: ../test_lib