|
8 | 8 |
|
9 | 9 | import {CommonModule, DOCUMENT} from '@angular/common';
|
10 | 10 | import {computeMsgId} from '@angular/compiler';
|
11 |
| -import {Compiler, Component, ComponentFactoryResolver, Directive, DoCheck, ElementRef, EmbeddedViewRef, ErrorHandler, Injector, NgModule, NO_ERRORS_SCHEMA, OnInit, Pipe, PipeTransform, QueryList, RendererFactory2, RendererType2, Sanitizer, TemplateRef, ViewChild, ViewChildren, ViewContainerRef, ɵsetDocument} from '@angular/core'; |
| 11 | +import {Compiler, Component, ComponentFactoryResolver, Directive, DoCheck, ElementRef, EmbeddedViewRef, ErrorHandler, Injector, NgModule, NO_ERRORS_SCHEMA, OnDestroy, OnInit, Pipe, PipeTransform, QueryList, RendererFactory2, RendererType2, Sanitizer, TemplateRef, ViewChild, ViewChildren, ViewContainerRef, ɵsetDocument} from '@angular/core'; |
12 | 12 | import {Input} from '@angular/core/src/metadata';
|
13 | 13 | import {ngDevModeResetPerfCounters} from '@angular/core/src/util/ng_dev_mode';
|
14 | 14 | import {TestBed, TestComponentRenderer} from '@angular/core/testing';
|
@@ -936,6 +936,62 @@ describe('ViewContainerRef', () => {
|
936 | 936 | });
|
937 | 937 | });
|
938 | 938 |
|
| 939 | + describe('dependant views', () => { |
| 940 | + it('should not throw when view removes another view upon removal', () => { |
| 941 | + @Component({ |
| 942 | + template: ` |
| 943 | + <div *ngIf="visible" [template]="parent">I host a template</div> |
| 944 | + <ng-template #parent> |
| 945 | + <div [template]="child">I host a child template</div> |
| 946 | + </ng-template> |
| 947 | + <ng-template #child> |
| 948 | + I am child template |
| 949 | + </ng-template> |
| 950 | + ` |
| 951 | + }) |
| 952 | + class AppComponent { |
| 953 | + visible = true; |
| 954 | + |
| 955 | + constructor(private readonly vcr: ViewContainerRef) {} |
| 956 | + |
| 957 | + add<C>(template: TemplateRef<C>): EmbeddedViewRef<C> { |
| 958 | + return this.vcr.createEmbeddedView(template); |
| 959 | + } |
| 960 | + |
| 961 | + remove<C>(viewRef: EmbeddedViewRef<C>) { |
| 962 | + this.vcr.remove(this.vcr.indexOf(viewRef)); |
| 963 | + } |
| 964 | + } |
| 965 | + |
| 966 | + @Directive({selector: '[template]'}) |
| 967 | + class TemplateDirective<C> implements OnInit, OnDestroy { |
| 968 | + @Input() template !: TemplateRef<C>; |
| 969 | + ref!: EmbeddedViewRef<C>; |
| 970 | + |
| 971 | + constructor(private readonly host: AppComponent) {} |
| 972 | + |
| 973 | + ngOnInit() { |
| 974 | + this.ref = this.host.add(this.template); |
| 975 | + this.ref.detectChanges(); |
| 976 | + } |
| 977 | + |
| 978 | + ngOnDestroy() { |
| 979 | + this.host.remove(this.ref); |
| 980 | + } |
| 981 | + } |
| 982 | + |
| 983 | + TestBed.configureTestingModule({ |
| 984 | + imports: [CommonModule], |
| 985 | + declarations: [AppComponent, TemplateDirective], |
| 986 | + }); |
| 987 | + |
| 988 | + const fixture = TestBed.createComponent(AppComponent); |
| 989 | + fixture.detectChanges(); |
| 990 | + fixture.componentRef.instance.visible = false; |
| 991 | + fixture.detectChanges(); |
| 992 | + }); |
| 993 | + }); |
| 994 | + |
939 | 995 | describe('createEmbeddedView (incl. insert)', () => {
|
940 | 996 | it('should work on elements', () => {
|
941 | 997 | @Component({
|
|
0 commit comments