@@ -30,6 +30,8 @@ import {
3030 ViewContainerRef ,
3131} from '../../src/core' ;
3232import { provideCheckNoChangesConfig } from '../../src/change_detection/provide_check_no_changes_config' ;
33+ import { LContainerFlags , MOVED_VIEWS } from '../../src/render3/interfaces/container' ;
34+ import { FLAGS , LView , QUERIES } from '../../src/render3/interfaces/view' ;
3335import { ComponentFixture , TestBed } from '../../testing' ;
3436import { expect } from '@angular/private/testing/matchers' ;
3537import { timeout } from '@angular/private/testing' ;
@@ -756,6 +758,114 @@ describe('change detection for transplanted views', () => {
756758 ) ;
757759 } ) ;
758760
761+ it ( 'keeps refreshing other transplanted views when an insertion container is cleared on destroy' , ( ) => {
762+ @Component ( {
763+ selector : 'outlet' ,
764+ template : '<ng-container #container />' ,
765+ standalone : true ,
766+ changeDetection : ChangeDetectionStrategy . OnPush ,
767+ } )
768+ class Outlet {
769+ @Input ( ) template ! : TemplateRef < { } > ;
770+ @ViewChild ( 'container' , { read : ViewContainerRef , static : true } )
771+ container ! : ViewContainerRef ;
772+
773+ ngOnInit ( ) {
774+ this . container . createEmbeddedView ( this . template ) ;
775+ }
776+
777+ ngOnDestroy ( ) {
778+ this . container . clear ( ) ;
779+ }
780+ }
781+
782+ @Component ( {
783+ template : `
784+ <ng-template #template>{{ name }}</ng-template>
785+ @for (item of items; track item) {
786+ <outlet [template]="template"></outlet>
787+ }
788+ ` ,
789+ standalone : true ,
790+ imports : [ Outlet ] ,
791+ changeDetection : ChangeDetectionStrategy . Eager ,
792+ } )
793+ class App {
794+ items = [ 1 , 2 , 3 ] ;
795+ name = 'Penny' ;
796+ }
797+
798+ const fixture = TestBed . createComponent ( App ) ;
799+ fixture . detectChanges ( ) ;
800+ expect ( fixture . nativeElement . textContent ) . toEqual ( 'PennyPennyPenny' ) ;
801+
802+ fixture . componentInstance . items = [ 1 , 2 ] ;
803+ fixture . detectChanges ( ) ;
804+ fixture . componentInstance . name = 'Sheldon' ;
805+ fixture . detectChanges ( ) ;
806+ expect ( fixture . nativeElement . textContent ) . toEqual ( 'SheldonSheldon' ) ;
807+ } ) ;
808+
809+ it ( 'should not double-detach queries and should clear HasTransplantedViews flag' , ( ) => {
810+ @Component ( {
811+ selector : 'outlet' ,
812+ template : '<ng-container #container />' ,
813+ standalone : true ,
814+ } )
815+ class Outlet {
816+ @Input ( ) template ! : TemplateRef < { } > ;
817+ @ViewChild ( 'container' , { read : ViewContainerRef , static : true } )
818+ container ! : ViewContainerRef ;
819+
820+ ngOnInit ( ) {
821+ this . container . createEmbeddedView ( this . template ) ;
822+ }
823+
824+ ngOnDestroy ( ) {
825+ this . container . clear ( ) ;
826+ }
827+ }
828+
829+ @Component ( {
830+ template : `
831+ <!-- We use a query to force the instantiation of LQueries -->
832+ <ng-template #template><div #myQuery></div></ng-template>
833+ @if (show) {
834+ <outlet [template]="template"></outlet>
835+ }
836+ ` ,
837+ standalone : true ,
838+ imports : [ Outlet ] ,
839+ } )
840+ class App {
841+ @ViewChild ( 'template' , { read : TemplateRef , static : true } )
842+ template ! : TemplateRef < any > ;
843+ show = true ;
844+ }
845+
846+ const fixture = TestBed . createComponent ( App ) ;
847+ fixture . detectChanges ( ) ;
848+
849+ const appLView = ( fixture . componentInstance as any ) . __ngContext__ as LView ;
850+ const declarationContainer = appLView [ 20 ] as any ;
851+ const transplantedLView = declarationContainer [ MOVED_VIEWS ] ! [ 0 ] as LView ;
852+ const lQueries = transplantedLView [ QUERIES ] ! ;
853+
854+ const detachViewSpy = spyOn ( lQueries , 'detachView' ) . and . callThrough ( ) ;
855+
856+ fixture . componentInstance . show = false ;
857+ fixture . detectChanges ( ) ;
858+
859+ expect ( detachViewSpy ) . toHaveBeenCalledTimes ( 1 ) ;
860+
861+ const hasTransplantedViewsFlag =
862+ ( declarationContainer [ FLAGS ] & LContainerFlags . HasTransplantedViews ) ===
863+ LContainerFlags . HasTransplantedViews ;
864+
865+ expect ( declarationContainer [ MOVED_VIEWS ] ) . toBeNull ( ) ;
866+ expect ( hasTransplantedViewsFlag ) . toBeFalse ( ) ;
867+ } ) ;
868+
759869 describe ( 'ViewRef and ViewContainerRef operations' , ( ) => {
760870 @Component ( {
761871 template : '<ng-template>{{incrementChecks()}}</ng-template>' ,
0 commit comments