diff --git a/packages/core/src/linker/query_list.ts b/packages/core/src/linker/query_list.ts index 9abd01b6fed..8dae2c824f1 100644 --- a/packages/core/src/linker/query_list.ts +++ b/packages/core/src/linker/query_list.ts @@ -108,6 +108,12 @@ export class QueryList/* implements Iterable */ { /** internal */ get dirty() { return this._dirty; } + + /** internal */ + destroy(): void { + this._emitter.complete(); + this._emitter.unsubscribe(); + } } function flatten(list: Array): T[] { diff --git a/packages/core/src/view/view.ts b/packages/core/src/view/view.ts index 18d07766c3b..2bc62aae471 100644 --- a/packages/core/src/view/view.ts +++ b/packages/core/src/view/view.ts @@ -530,6 +530,8 @@ function destroyViewNodes(view: ViewData) { view.renderer.destroyNode !(asElementData(view, i).renderElement); } else if (def.flags & NodeFlags.TypeText) { view.renderer.destroyNode !(asTextData(view, i).renderText); + } else if (def.flags & NodeFlags.TypeContentQuery || def.flags & NodeFlags.TypeViewQuery) { + asQueryList(view, i).destroy(); } } } diff --git a/packages/core/test/linker/query_integration_spec.ts b/packages/core/test/linker/query_integration_spec.ts index d3b5cc8b193..8c8b5d6a436 100644 --- a/packages/core/test/linker/query_integration_spec.ts +++ b/packages/core/test/linker/query_integration_spec.ts @@ -10,6 +10,8 @@ import {AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit, import {ComponentFixture, TestBed, async} from '@angular/core/testing'; import {expect} from '@angular/platform-browser/testing/src/matchers'; +import {Subject} from 'rxjs/Subject'; + import {stringify} from '../../src/util'; export function main() { @@ -348,16 +350,26 @@ export function main() { view.componentInstance.shouldShow = true; view.detectChanges(); + let isQueryListCompleted = false; + const q: NeedsQuery = view.debugElement.children[0].references !['q']; + const changes = >q.query.changes; expect(q.query.length).toEqual(1); + expect(changes.closed).toBeFalsy(); + changes.subscribe(() => {}, () => {}, () => { isQueryListCompleted = true; }); view.componentInstance.shouldShow = false; view.detectChanges(); + expect(changes.closed).toBeTruthy(); + expect(isQueryListCompleted).toBeTruthy(); + view.componentInstance.shouldShow = true; view.detectChanges(); const q2: NeedsQuery = view.debugElement.children[0].references !['q']; expect(q2.query.length).toEqual(1); + expect(changes.closed).toBeTruthy(); + expect((>q2.query.changes).closed).toBeFalsy(); }); }); diff --git a/tools/public_api_guard/core/core.d.ts b/tools/public_api_guard/core/core.d.ts index 91cc4736c2b..fb93e98b366 100644 --- a/tools/public_api_guard/core/core.d.ts +++ b/tools/public_api_guard/core/core.d.ts @@ -745,6 +745,7 @@ export declare class QueryList { readonly first: T; readonly last: T; readonly length: number; + destroy(): void; filter(fn: (item: T, index: number, array: T[]) => boolean): T[]; find(fn: (item: T, index: number, array: T[]) => boolean): T | undefined; forEach(fn: (item: T, index: number, array: T[]) => void): void;