fix(ivy): ngTemplateOutlet error when switching between null and template value (#32160)
Fixes an error that is thrown by `ngTemplateOutlet` under Ivy when switching from a template to null and back to a template. The error is thrown because the reference to the previous ViewRef is never cleared and the directive tries to detach a view that has already been detached. Fixes #32060. PR Close #32160
This commit is contained in:
parent
994264c0ba
commit
c2868de25a
|
@ -55,18 +55,17 @@ export class NgTemplateOutlet implements OnChanges {
|
||||||
const recreateView = this._shouldRecreateView(changes);
|
const recreateView = this._shouldRecreateView(changes);
|
||||||
|
|
||||||
if (recreateView) {
|
if (recreateView) {
|
||||||
|
const viewContainerRef = this._viewContainerRef;
|
||||||
|
|
||||||
if (this._viewRef) {
|
if (this._viewRef) {
|
||||||
this._viewContainerRef.remove(this._viewContainerRef.indexOf(this._viewRef));
|
viewContainerRef.remove(viewContainerRef.indexOf(this._viewRef));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.ngTemplateOutlet) {
|
this._viewRef = this.ngTemplateOutlet ?
|
||||||
this._viewRef = this._viewContainerRef.createEmbeddedView(
|
viewContainerRef.createEmbeddedView(this.ngTemplateOutlet, this.ngTemplateOutletContext) :
|
||||||
this.ngTemplateOutlet, this.ngTemplateOutletContext);
|
null;
|
||||||
}
|
} else if (this._viewRef && this.ngTemplateOutletContext) {
|
||||||
} else {
|
this._updateExistingContext(this.ngTemplateOutletContext);
|
||||||
if (this._viewRef && this.ngTemplateOutletContext) {
|
|
||||||
this._updateExistingContext(this.ngTemplateOutletContext);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,9 +95,8 @@ export class NgTemplateOutlet implements OnChanges {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
} else {
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _updateExistingContext(ctx: Object): void {
|
private _updateExistingContext(ctx: Object): void {
|
||||||
|
|
|
@ -218,6 +218,25 @@ describe('NgTemplateOutlet', () => {
|
||||||
}).not.toThrow();
|
}).not.toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should not throw when switching from template to null and back to template', async(() => {
|
||||||
|
const template = `<tpl-refs #refs="tplRefs"><ng-template>foo</ng-template></tpl-refs>` +
|
||||||
|
`<ng-container [ngTemplateOutlet]="currentTplRef"></ng-container>`;
|
||||||
|
fixture = createTestComponent(template);
|
||||||
|
fixture.detectChanges();
|
||||||
|
const refs = fixture.debugElement.children[0].references !['refs'];
|
||||||
|
|
||||||
|
setTplRef(refs.tplRefs.first);
|
||||||
|
detectChangesAndExpectText('foo');
|
||||||
|
|
||||||
|
setTplRef(null);
|
||||||
|
detectChangesAndExpectText('');
|
||||||
|
|
||||||
|
expect(() => {
|
||||||
|
setTplRef(refs.tplRefs.first);
|
||||||
|
detectChangesAndExpectText('foo');
|
||||||
|
}).not.toThrow();
|
||||||
|
}));
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
|
|
Loading…
Reference in New Issue