@@ -12,6 +12,7 @@ import {BrowserModule} from '@angular/platform-browser';
1212import { platformBrowserDynamic } from '@angular/platform-browser-dynamic' ;
1313import * as angular from '@angular/upgrade/src/common/angular1' ;
1414import { UpgradeAdapter , UpgradeAdapterRef } from '@angular/upgrade/src/dynamic/upgrade_adapter' ;
15+
1516import { $apply , $digest , html , multiTrim , withEachNg1Version } from './test_helpers' ;
1617
1718declare global {
@@ -2177,9 +2178,10 @@ withEachNg1Version(() => {
21772178 } ) ;
21782179 } ) ) ;
21792180
2180- it ( 'should emit `$destroy` on `$element`' , fakeAsync ( ( ) => {
2181+ it ( 'should emit `$destroy` on `$element` and descendants ' , fakeAsync ( ( ) => {
21812182 const adapter : UpgradeAdapter = new UpgradeAdapter ( forwardRef ( ( ) => Ng2Module ) ) ;
21822183 const elementDestroyListener = jasmine . createSpy ( 'elementDestroyListener' ) ;
2184+ const descendantDestroyListener = jasmine . createSpy ( 'descendantDestroyListener' ) ;
21832185 let ng2ComponentInstance : Ng2Component ;
21842186
21852187 @Component ( { selector : 'ng2' , template : '<div *ngIf="!ng2Destroy"><ng1></ng1></div>' } )
@@ -2194,9 +2196,13 @@ withEachNg1Version(() => {
21942196 // Mocking animations (via `ngAnimateMock`) avoids the issue.
21952197 angular . module ( 'ng1' , [ 'ngAnimateMock' ] )
21962198 . component ( 'ng1' , {
2197- controller : function ( $element : angular . IAugmentedJQuery ) {
2198- $element . on ! ( '$destroy' , elementDestroyListener ) ;
2199+ controller : class {
2200+ constructor ( private $element : angular . IAugmentedJQuery ) { } $onInit ( ) {
2201+ this . $element . on ! ( '$destroy' , elementDestroyListener ) ;
2202+ this . $element . contents ! ( ) . on ! ( '$destroy' , descendantDestroyListener ) ;
2203+ }
21992204 } ,
2205+ template : '<div></div>'
22002206 } )
22012207 . directive ( 'ng2' , adapter . downgradeNg2Component ( Ng2Component ) ) ;
22022208
@@ -2210,14 +2216,150 @@ withEachNg1Version(() => {
22102216 const element = html ( '<ng2></ng2>' ) ;
22112217 adapter . bootstrap ( element , [ 'ng1' ] ) . ready ( ( ref ) => {
22122218 const $rootScope = ref . ng1RootScope as any ;
2219+ tick ( ) ;
2220+ $rootScope . $digest ( ) ;
22132221
22142222 expect ( elementDestroyListener ) . not . toHaveBeenCalled ( ) ;
2223+ expect ( descendantDestroyListener ) . not . toHaveBeenCalled ( ) ;
22152224
22162225 ng2ComponentInstance . ng2Destroy = true ;
22172226 tick ( ) ;
22182227 $rootScope . $digest ( ) ;
22192228
22202229 expect ( elementDestroyListener ) . toHaveBeenCalledTimes ( 1 ) ;
2230+ expect ( descendantDestroyListener ) . toHaveBeenCalledTimes ( 1 ) ;
2231+ } ) ;
2232+ } ) ) ;
2233+
2234+ it ( 'should clear data on `$element` and descendants' , fakeAsync ( ( ) => {
2235+ const adapter : UpgradeAdapter = new UpgradeAdapter ( forwardRef ( ( ) => Ng2Module ) ) ;
2236+ let ng1ComponentElement : angular . IAugmentedJQuery ;
2237+ let ng2ComponentAInstance : Ng2ComponentA ;
2238+
2239+ // Define `ng1Component`
2240+ const ng1Component : angular . IComponent = {
2241+ controller : class {
2242+ constructor ( private $element : angular . IAugmentedJQuery ) { } $onInit ( ) {
2243+ this . $element . data ! ( 'test' , 1 ) ;
2244+ this . $element . contents ! ( ) . data ! ( 'test' , 2 ) ;
2245+
2246+ ng1ComponentElement = this . $element ;
2247+ }
2248+ } ,
2249+ template : '<div></div>'
2250+ } ;
2251+
2252+ // Define `Ng2Component`
2253+ @Component ( { selector : 'ng2A' , template : '<ng2B *ngIf="!destroyIt"></ng2B>' } )
2254+ class Ng2ComponentA {
2255+ destroyIt = false ;
2256+
2257+ constructor ( ) { ng2ComponentAInstance = this ; }
2258+ }
2259+
2260+ @Component ( { selector : 'ng2B' , template : '<ng1></ng1>' } )
2261+ class Ng2ComponentB {
2262+ }
2263+
2264+ // Define `ng1Module`
2265+ angular . module ( 'ng1Module' , [ ] )
2266+ . component ( 'ng1' , ng1Component )
2267+ . directive ( 'ng2A' , adapter . downgradeNg2Component ( Ng2ComponentA ) ) ;
2268+
2269+ // Define `Ng2Module`
2270+ @NgModule ( {
2271+ declarations : [ adapter . upgradeNg1Component ( 'ng1' ) , Ng2ComponentA , Ng2ComponentB ] ,
2272+ entryComponents : [ Ng2ComponentA ] ,
2273+ imports : [ BrowserModule ]
2274+ } )
2275+ class Ng2Module {
2276+ ngDoBootstrap ( ) { }
2277+ }
2278+
2279+ // Bootstrap
2280+ const element = html ( `<ng2-a></ng2-a>` ) ;
2281+
2282+ adapter . bootstrap ( element , [ 'ng1Module' ] ) . ready ( ( ref ) => {
2283+ const $rootScope = ref . ng1RootScope as any ;
2284+ tick ( ) ;
2285+ $rootScope . $digest ( ) ;
2286+ expect ( ng1ComponentElement . data ! ( 'test' ) ) . toBe ( 1 ) ;
2287+ expect ( ng1ComponentElement . contents ! ( ) . data ! ( 'test' ) ) . toBe ( 2 ) ;
2288+
2289+ ng2ComponentAInstance . destroyIt = true ;
2290+ tick ( ) ;
2291+ $rootScope . $digest ( ) ;
2292+
2293+ expect ( ng1ComponentElement . data ! ( 'test' ) ) . toBeUndefined ( ) ;
2294+ expect ( ng1ComponentElement . contents ! ( ) . data ! ( 'test' ) ) . toBeUndefined ( ) ;
2295+ } ) ;
2296+ } ) ) ;
2297+
2298+ it ( 'should clear dom listeners on `$element` and descendants`' , fakeAsync ( ( ) => {
2299+ const adapter : UpgradeAdapter = new UpgradeAdapter ( forwardRef ( ( ) => Ng2Module ) ) ;
2300+ const elementClickListener = jasmine . createSpy ( 'elementClickListener' ) ;
2301+ const descendantClickListener = jasmine . createSpy ( 'descendantClickListener' ) ;
2302+ let ng1DescendantElement : angular . IAugmentedJQuery ;
2303+ let ng2ComponentAInstance : Ng2ComponentA ;
2304+
2305+ // Define `ng1Component`
2306+ const ng1Component : angular . IComponent = {
2307+ controller : class {
2308+ constructor ( private $element : angular . IAugmentedJQuery ) { } $onInit ( ) {
2309+ ng1DescendantElement = this . $element . contents ! ( ) ;
2310+
2311+ this . $element . on ! ( 'click' , elementClickListener ) ;
2312+ ng1DescendantElement . on ! ( 'click' , descendantClickListener ) ;
2313+ }
2314+ } ,
2315+ template : '<div></div>'
2316+ } ;
2317+
2318+ // Define `Ng2Component`
2319+ @Component ( { selector : 'ng2A' , template : '<ng2B *ngIf="!destroyIt"></ng2B>' } )
2320+ class Ng2ComponentA {
2321+ destroyIt = false ;
2322+
2323+ constructor ( ) { ng2ComponentAInstance = this ; }
2324+ }
2325+
2326+ @Component ( { selector : 'ng2B' , template : '<ng1></ng1>' } )
2327+ class Ng2ComponentB {
2328+ }
2329+
2330+ // Define `ng1Module`
2331+ angular . module ( 'ng1Module' , [ ] )
2332+ . component ( 'ng1' , ng1Component )
2333+ . directive ( 'ng2A' , adapter . downgradeNg2Component ( Ng2ComponentA ) ) ;
2334+
2335+ // Define `Ng2Module`
2336+ @NgModule ( {
2337+ declarations : [ adapter . upgradeNg1Component ( 'ng1' ) , Ng2ComponentA , Ng2ComponentB ] ,
2338+ entryComponents : [ Ng2ComponentA ] ,
2339+ imports : [ BrowserModule ]
2340+ } )
2341+ class Ng2Module {
2342+ ngDoBootstrap ( ) { }
2343+ }
2344+
2345+ // Bootstrap
2346+ const element = html ( `<ng2-a></ng2-a>` ) ;
2347+
2348+ adapter . bootstrap ( element , [ 'ng1Module' ] ) . ready ( ( ref ) => {
2349+ const $rootScope = ref . ng1RootScope as any ;
2350+ tick ( ) ;
2351+ $rootScope . $digest ( ) ;
2352+ ( ng1DescendantElement [ 0 ] as HTMLElement ) . click ( ) ;
2353+ expect ( elementClickListener ) . toHaveBeenCalledTimes ( 1 ) ;
2354+ expect ( descendantClickListener ) . toHaveBeenCalledTimes ( 1 ) ;
2355+
2356+ ng2ComponentAInstance . destroyIt = true ;
2357+ tick ( ) ;
2358+ $rootScope . $digest ( ) ;
2359+
2360+ ( ng1DescendantElement [ 0 ] as HTMLElement ) . click ( ) ;
2361+ expect ( elementClickListener ) . toHaveBeenCalledTimes ( 1 ) ;
2362+ expect ( descendantClickListener ) . toHaveBeenCalledTimes ( 1 ) ;
22212363 } ) ;
22222364 } ) ) ;
22232365 } ) ;
0 commit comments