fix(ivy): remove query results from destroyed embedded views (#28445)

PR Close #28445
This commit is contained in:
Pawel Kozlowski 2019-01-30 12:18:27 +01:00 committed by Matias Niemelä
parent eed59b713a
commit 5ebc0da640
3 changed files with 30 additions and 18 deletions

View File

@ -242,14 +242,17 @@ export function destroyViewTree(rootView: LView): void {
while (viewOrContainer) { while (viewOrContainer) {
let next: LView|LContainer|null = null; let next: LView|LContainer|null = null;
if (viewOrContainer.length >= HEADER_OFFSET) { if (isLContainer(viewOrContainer)) {
// If container, traverse down to its first LView.
const container = viewOrContainer as LContainer;
const viewsInContainer = container[VIEWS];
if (viewsInContainer.length) {
next = viewsInContainer[0];
}
} else {
// If LView, traverse down to child. // If LView, traverse down to child.
const view = viewOrContainer as LView; const view = viewOrContainer as LView;
if (view[TVIEW].childIndex > -1) next = getLViewChild(view); if (view[TVIEW].childIndex > -1) next = getLViewChild(view);
} else {
// If container, traverse down to its first LView.
const container = viewOrContainer as LContainer;
if (container[VIEWS].length) next = container[VIEWS][0];
} }
if (next == null) { if (next == null) {
@ -258,6 +261,15 @@ export function destroyViewTree(rootView: LView): void {
while (viewOrContainer && !viewOrContainer ![NEXT] && viewOrContainer !== rootView) { while (viewOrContainer && !viewOrContainer ![NEXT] && viewOrContainer !== rootView) {
cleanUpView(viewOrContainer); cleanUpView(viewOrContainer);
viewOrContainer = getParentState(viewOrContainer, rootView); viewOrContainer = getParentState(viewOrContainer, rootView);
if (isLContainer(viewOrContainer)) {
// this view will be destroyed so we need to notify queries that a view is detached
const viewsInContainer = (viewOrContainer as LContainer)[VIEWS];
for (let viewToDetach of viewsInContainer) {
if (viewToDetach[QUERIES]) {
viewToDetach[QUERIES] !.removeView();
}
}
}
} }
cleanUpView(viewOrContainer || rootView); cleanUpView(viewOrContainer || rootView);
next = viewOrContainer && viewOrContainer ![NEXT]; next = viewOrContainer && viewOrContainer ![NEXT];

View File

@ -127,7 +127,8 @@ export function isComponentDef<T>(def: DirectiveDef<T>): def is ComponentDef<T>
return (def as ComponentDef<T>).template !== null; return (def as ComponentDef<T>).template !== null;
} }
export function isLContainer(value: RElement | RComment | LContainer | StylingContext): boolean { export function isLContainer(
value: RElement | RComment | LContainer | LView | StylingContext | null): boolean {
// Styling contexts are also arrays, but their first index contains an element node // Styling contexts are also arrays, but their first index contains an element node
return Array.isArray(value) && value.length === LCONTAINER_LENGTH; return Array.isArray(value) && value.length === LCONTAINER_LENGTH;
} }

View File

@ -633,8 +633,7 @@ describe('Query API', () => {
expect(q.query.map((d: TextDirective) => d.text)).toEqual(['2', '1']); expect(q.query.map((d: TextDirective) => d.text)).toEqual(['2', '1']);
}); });
fixmeIvy('FW-920: Queries in nested views are not destroyed properly') it('should remove manually projected templates if their parent view is destroyed', () => {
.it('should remove manually projected templates if their parent view is destroyed', () => {
const template = ` const template = `
<manual-projecting #q><ng-template #tpl><div text="1"></div></ng-template></manual-projecting> <manual-projecting #q><ng-template #tpl><div text="1"></div></ng-template></manual-projecting>
<div *ngIf="shouldShow"> <div *ngIf="shouldShow">