feat(ChangeDetector): Add support for chained properties
This commit is contained in:
		
							parent
							
								
									63494a74bf
								
							
						
					
					
						commit
						c90a7114d3
					
				| @ -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(); | ||||
|  | ||||
| @ -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,10 +20,18 @@ 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); | ||||
| 
 | ||||
|     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 { | ||||
| @ -31,6 +40,7 @@ export class ProtoWatchGroup { | ||||
|         this.tailRecord = protoRecord; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   instantiate(dispatcher:WatchGroupDispatcher):WatchGroup { | ||||
|     var watchGroup:WatchGroup = new WatchGroup(this, dispatcher); | ||||
|  | ||||
| @ -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; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -1,7 +1,6 @@ | ||||
| name: facade | ||||
| environment: | ||||
|   sdk: '>=1.4.0' | ||||
| dependencies: | ||||
| dev_dependencies: | ||||
|   test_lib: | ||||
|     path: ../test_lib | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user