From 272ad61ab16d42ffcdb1bf137751be63612dae65 Mon Sep 17 00:00:00 2001 From: Rado Kirov Date: Thu, 13 Aug 2015 18:06:55 -0700 Subject: [PATCH] fix(injectors): reset the construction counter in dynamic strategy. Adds tests for hydrate / dehydrate in cycle. Closes #3635 --- .../src/core/compiler/element_injector.ts | 7 +-- .../core/compiler/element_injector_spec.ts | 44 +++++++++++++++++++ 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/modules/angular2/src/core/compiler/element_injector.ts b/modules/angular2/src/core/compiler/element_injector.ts index 6982b980b2..bbb184365e 100644 --- a/modules/angular2/src/core/compiler/element_injector.ts +++ b/modules/angular2/src/core/compiler/element_injector.ts @@ -673,7 +673,7 @@ export class ElementInjector extends TreeNode implements Depend private _addViewQuery(queryRef: QueryRef, host: ElementInjector): void { if (isBlank(queryRef) || !queryRef.isViewQuery || this._hasQuery(queryRef)) return; - if (host._query0.originator == host) { + if (queryRef.originator == host) { // TODO(rado): Replace this.parent check with distanceToParent = 1 when // https://github.com/angular/angular/issues/2707 is fixed. if (!queryRef.query.descendants && isPresent(this.parent)) return; @@ -863,8 +863,8 @@ export class ElementInjector extends TreeNode implements Depend getRootViewInjectors(): ElementInjector[] { var view = this._preBuiltObjects.view; - return view.getNestedView(view.elementOffset + this.getBoundElementIndex()) - .rootElementInjectors; + var nestedView = view.getNestedView(view.elementOffset + this.getBoundElementIndex()); + return isPresent(nestedView) ? nestedView.rootElementInjectors : []; } } @@ -1068,6 +1068,7 @@ class ElementInjectorDynamicStrategy implements _ElementInjectorStrategy { hydrate(): void { var inj = this.injectorStrategy; var p = inj.protoStrategy; + inj.resetConstructionCounter(); for (var i = 0; i < p.keyIds.length; i++) { if (p.bindings[i] instanceof DirectiveBinding && isPresent(p.keyIds[i]) && diff --git a/modules/angular2/test/core/compiler/element_injector_spec.ts b/modules/angular2/test/core/compiler/element_injector_spec.ts index d09ad722cb..558e65baeb 100644 --- a/modules/angular2/test/core/compiler/element_injector_spec.ts +++ b/modules/angular2/test/core/compiler/element_injector_spec.ts @@ -35,6 +35,7 @@ import { import { Attribute, Query, + ViewQuery, ComponentMetadata, DirectiveMetadata, LifecycleEvent @@ -51,9 +52,11 @@ import {QueryList} from 'angular2/src/core/compiler/query_list'; @IMPLEMENTS(AppView) class DummyView extends SpyObject { changeDetector; + elementOffset: number; constructor() { super(AppView); this.changeDetector = null; + this.elementOffset = 0; } noSuchMethod(m) { return super.noSuchMethod(m); } } @@ -159,6 +162,12 @@ class NeedsQuery { constructor(@Query(CountingDirective) query: QueryList) { this.query = query; } } +@Injectable() +class NeedsViewQuery { + query: QueryList; + constructor(@ViewQuery(CountingDirective) query: QueryList) { this.query = query; } +} + @Injectable() class NeedsQueryByVarBindings { query: QueryList; @@ -850,6 +859,41 @@ export function main() { }); }); + describe("getRootViewInjectors", () => { + it("should return an empty array if there is no nested view", () => { + var inj = injector(extraBindings); + expect(inj.getRootViewInjectors()).toEqual([]); + }); + }); + + describe("dehydrate", () => { + function cycleHydrate(inj: ElementInjector, host=null): void { + // Each injection supports 3 query slots, so we cycle 4 times. + for (var i = 0; i < 4; i++) { + inj.dehydrate(); + inj.hydrate(null, host, defaultPreBuiltObjects); + } + } + + it("should handle repeated hydration / dehydration", () => { + var inj = injector(extraBindings); + cycleHydrate(inj); + }); + + it("should handle repeated hydration / dehydration with query present", () => { + var inj = injector(ListWrapper.concat([NeedsQuery], extraBindings)); + cycleHydrate(inj); + }); + + + it("should handle repeated hydration / dehydration with view query present", () => { + var inj = injector(extraBindings); + var host = injector(ListWrapper.concat([NeedsViewQuery], extraBindings)); + + cycleHydrate(inj, host); + }); + }); + describe("lifecycle", () => { it("should call onDestroy on directives subscribed to this event", () => { var inj = injector(ListWrapper.concat(