fix(core): don’t detach nested view containers when destroying a view
When a view is destroyed, we destroy all
views in view containers and should not detach them. However, previously, we also detached them which lead to problems during the iteration loop.
Closes #8458
Closes #8471
Introduced by 0c600cf6e3
This commit is contained in:
parent
b30ddfbfc5
commit
e2b1e1577d
|
@ -192,13 +192,7 @@ export abstract class AppView<T> {
|
|||
ObservableWrapper.dispose(this.subscriptions[i]);
|
||||
}
|
||||
this.destroyInternal();
|
||||
if (this._hasExternalHostElement) {
|
||||
this.renderer.detachView(this.flatRootNodes);
|
||||
} else if (isPresent(this.viewContainerElement)) {
|
||||
this.viewContainerElement.detachView(this.viewContainerElement.nestedViews.indexOf(this));
|
||||
} else {
|
||||
this.dirtyParentQueriesInternal();
|
||||
}
|
||||
this.dirtyParentQueriesInternal();
|
||||
this.renderer.destroyView(hostElement, this.allNodes);
|
||||
}
|
||||
|
||||
|
|
|
@ -1005,14 +1005,18 @@ export function main() {
|
|||
}));
|
||||
|
||||
it('should be called after processing the content and view children', fakeAsync(() => {
|
||||
var ctx = createCompWithContentAndViewChild();
|
||||
var ctx = createCompFixture(
|
||||
'<div testDirective="parent"><div *ngFor="let x of [0,1]" testDirective="contentChild{{x}}"></div>' +
|
||||
'<other-cmp></other-cmp></div>',
|
||||
TestComponent,
|
||||
tcb.overrideTemplate(AnotherComponent, '<div testDirective="viewChild"></div>'));
|
||||
|
||||
ctx.detectChanges(false);
|
||||
ctx.destroy();
|
||||
|
||||
expect(directiveLog.filter(['ngOnDestroy']))
|
||||
.toEqual(
|
||||
['contentChild.ngOnDestroy', 'viewChild.ngOnDestroy', 'parent.ngOnDestroy']);
|
||||
['contentChild0.ngOnDestroy', 'contentChild1.ngOnDestroy', 'viewChild.ngOnDestroy', 'parent.ngOnDestroy']);
|
||||
}));
|
||||
|
||||
it('should be called in reverse order so the child is always notified before the parent',
|
||||
|
|
|
@ -483,6 +483,35 @@ function declareTests(isJit: boolean) {
|
|||
});
|
||||
}));
|
||||
|
||||
it('should not detach views in ViewContainers when the parent view is destroyed.',
|
||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||
tcb.overrideView(
|
||||
MyComp, new ViewMetadata({
|
||||
template:
|
||||
'<div *ngIf="ctxBoolProp"><template some-viewport let-greeting="someTmpl"><span>{{greeting}}</span></template></div>',
|
||||
directives: [SomeViewport]
|
||||
}))
|
||||
|
||||
.createAsync(MyComp)
|
||||
.then((fixture) => {
|
||||
fixture.debugElement.componentInstance.ctxBoolProp = true;
|
||||
fixture.detectChanges();
|
||||
|
||||
var ngIfEl = fixture.debugElement.children[0];
|
||||
var someViewport:SomeViewport = ngIfEl.childNodes[0].inject(SomeViewport);
|
||||
expect(someViewport.container.length).toBe(2);
|
||||
expect(ngIfEl.children.length).toBe(2);
|
||||
|
||||
fixture.debugElement.componentInstance.ctxBoolProp = false;
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(someViewport.container.length).toBe(2);
|
||||
expect(fixture.debugElement.children.length).toBe(0);
|
||||
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should use a comment while stamping out `<template>` elements.',
|
||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||
tcb.overrideView(MyComp, new ViewMetadata({template: '<template></template>'}))
|
||||
|
@ -2165,7 +2194,7 @@ class SomeViewportContext {
|
|||
@Directive({selector: '[some-viewport]'})
|
||||
@Injectable()
|
||||
class SomeViewport {
|
||||
constructor(container: ViewContainerRef, templateRef: TemplateRef<SomeViewportContext>) {
|
||||
constructor(public container: ViewContainerRef, templateRef: TemplateRef<SomeViewportContext>) {
|
||||
container.createEmbeddedView(templateRef, new SomeViewportContext('hello'));
|
||||
container.createEmbeddedView(templateRef, new SomeViewportContext('again'));
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue