fix(query): clean-up queryref during dehydration
The QueryRef objects persists during dehydration but needs to be cleaned-up by removing callbacks and previous elements. Closes #3944 Closes #3948
This commit is contained in:
		
							parent
							
								
									44a991e245
								
							
						
					
					
						commit
						01cdd31339
					
				| @ -433,6 +433,7 @@ export class ElementInjector extends TreeNode<ElementInjector> implements Depend | ||||
|     this._preBuiltObjects = null; | ||||
|     this._strategy.callOnDestroy(); | ||||
|     this._strategy.dehydrate(); | ||||
|     this._clearQueryLists(); | ||||
|   } | ||||
| 
 | ||||
|   afterContentChecked(): void { | ||||
| @ -837,6 +838,12 @@ export class ElementInjector extends TreeNode<ElementInjector> implements Depend | ||||
|     var nestedView = view.getNestedView(view.elementOffset + this.getBoundElementIndex()); | ||||
|     return isPresent(nestedView) ? nestedView.rootElementInjectors : []; | ||||
|   } | ||||
| 
 | ||||
|   private _clearQueryLists(): void { | ||||
|     if (isPresent(this._query0) && this._query0.originator === this) this._query0.reset(); | ||||
|     if (isPresent(this._query1) && this._query1.originator === this) this._query1.reset(); | ||||
|     if (isPresent(this._query2) && this._query2.originator === this) this._query2.reset(); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| interface _ElementInjectorStrategy { | ||||
| @ -1163,4 +1170,9 @@ export class QueryRef { | ||||
|   private _aggregateDirective(inj: ElementInjector, aggregator: any[]): void { | ||||
|     inj.addDirectivesMatchingQuery(this.query, aggregator); | ||||
|   } | ||||
| 
 | ||||
|   reset(): void { | ||||
|     this.list.reset([]); | ||||
|     this.list.removeAllCallbacks(); | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -89,13 +89,6 @@ class QueryList<T> extends Object | ||||
|     _dirty = true; | ||||
|   } | ||||
| 
 | ||||
|   // TODO(rado): hook up with change detection after #995. | ||||
|   void fireCallbacks() { | ||||
|     if (_dirty) { | ||||
|       _callbacks.forEach((c) => c()); | ||||
|       _dirty = false; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   void onChange(callback) { | ||||
|     _callbacks.add(callback); | ||||
| @ -105,6 +98,10 @@ class QueryList<T> extends Object | ||||
|     _callbacks.remove(callback); | ||||
|   } | ||||
| 
 | ||||
|   void removeAllCallbacks() { | ||||
|     this._callbacks = []; | ||||
|   } | ||||
| 
 | ||||
|   int get length => _results.length; | ||||
|   T get first => _results.first; | ||||
|   T get last => _results.last; | ||||
| @ -116,4 +113,12 @@ class QueryList<T> extends Object | ||||
|     // Note: we need to return a list instead of iterable to match JS. | ||||
|     return this._results.map(fn).toList(); | ||||
|   } | ||||
| 
 | ||||
|   // Internal to the framework. | ||||
|   void fireCallbacks() { | ||||
|     if (_dirty) { | ||||
|       _callbacks.forEach((c) => c()); | ||||
|       _dirty = false; | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -86,17 +86,13 @@ export class QueryList<T> { | ||||
|     this._dirty = true; | ||||
|   } | ||||
| 
 | ||||
|   fireCallbacks(): void { | ||||
|     if (this._dirty) { | ||||
|       ListWrapper.forEach(this._callbacks, (c) => c()); | ||||
|       this._dirty = false; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   onChange(callback: () => void): void { this._callbacks.push(callback); } | ||||
| 
 | ||||
|   removeCallback(callback: () => void): void { ListWrapper.remove(this._callbacks, callback); } | ||||
| 
 | ||||
|   removeAllCallbacks(): void { this._callbacks = []; } | ||||
| 
 | ||||
|   toString(): string { return this._results.toString(); } | ||||
| 
 | ||||
|   get length(): number { return this._results.length; } | ||||
| @ -106,4 +102,12 @@ export class QueryList<T> { | ||||
|   map<U>(fn: (item: T) => U): U[] { return this._results.map(fn); } | ||||
| 
 | ||||
|   [Symbol.iterator](): any { return this._results[Symbol.iterator](); } | ||||
| 
 | ||||
|   // Internal to the framework.
 | ||||
|   fireCallbacks(): void { | ||||
|     if (this._dirty) { | ||||
|       ListWrapper.forEach(this._callbacks, (c) => c()); | ||||
|       this._dirty = false; | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -212,6 +212,34 @@ export function main() { | ||||
|                  view.detectChanges(); | ||||
|                }); | ||||
|          })); | ||||
| 
 | ||||
|       it('should correctly clean-up when destroyed together with the directives it is querying', | ||||
|          inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => { | ||||
|            var template = | ||||
|                '<needs-query #q *ng-if="shouldShow"><div text="foo"></div></needs-query>'; | ||||
| 
 | ||||
|            tcb.overrideTemplate(MyComp, template) | ||||
|                .createAsync(MyComp) | ||||
|                .then((view) => { | ||||
|                  view.componentInstance.shouldShow = true; | ||||
|                  view.detectChanges(); | ||||
| 
 | ||||
|                  var q: NeedsQuery = view.componentViewChildren[1].getLocal('q'); | ||||
|                  expect(q.query.length).toEqual(1); | ||||
| 
 | ||||
|                  view.componentInstance.shouldShow = false; | ||||
|                  view.detectChanges(); | ||||
| 
 | ||||
|                  view.componentInstance.shouldShow = true; | ||||
|                  view.detectChanges(); | ||||
| 
 | ||||
|                  var q2: NeedsQuery = view.componentViewChildren[1].getLocal('q'); | ||||
| 
 | ||||
|                  expect(q2.query.length).toEqual(1); | ||||
| 
 | ||||
|                  async.done(); | ||||
|                }); | ||||
|          })); | ||||
|     }); | ||||
| 
 | ||||
|     describe("querying by var binding", () => { | ||||
|  | ||||
| @ -92,6 +92,19 @@ export function main() { | ||||
|         queryList.fireCallbacks(); | ||||
|         expect(fires).toEqual(1); | ||||
|       }); | ||||
| 
 | ||||
|       it('should support removing all callbacks', () => { | ||||
|         var fires = 0; | ||||
|         var callback = () => fires += 1; | ||||
|         queryList.onChange(callback); | ||||
| 
 | ||||
|         queryList.add('one'); | ||||
|         queryList.removeAllCallbacks(); | ||||
| 
 | ||||
|         queryList.fireCallbacks(); | ||||
| 
 | ||||
|         expect(fires).toEqual(0); | ||||
|       }); | ||||
|     }); | ||||
|   }); | ||||
| } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user