| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @license | 
					
						
							|  |  |  |  * Copyright Google Inc. All Rights Reserved. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Use of this source code is governed by an MIT-style license that can be | 
					
						
							|  |  |  |  * found in the LICENSE file at https://angular.io/license
 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-05 13:58:27 +03:00
										 |  |  | import {Component, Directive, ElementRef, ErrorHandler, EventEmitter, Inject, Injector, Input, NO_ERRORS_SCHEMA, NgModule, Output, SimpleChanges, destroyPlatform} from '@angular/core'; | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  | import {async, fakeAsync, tick} from '@angular/core/testing'; | 
					
						
							|  |  |  | import {BrowserModule} from '@angular/platform-browser'; | 
					
						
							|  |  |  | import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; | 
					
						
							| 
									
										
										
										
											2016-10-20 19:35:35 -07:00
										 |  |  | import {UpgradeComponent, UpgradeModule, downgradeComponent} from '@angular/upgrade/static'; | 
					
						
							| 
									
										
										
										
											2018-02-15 19:14:20 +02:00
										 |  |  | import * as angular from '@angular/upgrade/static/src/common/angular1'; | 
					
						
							| 
									
										
										
										
											2018-10-11 17:44:59 +03:00
										 |  |  | import {$EXCEPTION_HANDLER, $SCOPE} from '@angular/upgrade/static/src/common/constants'; | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-15 19:21:18 +02:00
										 |  |  | import {$digest, bootstrap, html, multiTrim, withEachNg1Version} from '../test_helpers'; | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-15 19:21:18 +02:00
										 |  |  | withEachNg1Version(() => { | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  |   describe('upgrade ng1 component', () => { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     beforeEach(() => destroyPlatform()); | 
					
						
							|  |  |  |     afterEach(() => destroyPlatform()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     describe('template/templateUrl', () => { | 
					
						
							|  |  |  |       it('should support `template` (string)', async(() => { | 
					
						
							|  |  |  |            // Define `ng1Component`
 | 
					
						
							|  |  |  |            const ng1Component: angular.IComponent = {template: 'Hello, Angular!'}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng1ComponentFacade`
 | 
					
						
							|  |  |  |            @Directive({selector: 'ng1'}) | 
					
						
							|  |  |  |            class Ng1ComponentFacade extends UpgradeComponent { | 
					
						
							|  |  |  |              constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                super('ng1', elementRef, injector); | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Component`
 | 
					
						
							|  |  |  |            @Component({selector: 'ng2', template: '<ng1></ng1>'}) | 
					
						
							|  |  |  |            class Ng2Component { | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Module`
 | 
					
						
							|  |  |  |            const ng1Module = angular.module('ng1Module', []) | 
					
						
							|  |  |  |                                  .component('ng1', ng1Component) | 
					
						
							|  |  |  |                                  .directive('ng2', downgradeComponent({component: Ng2Component})); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Module`
 | 
					
						
							|  |  |  |            @NgModule({ | 
					
						
							|  |  |  |              declarations: [Ng1ComponentFacade, Ng2Component], | 
					
						
							|  |  |  |              entryComponents: [Ng2Component], | 
					
						
							|  |  |  |              imports: [BrowserModule, UpgradeModule] | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Module { | 
					
						
							|  |  |  |              ngDoBootstrap() {} | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Bootstrap
 | 
					
						
							|  |  |  |            const element = html(`<ng2></ng2>`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then((upgrade) => { | 
					
						
							|  |  |  |              expect(multiTrim(element.textContent)).toBe('Hello, Angular!'); | 
					
						
							|  |  |  |            }); | 
					
						
							|  |  |  |          })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should support `template` (function)', async(() => { | 
					
						
							|  |  |  |            // Define `ng1Component`
 | 
					
						
							|  |  |  |            const ng1Component: angular.IComponent = {template: () => 'Hello, Angular!'}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng1ComponentFacade`
 | 
					
						
							|  |  |  |            @Directive({selector: 'ng1'}) | 
					
						
							|  |  |  |            class Ng1ComponentFacade extends UpgradeComponent { | 
					
						
							|  |  |  |              constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                super('ng1', elementRef, injector); | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Component`
 | 
					
						
							|  |  |  |            @Component({selector: 'ng2', template: '<ng1></ng1>'}) | 
					
						
							|  |  |  |            class Ng2Component { | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Module`
 | 
					
						
							|  |  |  |            const ng1Module = angular.module('ng1Module', []) | 
					
						
							|  |  |  |                                  .component('ng1', ng1Component) | 
					
						
							|  |  |  |                                  .directive('ng2', downgradeComponent({component: Ng2Component})); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Module`
 | 
					
						
							|  |  |  |            @NgModule({ | 
					
						
							|  |  |  |              declarations: [Ng1ComponentFacade, Ng2Component], | 
					
						
							|  |  |  |              entryComponents: [Ng2Component], | 
					
						
							|  |  |  |              imports: [BrowserModule, UpgradeModule] | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Module { | 
					
						
							|  |  |  |              ngDoBootstrap() {} | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Bootstrap
 | 
					
						
							|  |  |  |            const element = html(`<ng2></ng2>`); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  |            bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(() => { | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  |              expect(multiTrim(element.textContent)).toBe('Hello, Angular!'); | 
					
						
							|  |  |  |            }); | 
					
						
							|  |  |  |          })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should support not pass any arguments to `template` function', async(() => { | 
					
						
							|  |  |  |            // Define `ng1Component`
 | 
					
						
							|  |  |  |            const ng1Component: angular.IComponent = { | 
					
						
							|  |  |  |              template: ($attrs: angular.IAttributes, $element: angular.IAugmentedJQuery) => { | 
					
						
							|  |  |  |                expect($attrs).toBeUndefined(); | 
					
						
							|  |  |  |                expect($element).toBeUndefined(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                return 'Hello, Angular!'; | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng1ComponentFacade`
 | 
					
						
							|  |  |  |            @Directive({selector: 'ng1'}) | 
					
						
							|  |  |  |            class Ng1ComponentFacade extends UpgradeComponent { | 
					
						
							|  |  |  |              constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                super('ng1', elementRef, injector); | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Component`
 | 
					
						
							|  |  |  |            @Component({selector: 'ng2', template: '<ng1></ng1>'}) | 
					
						
							|  |  |  |            class Ng2Component { | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Module`
 | 
					
						
							|  |  |  |            const ng1Module = angular.module('ng1Module', []) | 
					
						
							|  |  |  |                                  .component('ng1', ng1Component) | 
					
						
							|  |  |  |                                  .directive('ng2', downgradeComponent({component: Ng2Component})); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Module`
 | 
					
						
							|  |  |  |            @NgModule({ | 
					
						
							|  |  |  |              declarations: [Ng1ComponentFacade, Ng2Component], | 
					
						
							|  |  |  |              entryComponents: [Ng2Component], | 
					
						
							|  |  |  |              imports: [BrowserModule, UpgradeModule] | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Module { | 
					
						
							|  |  |  |              ngDoBootstrap() {} | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Bootstrap
 | 
					
						
							|  |  |  |            const element = html(`<ng2></ng2>`); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  |            bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(() => { | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  |              expect(multiTrim(element.textContent)).toBe('Hello, Angular!'); | 
					
						
							|  |  |  |            }); | 
					
						
							|  |  |  |          })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should support `templateUrl` (string) fetched from `$templateCache`', async(() => { | 
					
						
							|  |  |  |            // Define `ng1Component`
 | 
					
						
							|  |  |  |            const ng1Component: angular.IComponent = {templateUrl: 'ng1.component.html'}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng1ComponentFacade`
 | 
					
						
							|  |  |  |            @Directive({selector: 'ng1'}) | 
					
						
							|  |  |  |            class Ng1ComponentFacade extends UpgradeComponent { | 
					
						
							|  |  |  |              constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                super('ng1', elementRef, injector); | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Component`
 | 
					
						
							|  |  |  |            @Component({selector: 'ng2', template: '<ng1></ng1>'}) | 
					
						
							|  |  |  |            class Ng2Component { | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Module`
 | 
					
						
							|  |  |  |            const ng1Module = | 
					
						
							|  |  |  |                angular.module('ng1Module', []) | 
					
						
							|  |  |  |                    .component('ng1', ng1Component) | 
					
						
							|  |  |  |                    .directive('ng2', downgradeComponent({component: Ng2Component})) | 
					
						
							|  |  |  |                    .run( | 
					
						
							|  |  |  |                        ($templateCache: angular.ITemplateCacheService) => | 
					
						
							|  |  |  |                            $templateCache.put('ng1.component.html', 'Hello, Angular!')); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Module`
 | 
					
						
							|  |  |  |            @NgModule({ | 
					
						
							|  |  |  |              declarations: [Ng1ComponentFacade, Ng2Component], | 
					
						
							|  |  |  |              entryComponents: [Ng2Component], | 
					
						
							|  |  |  |              imports: [BrowserModule, UpgradeModule] | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Module { | 
					
						
							|  |  |  |              ngDoBootstrap() {} | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Bootstrap
 | 
					
						
							|  |  |  |            const element = html(`<ng2></ng2>`); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  |            bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(() => { | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  |              expect(multiTrim(element.textContent)).toBe('Hello, Angular!'); | 
					
						
							|  |  |  |            }); | 
					
						
							|  |  |  |          })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should support `templateUrl` (function) fetched from `$templateCache`', async(() => { | 
					
						
							|  |  |  |            // Define `ng1Component`
 | 
					
						
							|  |  |  |            const ng1Component: angular.IComponent = {templateUrl: () => 'ng1.component.html'}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng1ComponentFacade`
 | 
					
						
							|  |  |  |            @Directive({selector: 'ng1'}) | 
					
						
							|  |  |  |            class Ng1ComponentFacade extends UpgradeComponent { | 
					
						
							|  |  |  |              constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                super('ng1', elementRef, injector); | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Component`
 | 
					
						
							|  |  |  |            @Component({selector: 'ng2', template: '<ng1></ng1>'}) | 
					
						
							|  |  |  |            class Ng2Component { | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Module`
 | 
					
						
							|  |  |  |            const ng1Module = | 
					
						
							|  |  |  |                angular.module('ng1Module', []) | 
					
						
							|  |  |  |                    .component('ng1', ng1Component) | 
					
						
							|  |  |  |                    .directive('ng2', downgradeComponent({component: Ng2Component})) | 
					
						
							|  |  |  |                    .run( | 
					
						
							|  |  |  |                        ($templateCache: angular.ITemplateCacheService) => | 
					
						
							|  |  |  |                            $templateCache.put('ng1.component.html', 'Hello, Angular!')); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Module`
 | 
					
						
							|  |  |  |            @NgModule({ | 
					
						
							|  |  |  |              declarations: [Ng1ComponentFacade, Ng2Component], | 
					
						
							|  |  |  |              entryComponents: [Ng2Component], | 
					
						
							|  |  |  |              imports: [BrowserModule, UpgradeModule] | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Module { | 
					
						
							|  |  |  |              ngDoBootstrap() {} | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Bootstrap
 | 
					
						
							|  |  |  |            const element = html(`<ng2></ng2>`); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  |            bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(() => { | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  |              expect(multiTrim(element.textContent)).toBe('Hello, Angular!'); | 
					
						
							|  |  |  |            }); | 
					
						
							|  |  |  |          })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should support not pass any arguments to `templateUrl` function', async(() => { | 
					
						
							|  |  |  |            // Define `ng1Component`
 | 
					
						
							|  |  |  |            const ng1Component: angular.IComponent = { | 
					
						
							|  |  |  |              templateUrl: ($attrs: angular.IAttributes, $element: angular.IAugmentedJQuery) => { | 
					
						
							|  |  |  |                expect($attrs).toBeUndefined(); | 
					
						
							|  |  |  |                expect($element).toBeUndefined(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                return 'ng1.component.html'; | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng1ComponentFacade`
 | 
					
						
							|  |  |  |            @Directive({selector: 'ng1'}) | 
					
						
							|  |  |  |            class Ng1ComponentFacade extends UpgradeComponent { | 
					
						
							|  |  |  |              constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                super('ng1', elementRef, injector); | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Component`
 | 
					
						
							|  |  |  |            @Component({selector: 'ng2', template: '<ng1></ng1>'}) | 
					
						
							|  |  |  |            class Ng2Component { | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Module`
 | 
					
						
							|  |  |  |            const ng1Module = | 
					
						
							|  |  |  |                angular.module('ng1Module', []) | 
					
						
							|  |  |  |                    .component('ng1', ng1Component) | 
					
						
							|  |  |  |                    .directive('ng2', downgradeComponent({component: Ng2Component})) | 
					
						
							|  |  |  |                    .run( | 
					
						
							|  |  |  |                        ($templateCache: angular.ITemplateCacheService) => | 
					
						
							|  |  |  |                            $templateCache.put('ng1.component.html', 'Hello, Angular!')); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Module`
 | 
					
						
							|  |  |  |            @NgModule({ | 
					
						
							|  |  |  |              declarations: [Ng1ComponentFacade, Ng2Component], | 
					
						
							|  |  |  |              entryComponents: [Ng2Component], | 
					
						
							|  |  |  |              imports: [BrowserModule, UpgradeModule] | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Module { | 
					
						
							|  |  |  |              ngDoBootstrap() {} | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Bootstrap
 | 
					
						
							|  |  |  |            const element = html(`<ng2></ng2>`); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  |            bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(() => { | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  |              expect(multiTrim(element.textContent)).toBe('Hello, Angular!'); | 
					
						
							|  |  |  |            }); | 
					
						
							|  |  |  |          })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // NOT SUPPORTED YET
 | 
					
						
							|  |  |  |       xit('should support `templateUrl` (string) fetched from the server', fakeAsync(() => { | 
					
						
							|  |  |  |             // Define `ng1Component`
 | 
					
						
							|  |  |  |             const ng1Component: angular.IComponent = {templateUrl: 'ng1.component.html'}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // Define `Ng1ComponentFacade`
 | 
					
						
							|  |  |  |             @Directive({selector: 'ng1'}) | 
					
						
							|  |  |  |             class Ng1ComponentFacade extends UpgradeComponent { | 
					
						
							|  |  |  |               constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                 super('ng1', elementRef, injector); | 
					
						
							|  |  |  |               } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // Define `Ng2Component`
 | 
					
						
							|  |  |  |             @Component({selector: 'ng2', template: '<ng1></ng1>'}) | 
					
						
							|  |  |  |             class Ng2Component { | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // Define `ng1Module`
 | 
					
						
							|  |  |  |             const ng1Module = | 
					
						
							|  |  |  |                 angular.module('ng1Module', []) | 
					
						
							|  |  |  |                     .component('ng1', ng1Component) | 
					
						
							|  |  |  |                     .directive('ng2', downgradeComponent({component: Ng2Component})) | 
					
						
							|  |  |  |                     .value( | 
					
						
							|  |  |  |                         '$httpBackend', | 
					
						
							|  |  |  |                         (method: string, url: string, post?: any, callback?: Function) => | 
					
						
							|  |  |  |                             setTimeout( | 
					
						
							| 
									
										
										
										
											2017-03-24 09:59:18 -07:00
										 |  |  |                                 () => callback !(200, `${method}:${url}`.toLowerCase()), 1000)); | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |             // Define `Ng2Module`
 | 
					
						
							|  |  |  |             @NgModule({ | 
					
						
							|  |  |  |               declarations: [Ng1ComponentFacade, Ng2Component], | 
					
						
							|  |  |  |               entryComponents: [Ng2Component], | 
					
						
							|  |  |  |               imports: [BrowserModule, UpgradeModule] | 
					
						
							|  |  |  |             }) | 
					
						
							|  |  |  |             class Ng2Module { | 
					
						
							|  |  |  |               ngDoBootstrap() {} | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // Bootstrap
 | 
					
						
							|  |  |  |             const element = html(`<ng2></ng2>`); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  |             bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(() => { | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  |               tick(500); | 
					
						
							|  |  |  |               expect(multiTrim(element.textContent)).toBe(''); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |               tick(500); | 
					
						
							|  |  |  |               expect(multiTrim(element.textContent)).toBe('get:ng1.component.html'); | 
					
						
							|  |  |  |             }); | 
					
						
							|  |  |  |           })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // NOT SUPPORTED YET
 | 
					
						
							|  |  |  |       xit('should support `templateUrl` (function) fetched from the server', fakeAsync(() => { | 
					
						
							|  |  |  |             // Define `ng1Component`
 | 
					
						
							|  |  |  |             const ng1Component: angular.IComponent = {templateUrl: () => 'ng1.component.html'}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // Define `Ng1ComponentFacade`
 | 
					
						
							|  |  |  |             @Directive({selector: 'ng1'}) | 
					
						
							|  |  |  |             class Ng1ComponentFacade extends UpgradeComponent { | 
					
						
							|  |  |  |               constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                 super('ng1', elementRef, injector); | 
					
						
							|  |  |  |               } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // Define `Ng2Component`
 | 
					
						
							|  |  |  |             @Component({selector: 'ng2', template: '<ng1></ng1>'}) | 
					
						
							|  |  |  |             class Ng2Component { | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // Define `ng1Module`
 | 
					
						
							|  |  |  |             const ng1Module = | 
					
						
							|  |  |  |                 angular.module('ng1Module', []) | 
					
						
							|  |  |  |                     .component('ng1', ng1Component) | 
					
						
							|  |  |  |                     .directive('ng2', downgradeComponent({component: Ng2Component})) | 
					
						
							|  |  |  |                     .value( | 
					
						
							|  |  |  |                         '$httpBackend', | 
					
						
							|  |  |  |                         (method: string, url: string, post?: any, callback?: Function) => | 
					
						
							|  |  |  |                             setTimeout( | 
					
						
							| 
									
										
										
										
											2017-03-24 09:59:18 -07:00
										 |  |  |                                 () => callback !(200, `${method}:${url}`.toLowerCase()), 1000)); | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |             // Define `Ng2Module`
 | 
					
						
							|  |  |  |             @NgModule({ | 
					
						
							|  |  |  |               declarations: [Ng1ComponentFacade, Ng2Component], | 
					
						
							|  |  |  |               entryComponents: [Ng2Component], | 
					
						
							|  |  |  |               imports: [BrowserModule, UpgradeModule] | 
					
						
							|  |  |  |             }) | 
					
						
							|  |  |  |             class Ng2Module { | 
					
						
							|  |  |  |               ngDoBootstrap() {} | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // Bootstrap
 | 
					
						
							|  |  |  |             const element = html(`<ng2></ng2>`); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  |             bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(() => { | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  |               tick(500); | 
					
						
							|  |  |  |               expect(multiTrim(element.textContent)).toBe(''); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |               tick(500); | 
					
						
							|  |  |  |               expect(multiTrim(element.textContent)).toBe('get:ng1.component.html'); | 
					
						
							|  |  |  |             }); | 
					
						
							|  |  |  |           })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should support empty templates', async(() => { | 
					
						
							|  |  |  |            // Define `ng1Component`s
 | 
					
						
							|  |  |  |            const ng1ComponentA: angular.IComponent = {template: ''}; | 
					
						
							|  |  |  |            const ng1ComponentB: angular.IComponent = {template: () => ''}; | 
					
						
							|  |  |  |            const ng1ComponentC: angular.IComponent = {templateUrl: 'ng1.component.html'}; | 
					
						
							|  |  |  |            const ng1ComponentD: angular.IComponent = {templateUrl: () => 'ng1.component.html'}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng1ComponentFacade`s
 | 
					
						
							|  |  |  |            @Directive({selector: 'ng1A'}) | 
					
						
							|  |  |  |            class Ng1ComponentAFacade extends UpgradeComponent { | 
					
						
							|  |  |  |              constructor(e: ElementRef, i: Injector) { super('ng1A', e, i); } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  |            @Directive({selector: 'ng1B'}) | 
					
						
							|  |  |  |            class Ng1ComponentBFacade extends UpgradeComponent { | 
					
						
							|  |  |  |              constructor(e: ElementRef, i: Injector) { super('ng1B', e, i); } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  |            @Directive({selector: 'ng1C'}) | 
					
						
							|  |  |  |            class Ng1ComponentCFacade extends UpgradeComponent { | 
					
						
							|  |  |  |              constructor(e: ElementRef, i: Injector) { super('ng1C', e, i); } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  |            @Directive({selector: 'ng1D'}) | 
					
						
							|  |  |  |            class Ng1ComponentDFacade extends UpgradeComponent { | 
					
						
							|  |  |  |              constructor(e: ElementRef, i: Injector) { super('ng1D', e, i); } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Component`
 | 
					
						
							|  |  |  |            @Component({ | 
					
						
							|  |  |  |              selector: 'ng2', | 
					
						
							|  |  |  |              template: `
 | 
					
						
							|  |  |  |                <ng1A>Ignore this</ng1A> | 
					
						
							|  |  |  |                <ng1B>Ignore this</ng1B> | 
					
						
							|  |  |  |                <ng1C>Ignore this</ng1C> | 
					
						
							|  |  |  |                <ng1D>Ignore this</ng1D> | 
					
						
							|  |  |  |              `
 | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Component { | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Module`
 | 
					
						
							|  |  |  |            const ng1Module = angular.module('ng1Module', []) | 
					
						
							|  |  |  |                                  .component('ng1A', ng1ComponentA) | 
					
						
							|  |  |  |                                  .component('ng1B', ng1ComponentB) | 
					
						
							|  |  |  |                                  .component('ng1C', ng1ComponentC) | 
					
						
							|  |  |  |                                  .component('ng1D', ng1ComponentD) | 
					
						
							|  |  |  |                                  .directive('ng2', downgradeComponent({component: Ng2Component})) | 
					
						
							|  |  |  |                                  .run( | 
					
						
							|  |  |  |                                      ($templateCache: angular.ITemplateCacheService) => | 
					
						
							|  |  |  |                                          $templateCache.put('ng1.component.html', '')); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Module`
 | 
					
						
							|  |  |  |            @NgModule({ | 
					
						
							|  |  |  |              declarations: [ | 
					
						
							|  |  |  |                Ng1ComponentAFacade, Ng1ComponentBFacade, Ng1ComponentCFacade, Ng1ComponentDFacade, | 
					
						
							|  |  |  |                Ng2Component | 
					
						
							|  |  |  |              ], | 
					
						
							|  |  |  |              entryComponents: [Ng2Component], | 
					
						
							|  |  |  |              imports: [BrowserModule, UpgradeModule], | 
					
						
							|  |  |  |              schemas: [NO_ERRORS_SCHEMA] | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Module { | 
					
						
							|  |  |  |              ngDoBootstrap() {} | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Bootstrap
 | 
					
						
							|  |  |  |            const element = html(`<ng2></ng2>`); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  |            bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(() => { | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  |              expect(multiTrim(element.textContent)).toBe(''); | 
					
						
							|  |  |  |            }); | 
					
						
							|  |  |  |          })); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     describe('bindings', () => { | 
					
						
							|  |  |  |       it('should support `@` bindings', fakeAsync(() => { | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  |            let ng2ComponentInstance: Ng2Component; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  |            // Define `ng1Component`
 | 
					
						
							|  |  |  |            const ng1Component: angular.IComponent = { | 
					
						
							|  |  |  |              template: 'Inside: {{ $ctrl.inputA }}, {{ $ctrl.inputB }}', | 
					
						
							|  |  |  |              bindings: {inputA: '@inputAttrA', inputB: '@'} | 
					
						
							|  |  |  |            }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng1ComponentFacade`
 | 
					
						
							|  |  |  |            @Directive({selector: 'ng1'}) | 
					
						
							|  |  |  |            class Ng1ComponentFacade extends UpgradeComponent { | 
					
						
							| 
									
										
										
										
											2018-06-18 16:38:33 -07:00
										 |  |  |              // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |              @Input('inputAttrA') inputA !: string; | 
					
						
							|  |  |  |              // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |              @Input() inputB !: string; | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |              constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                super('ng1', elementRef, injector); | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Component`
 | 
					
						
							|  |  |  |            @Component({ | 
					
						
							|  |  |  |              selector: 'ng2', | 
					
						
							|  |  |  |              template: `
 | 
					
						
							|  |  |  |                <ng1 inputAttrA="{{ dataA }}" inputB="{{ dataB }}"></ng1> | 
					
						
							|  |  |  |                | Outside: {{ dataA }}, {{ dataB }} | 
					
						
							|  |  |  |              `
 | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Component { | 
					
						
							|  |  |  |              dataA = 'foo'; | 
					
						
							|  |  |  |              dataB = 'bar'; | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |              constructor() { ng2ComponentInstance = this; } | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Module`
 | 
					
						
							|  |  |  |            const ng1Module = angular.module('ng1Module', []) | 
					
						
							|  |  |  |                                  .component('ng1', ng1Component) | 
					
						
							|  |  |  |                                  .directive('ng2', downgradeComponent({component: Ng2Component})); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Module`
 | 
					
						
							|  |  |  |            @NgModule({ | 
					
						
							|  |  |  |              declarations: [Ng1ComponentFacade, Ng2Component], | 
					
						
							|  |  |  |              entryComponents: [Ng2Component], | 
					
						
							|  |  |  |              imports: [BrowserModule, UpgradeModule] | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Module { | 
					
						
							|  |  |  |              ngDoBootstrap() {} | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Bootstrap
 | 
					
						
							|  |  |  |            const element = html(`<ng2></ng2>`); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  |            bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(adapter => { | 
					
						
							| 
									
										
										
										
											2017-03-24 09:59:18 -07:00
										 |  |  |              const ng1 = element.querySelector('ng1') !; | 
					
						
							|  |  |  |              const ng1Controller = angular.element(ng1).controller !('ng1'); | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |              expect(multiTrim(element.textContent)).toBe('Inside: foo, bar | Outside: foo, bar'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              ng1Controller.inputA = 'baz'; | 
					
						
							|  |  |  |              ng1Controller.inputB = 'qux'; | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(multiTrim(element.textContent)).toBe('Inside: baz, qux | Outside: foo, bar'); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  |              ng2ComponentInstance.dataA = 'foo2'; | 
					
						
							|  |  |  |              ng2ComponentInstance.dataB = 'bar2'; | 
					
						
							| 
									
										
										
										
											2017-02-04 17:19:09 +02:00
										 |  |  |              $digest(adapter); | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(multiTrim(element.textContent)) | 
					
						
							|  |  |  |                  .toBe('Inside: foo2, bar2 | Outside: foo2, bar2'); | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  |            }); | 
					
						
							|  |  |  |          })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should support `<` bindings', fakeAsync(() => { | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  |            let ng2ComponentInstance: Ng2Component; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  |            // Define `ng1Component`
 | 
					
						
							|  |  |  |            const ng1Component: angular.IComponent = { | 
					
						
							|  |  |  |              template: 'Inside: {{ $ctrl.inputA.value }}, {{ $ctrl.inputB.value }}', | 
					
						
							|  |  |  |              bindings: {inputA: '<inputAttrA', inputB: '<'} | 
					
						
							|  |  |  |            }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng1ComponentFacade`
 | 
					
						
							|  |  |  |            @Directive({selector: 'ng1'}) | 
					
						
							|  |  |  |            class Ng1ComponentFacade extends UpgradeComponent { | 
					
						
							| 
									
										
										
										
											2018-06-18 16:38:33 -07:00
										 |  |  |              // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |              @Input('inputAttrA') inputA !: string; | 
					
						
							|  |  |  |              // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |              @Input() inputB !: string; | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |              constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                super('ng1', elementRef, injector); | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Component`
 | 
					
						
							|  |  |  |            @Component({ | 
					
						
							|  |  |  |              selector: 'ng2', | 
					
						
							|  |  |  |              template: `
 | 
					
						
							|  |  |  |                <ng1 [inputAttrA]="dataA" [inputB]="dataB"></ng1> | 
					
						
							|  |  |  |                | Outside: {{ dataA.value }}, {{ dataB.value }} | 
					
						
							|  |  |  |              `
 | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Component { | 
					
						
							|  |  |  |              dataA = {value: 'foo'}; | 
					
						
							|  |  |  |              dataB = {value: 'bar'}; | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |              constructor() { ng2ComponentInstance = this; } | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Module`
 | 
					
						
							|  |  |  |            const ng1Module = angular.module('ng1Module', []) | 
					
						
							|  |  |  |                                  .component('ng1', ng1Component) | 
					
						
							|  |  |  |                                  .directive('ng2', downgradeComponent({component: Ng2Component})); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Module`
 | 
					
						
							|  |  |  |            @NgModule({ | 
					
						
							|  |  |  |              declarations: [Ng1ComponentFacade, Ng2Component], | 
					
						
							|  |  |  |              entryComponents: [Ng2Component], | 
					
						
							|  |  |  |              imports: [BrowserModule, UpgradeModule] | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Module { | 
					
						
							|  |  |  |              ngDoBootstrap() {} | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Bootstrap
 | 
					
						
							|  |  |  |            const element = html(`<ng2></ng2>`); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  |            bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(adapter => { | 
					
						
							| 
									
										
										
										
											2017-03-24 09:59:18 -07:00
										 |  |  |              const ng1 = element.querySelector('ng1') !; | 
					
						
							|  |  |  |              const ng1Controller = angular.element(ng1).controller !('ng1'); | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |              expect(multiTrim(element.textContent)).toBe('Inside: foo, bar | Outside: foo, bar'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              ng1Controller.inputA = {value: 'baz'}; | 
					
						
							|  |  |  |              ng1Controller.inputB = {value: 'qux'}; | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(multiTrim(element.textContent)).toBe('Inside: baz, qux | Outside: foo, bar'); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  |              ng2ComponentInstance.dataA = {value: 'foo2'}; | 
					
						
							|  |  |  |              ng2ComponentInstance.dataB = {value: 'bar2'}; | 
					
						
							| 
									
										
										
										
											2017-02-04 17:19:09 +02:00
										 |  |  |              $digest(adapter); | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(multiTrim(element.textContent)) | 
					
						
							|  |  |  |                  .toBe('Inside: foo2, bar2 | Outside: foo2, bar2'); | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  |            }); | 
					
						
							|  |  |  |          })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should support `=` bindings', fakeAsync(() => { | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  |            let ng2ComponentInstance: Ng2Component; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  |            // Define `ng1Component`
 | 
					
						
							|  |  |  |            const ng1Component: angular.IComponent = { | 
					
						
							|  |  |  |              template: 'Inside: {{ $ctrl.inputA.value }}, {{ $ctrl.inputB.value }}', | 
					
						
							|  |  |  |              bindings: {inputA: '=inputAttrA', inputB: '='} | 
					
						
							|  |  |  |            }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng1ComponentFacade`
 | 
					
						
							|  |  |  |            @Directive({selector: 'ng1'}) | 
					
						
							|  |  |  |            class Ng1ComponentFacade extends UpgradeComponent { | 
					
						
							| 
									
										
										
										
											2018-06-18 16:38:33 -07:00
										 |  |  |              // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |              @Input('inputAttrA') inputA !: string; | 
					
						
							|  |  |  |              // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |              @Output('inputAttrAChange') inputAChange !: EventEmitter<any>; | 
					
						
							|  |  |  |              // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |              @Input() inputB !: string; | 
					
						
							|  |  |  |              // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |              @Output() inputBChange !: EventEmitter<any>; | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |              constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                super('ng1', elementRef, injector); | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Component`
 | 
					
						
							|  |  |  |            @Component({ | 
					
						
							|  |  |  |              selector: 'ng2', | 
					
						
							|  |  |  |              template: `
 | 
					
						
							|  |  |  |                <ng1 [(inputAttrA)]="dataA" [(inputB)]="dataB"></ng1> | 
					
						
							|  |  |  |                | Outside: {{ dataA.value }}, {{ dataB.value }} | 
					
						
							|  |  |  |              `
 | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Component { | 
					
						
							|  |  |  |              dataA = {value: 'foo'}; | 
					
						
							|  |  |  |              dataB = {value: 'bar'}; | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |              constructor() { ng2ComponentInstance = this; } | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Module`
 | 
					
						
							|  |  |  |            const ng1Module = angular.module('ng1Module', []) | 
					
						
							|  |  |  |                                  .component('ng1', ng1Component) | 
					
						
							|  |  |  |                                  .directive('ng2', downgradeComponent({component: Ng2Component})); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Module`
 | 
					
						
							|  |  |  |            @NgModule({ | 
					
						
							|  |  |  |              declarations: [Ng1ComponentFacade, Ng2Component], | 
					
						
							|  |  |  |              entryComponents: [Ng2Component], | 
					
						
							|  |  |  |              imports: [BrowserModule, UpgradeModule] | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Module { | 
					
						
							|  |  |  |              ngDoBootstrap() {} | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Bootstrap
 | 
					
						
							|  |  |  |            const element = html(`<ng2></ng2>`); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  |            bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(adapter => { | 
					
						
							| 
									
										
										
										
											2017-03-24 09:59:18 -07:00
										 |  |  |              const ng1 = element.querySelector('ng1') !; | 
					
						
							|  |  |  |              const ng1Controller = angular.element(ng1).controller !('ng1'); | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |              expect(multiTrim(element.textContent)).toBe('Inside: foo, bar | Outside: foo, bar'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              ng1Controller.inputA = {value: 'baz'}; | 
					
						
							|  |  |  |              ng1Controller.inputB = {value: 'qux'}; | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(multiTrim(element.textContent)).toBe('Inside: baz, qux | Outside: baz, qux'); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  |              ng2ComponentInstance.dataA = {value: 'foo2'}; | 
					
						
							|  |  |  |              ng2ComponentInstance.dataB = {value: 'bar2'}; | 
					
						
							| 
									
										
										
										
											2017-02-04 17:19:09 +02:00
										 |  |  |              $digest(adapter); | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(multiTrim(element.textContent)) | 
					
						
							|  |  |  |                  .toBe('Inside: foo2, bar2 | Outside: foo2, bar2'); | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  |            }); | 
					
						
							|  |  |  |          })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should support `&` bindings', fakeAsync(() => { | 
					
						
							|  |  |  |            // Define `ng1Component`
 | 
					
						
							|  |  |  |            const ng1Component: angular.IComponent = { | 
					
						
							|  |  |  |              template: 'Inside: -', | 
					
						
							|  |  |  |              bindings: {outputA: '&outputAttrA', outputB: '&'} | 
					
						
							|  |  |  |            }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng1ComponentFacade`
 | 
					
						
							|  |  |  |            @Directive({selector: 'ng1'}) | 
					
						
							|  |  |  |            class Ng1ComponentFacade extends UpgradeComponent { | 
					
						
							| 
									
										
										
										
											2018-06-18 16:38:33 -07:00
										 |  |  |              // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |              @Output('outputAttrA') outputA !: EventEmitter<any>; | 
					
						
							|  |  |  |              // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |              @Output() outputB !: EventEmitter<any>; | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |              constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                super('ng1', elementRef, injector); | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Component`
 | 
					
						
							|  |  |  |            @Component({ | 
					
						
							|  |  |  |              selector: 'ng2', | 
					
						
							|  |  |  |              template: `
 | 
					
						
							|  |  |  |                <ng1 (outputAttrA)="dataA = $event" (outputB)="dataB = $event"></ng1> | 
					
						
							|  |  |  |                | Outside: {{ dataA }}, {{ dataB }} | 
					
						
							|  |  |  |              `
 | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Component { | 
					
						
							|  |  |  |              dataA = 'foo'; | 
					
						
							|  |  |  |              dataB = 'bar'; | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Module`
 | 
					
						
							|  |  |  |            const ng1Module = angular.module('ng1Module', []) | 
					
						
							|  |  |  |                                  .component('ng1', ng1Component) | 
					
						
							|  |  |  |                                  .directive('ng2', downgradeComponent({component: Ng2Component})); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Module`
 | 
					
						
							|  |  |  |            @NgModule({ | 
					
						
							|  |  |  |              declarations: [Ng1ComponentFacade, Ng2Component], | 
					
						
							|  |  |  |              entryComponents: [Ng2Component], | 
					
						
							|  |  |  |              imports: [BrowserModule, UpgradeModule] | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Module { | 
					
						
							|  |  |  |              ngDoBootstrap() {} | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Bootstrap
 | 
					
						
							|  |  |  |            const element = html(`<ng2></ng2>`); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  |            bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(() => { | 
					
						
							| 
									
										
										
										
											2017-03-24 09:59:18 -07:00
										 |  |  |              const ng1 = element.querySelector('ng1') !; | 
					
						
							|  |  |  |              const ng1Controller = angular.element(ng1).controller !('ng1'); | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |              expect(multiTrim(element.textContent)).toBe('Inside: - | Outside: foo, bar'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              ng1Controller.outputA('baz'); | 
					
						
							|  |  |  |              ng1Controller.outputB('qux'); | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(multiTrim(element.textContent)).toBe('Inside: - | Outside: baz, qux'); | 
					
						
							|  |  |  |            }); | 
					
						
							|  |  |  |          })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should bind properties, events', fakeAsync(() => { | 
					
						
							|  |  |  |            // Define `ng1Component`
 | 
					
						
							|  |  |  |            const ng1Component: angular.IComponent = { | 
					
						
							|  |  |  |              template: `
 | 
					
						
							|  |  |  |                Hello {{ $ctrl.fullName }}; | 
					
						
							|  |  |  |                A: {{ $ctrl.modelA }}; | 
					
						
							|  |  |  |                B: {{ $ctrl.modelB }}; | 
					
						
							|  |  |  |                C: {{ $ctrl.modelC }} | 
					
						
							|  |  |  |              `,
 | 
					
						
							|  |  |  |              bindings: {fullName: '@', modelA: '<dataA', modelB: '=dataB', modelC: '=', event: '&'}, | 
					
						
							|  |  |  |              controller: function($scope: angular.IScope) { | 
					
						
							|  |  |  |                $scope.$watch('$ctrl.modelB', (v: string) => { | 
					
						
							|  |  |  |                  if (v === 'Savkin') { | 
					
						
							|  |  |  |                    this.modelB = 'SAVKIN'; | 
					
						
							|  |  |  |                    this.event('WORKS'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                    // Should not update because `modelA: '<dataA'` is uni-directional.
 | 
					
						
							|  |  |  |                    this.modelA = 'VICTOR'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                    // Should not update because `[modelC]` is uni-directional.
 | 
					
						
							|  |  |  |                    this.modelC = 'sf'; | 
					
						
							|  |  |  |                  } | 
					
						
							|  |  |  |                }); | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng1ComponentFacade`
 | 
					
						
							|  |  |  |            @Directive({selector: 'ng1'}) | 
					
						
							|  |  |  |            class Ng1ComponentFacade extends UpgradeComponent { | 
					
						
							| 
									
										
										
										
											2018-06-18 16:38:33 -07:00
										 |  |  |              // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |              @Input() fullName !: string; | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  |              @Input('dataA') modelA: any; | 
					
						
							|  |  |  |              @Input('dataB') modelB: any; | 
					
						
							| 
									
										
										
										
											2018-06-18 16:38:33 -07:00
										 |  |  |              // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |              @Output('dataBChange') modelBChange !: EventEmitter<any>; | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  |              @Input() modelC: any; | 
					
						
							| 
									
										
										
										
											2018-06-18 16:38:33 -07:00
										 |  |  |              // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |              @Output() modelCChange !: EventEmitter<any>; | 
					
						
							|  |  |  |              // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |              @Output() event !: EventEmitter<any>; | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |              constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                super('ng1', elementRef, injector); | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Component`
 | 
					
						
							|  |  |  |            @Component({ | 
					
						
							|  |  |  |              selector: 'ng2', | 
					
						
							|  |  |  |              template: `
 | 
					
						
							|  |  |  |                <ng1 fullName="{{ last }}, {{ first }}, {{ city }}" | 
					
						
							|  |  |  |                    [(dataA)]="first" [(dataB)]="last" [modelC]="city" | 
					
						
							|  |  |  |                    (event)="event = $event"> | 
					
						
							|  |  |  |                </ng1> | | 
					
						
							|  |  |  |                <ng1 fullName="{{ 'TEST' }}" dataA="First" dataB="Last" modelC="City"></ng1> | | 
					
						
							|  |  |  |                {{ event }} - {{ last }}, {{ first }}, {{ city }} | 
					
						
							|  |  |  |              `
 | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Component { | 
					
						
							|  |  |  |              first = 'Victor'; | 
					
						
							|  |  |  |              last = 'Savkin'; | 
					
						
							|  |  |  |              city = 'SF'; | 
					
						
							|  |  |  |              event = '?'; | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Module`
 | 
					
						
							|  |  |  |            const ng1Module = angular.module('ng1Module', []) | 
					
						
							|  |  |  |                                  .component('ng1', ng1Component) | 
					
						
							|  |  |  |                                  .directive('ng2', downgradeComponent({component: Ng2Component})); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Module`
 | 
					
						
							|  |  |  |            @NgModule({ | 
					
						
							|  |  |  |              declarations: [Ng1ComponentFacade, Ng2Component], | 
					
						
							|  |  |  |              entryComponents: [Ng2Component], | 
					
						
							|  |  |  |              imports: [BrowserModule, UpgradeModule] | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Module { | 
					
						
							|  |  |  |              ngDoBootstrap() {} | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Bootstrap
 | 
					
						
							|  |  |  |            const element = html(`<ng2></ng2>`); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  |            bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(() => { | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  |              expect(multiTrim(element.textContent)) | 
					
						
							|  |  |  |                  .toBe( | 
					
						
							|  |  |  |                      'Hello Savkin, Victor, SF; A: VICTOR; B: SAVKIN; C: sf | ' + | 
					
						
							|  |  |  |                      'Hello TEST; A: First; B: Last; C: City | ' + | 
					
						
							|  |  |  |                      'WORKS - SAVKIN, Victor, SF'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              // Detect changes
 | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(multiTrim(element.textContent)) | 
					
						
							|  |  |  |                  .toBe( | 
					
						
							|  |  |  |                      'Hello SAVKIN, Victor, SF; A: VICTOR; B: SAVKIN; C: sf | ' + | 
					
						
							|  |  |  |                      'Hello TEST; A: First; B: Last; C: City | ' + | 
					
						
							|  |  |  |                      'WORKS - SAVKIN, Victor, SF'); | 
					
						
							|  |  |  |            }); | 
					
						
							|  |  |  |          })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should bind optional properties', fakeAsync(() => { | 
					
						
							|  |  |  |            // Define `ng1Component`
 | 
					
						
							|  |  |  |            const ng1Component: angular.IComponent = { | 
					
						
							|  |  |  |              template: 'Inside: {{ $ctrl.inputA.value }}, {{ $ctrl.inputB }}', | 
					
						
							|  |  |  |              bindings: | 
					
						
							|  |  |  |                  {inputA: '=?inputAttrA', inputB: '=?', outputA: '&?outputAttrA', outputB: '&?'} | 
					
						
							|  |  |  |            }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng1ComponentFacade`
 | 
					
						
							|  |  |  |            @Directive({selector: 'ng1'}) | 
					
						
							|  |  |  |            class Ng1ComponentFacade extends UpgradeComponent { | 
					
						
							| 
									
										
										
										
											2018-06-18 16:38:33 -07:00
										 |  |  |              // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |              @Input('inputAttrA') inputA !: string; | 
					
						
							|  |  |  |              // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |              @Output('inputAttrAChange') inputAChange !: EventEmitter<any>; | 
					
						
							|  |  |  |              // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |              @Input() inputB !: string; | 
					
						
							|  |  |  |              // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |              @Output() inputBChange !: EventEmitter<any>; | 
					
						
							|  |  |  |              // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |              @Output('outputAttrA') outputA !: EventEmitter<any>; | 
					
						
							|  |  |  |              // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |              @Output() outputB !: EventEmitter<any>; | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |              constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                super('ng1', elementRef, injector); | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Component`
 | 
					
						
							|  |  |  |            @Component({ | 
					
						
							|  |  |  |              selector: 'ng2', | 
					
						
							|  |  |  |              template: `
 | 
					
						
							|  |  |  |                <ng1 [(inputAttrA)]="dataA" [(inputB)]="dataB.value"></ng1> | | 
					
						
							|  |  |  |                <ng1 inputB="Bar" (outputAttrA)="dataA = $event"></ng1> | | 
					
						
							|  |  |  |                <ng1 (outputB)="updateDataB($event)"></ng1> | | 
					
						
							|  |  |  |                <ng1></ng1> | | 
					
						
							|  |  |  |                Outside: {{ dataA.value }}, {{ dataB.value }} | 
					
						
							|  |  |  |              `
 | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Component { | 
					
						
							|  |  |  |              dataA = {value: 'foo'}; | 
					
						
							|  |  |  |              dataB = {value: 'bar'}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              updateDataB(value: any) { this.dataB.value = value; } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Module`
 | 
					
						
							|  |  |  |            const ng1Module = angular.module('ng1Module', []) | 
					
						
							|  |  |  |                                  .component('ng1', ng1Component) | 
					
						
							|  |  |  |                                  .directive('ng2', downgradeComponent({component: Ng2Component})); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Module`
 | 
					
						
							|  |  |  |            @NgModule({ | 
					
						
							|  |  |  |              declarations: [Ng1ComponentFacade, Ng2Component], | 
					
						
							|  |  |  |              entryComponents: [Ng2Component], | 
					
						
							|  |  |  |              imports: [BrowserModule, UpgradeModule] | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Module { | 
					
						
							|  |  |  |              ngDoBootstrap() {} | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Bootstrap
 | 
					
						
							|  |  |  |            const element = html(`<ng2></ng2>`); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  |            bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(adapter => { | 
					
						
							| 
									
										
										
										
											2017-03-24 09:59:18 -07:00
										 |  |  |              const ng1s = element.querySelectorAll('ng1') !; | 
					
						
							|  |  |  |              const ng1Controller0 = angular.element(ng1s[0]).controller !('ng1'); | 
					
						
							|  |  |  |              const ng1Controller1 = angular.element(ng1s[1]).controller !('ng1'); | 
					
						
							|  |  |  |              const ng1Controller2 = angular.element(ng1s[2]).controller !('ng1'); | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |              expect(multiTrim(element.textContent)) | 
					
						
							|  |  |  |                  .toBe( | 
					
						
							|  |  |  |                      'Inside: foo, bar | Inside: , Bar | Inside: , | Inside: , | Outside: foo, bar'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              ng1Controller0.inputA.value = 'baz'; | 
					
						
							|  |  |  |              ng1Controller0.inputB = 'qux'; | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(multiTrim(element.textContent)) | 
					
						
							|  |  |  |                  .toBe( | 
					
						
							|  |  |  |                      'Inside: baz, qux | Inside: , Bar | Inside: , | Inside: , | Outside: baz, qux'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              ng1Controller1.outputA({value: 'foo again'}); | 
					
						
							|  |  |  |              ng1Controller2.outputB('bar again'); | 
					
						
							| 
									
										
										
										
											2017-02-04 17:19:09 +02:00
										 |  |  |              $digest(adapter); | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(ng1Controller0.inputA).toEqual({value: 'foo again'}); | 
					
						
							|  |  |  |              expect(ng1Controller0.inputB).toEqual('bar again'); | 
					
						
							|  |  |  |              expect(multiTrim(element.textContent)) | 
					
						
							|  |  |  |                  .toBe( | 
					
						
							|  |  |  |                      'Inside: foo again, bar again | Inside: , Bar | Inside: , | Inside: , | ' + | 
					
						
							|  |  |  |                      'Outside: foo again, bar again'); | 
					
						
							|  |  |  |            }); | 
					
						
							|  |  |  |          })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should bind properties, events to scope when bindToController is not used', | 
					
						
							|  |  |  |          fakeAsync(() => { | 
					
						
							|  |  |  |            // Define `ng1Directive`
 | 
					
						
							|  |  |  |            const ng1Directive: angular.IDirective = { | 
					
						
							|  |  |  |              template: '{{ someText }} - Data: {{ inputA }} - Length: {{ inputA.length }}', | 
					
						
							|  |  |  |              scope: {inputA: '=', outputA: '&'}, | 
					
						
							|  |  |  |              controller: function($scope: angular.IScope) { | 
					
						
							|  |  |  |                $scope['someText'] = 'ng1'; | 
					
						
							|  |  |  |                this.$scope = $scope; | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng1ComponentFacade`
 | 
					
						
							|  |  |  |            @Directive({selector: '[ng1]'}) | 
					
						
							|  |  |  |            class Ng1ComponentFacade extends UpgradeComponent { | 
					
						
							| 
									
										
										
										
											2018-06-18 16:38:33 -07:00
										 |  |  |              // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |              @Input() inputA !: string; | 
					
						
							|  |  |  |              // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |              @Output() inputAChange !: EventEmitter<any>; | 
					
						
							|  |  |  |              // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |              @Output() outputA !: EventEmitter<any>; | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |              constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                super('ng1', elementRef, injector); | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Component`
 | 
					
						
							|  |  |  |            @Component({ | 
					
						
							|  |  |  |              selector: 'ng2', | 
					
						
							|  |  |  |              template: `
 | 
					
						
							|  |  |  |                 <div ng1 [(inputA)]="dataA" (outputA)="dataA.push($event)"></div> | | 
					
						
							|  |  |  |                 {{ someText }} - Data: {{ dataA }} - Length: {{ dataA.length }} | 
					
						
							|  |  |  |               `
 | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Component { | 
					
						
							|  |  |  |              someText = 'ng2'; | 
					
						
							|  |  |  |              dataA = [1, 2, 3]; | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Module`
 | 
					
						
							|  |  |  |            const ng1Module = angular.module('ng1Module', []) | 
					
						
							|  |  |  |                                  .directive('ng1', () => ng1Directive) | 
					
						
							|  |  |  |                                  .directive('ng2', downgradeComponent({component: Ng2Component})); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Module`
 | 
					
						
							|  |  |  |            @NgModule({ | 
					
						
							|  |  |  |              declarations: [Ng1ComponentFacade, Ng2Component], | 
					
						
							|  |  |  |              entryComponents: [Ng2Component], | 
					
						
							|  |  |  |              imports: [BrowserModule, UpgradeModule] | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Module { | 
					
						
							|  |  |  |              ngDoBootstrap() {} | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Bootstrap
 | 
					
						
							|  |  |  |            const element = html(`<ng2></ng2>`); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  |            bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(adapter => { | 
					
						
							| 
									
										
										
										
											2017-03-24 09:59:18 -07:00
										 |  |  |              const ng1 = element.querySelector('[ng1]') !; | 
					
						
							|  |  |  |              const ng1Controller = angular.element(ng1).controller !('ng1'); | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |              expect(multiTrim(element.textContent)) | 
					
						
							|  |  |  |                  .toBe('ng1 - Data: [1,2,3] - Length: 3 | ng2 - Data: 1,2,3 - Length: 3'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              ng1Controller.$scope.inputA = [4, 5]; | 
					
						
							|  |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(multiTrim(element.textContent)) | 
					
						
							|  |  |  |                  .toBe('ng1 - Data: [4,5] - Length: 2 | ng2 - Data: 4,5 - Length: 2'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              ng1Controller.$scope.outputA(6); | 
					
						
							| 
									
										
										
										
											2017-02-04 17:19:09 +02:00
										 |  |  |              $digest(adapter); | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(ng1Controller.$scope.inputA).toEqual([4, 5, 6]); | 
					
						
							|  |  |  |              expect(multiTrim(element.textContent)) | 
					
						
							|  |  |  |                  .toBe('ng1 - Data: [4,5,6] - Length: 3 | ng2 - Data: 4,5,6 - Length: 3'); | 
					
						
							|  |  |  |            }); | 
					
						
							|  |  |  |          })); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
											  
											
												fix(upgrade): populate upgraded component's view before creating the controller (#14289)
Previously, the relative order of the AngularJS compiling/linking operations was
not similar to AngularJS's, resulting in inconsistent behavior for upgraded
components (which made upgrading to Angular less straight forward).
This commit fixes it, by following the compiling/linking process of AngularJS
more closely.
Main differences:
- The components view is already populated when the controller is instantiated
  (and subsequent hooks are called).
- The correct DOM content is available when running the `$onChanges`, `$onInit`,
  `$doCheck` hooks. Previously, the "content children" were still present, not
  the "view children".
- The same for pre-linking.
- The template is compiled in the correct DOM context (e.g. has access to
  ancestors). Previously, it was compiled in isolation, inside a dummy element.
For reference, here is the order of operations:
**Before**
1. Compile template
2. Instantiate controller
3. Hook: $onChanges
4. Hook: $onInit
5. Hook: $doCheck
6. Pre-linking
7. Collect content children
8. Insert compiled template
9. Linking
10. Post-linking
11. Hook: $postLink
**After**
1. Collect content children
2. Insert template
3. Compile template
4. Instantiate controller
5. Hook: $onChanges
6. Hook: $onInit
7. Hook: $doCheck
8. Pre-linking
9. Linking
10. Post-linking
11. Hook: $postLink
Fixes #13912
											
										 
											2017-03-07 19:32:52 +02:00
										 |  |  |     describe('compiling', () => { | 
					
						
							|  |  |  |       it('should compile the ng1 template in the correct DOM context', async(() => { | 
					
						
							|  |  |  |            let grandParentNodeName: string; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Component`
 | 
					
						
							|  |  |  |            const ng1ComponentA: angular.IComponent = {template: 'ng1A(<ng1-b></ng1-b>)'}; | 
					
						
							|  |  |  |            const ng1DirectiveB: angular.IDirective = { | 
					
						
							| 
									
										
										
										
											2017-08-02 16:28:04 -07:00
										 |  |  |              compile: tElem => { | 
					
						
							|  |  |  |                grandParentNodeName = tElem.parent !().parent !()[0].nodeName; | 
					
						
							|  |  |  |                return {}; | 
					
						
							|  |  |  |              } | 
					
						
							| 
									
										
											  
											
												fix(upgrade): populate upgraded component's view before creating the controller (#14289)
Previously, the relative order of the AngularJS compiling/linking operations was
not similar to AngularJS's, resulting in inconsistent behavior for upgraded
components (which made upgrading to Angular less straight forward).
This commit fixes it, by following the compiling/linking process of AngularJS
more closely.
Main differences:
- The components view is already populated when the controller is instantiated
  (and subsequent hooks are called).
- The correct DOM content is available when running the `$onChanges`, `$onInit`,
  `$doCheck` hooks. Previously, the "content children" were still present, not
  the "view children".
- The same for pre-linking.
- The template is compiled in the correct DOM context (e.g. has access to
  ancestors). Previously, it was compiled in isolation, inside a dummy element.
For reference, here is the order of operations:
**Before**
1. Compile template
2. Instantiate controller
3. Hook: $onChanges
4. Hook: $onInit
5. Hook: $doCheck
6. Pre-linking
7. Collect content children
8. Insert compiled template
9. Linking
10. Post-linking
11. Hook: $postLink
**After**
1. Collect content children
2. Insert template
3. Compile template
4. Instantiate controller
5. Hook: $onChanges
6. Hook: $onInit
7. Hook: $doCheck
8. Pre-linking
9. Linking
10. Post-linking
11. Hook: $postLink
Fixes #13912
											
										 
											2017-03-07 19:32:52 +02:00
										 |  |  |            }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng1ComponentAFacade`
 | 
					
						
							|  |  |  |            @Directive({selector: 'ng1A'}) | 
					
						
							|  |  |  |            class Ng1ComponentAFacade extends UpgradeComponent { | 
					
						
							|  |  |  |              constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                super('ng1A', elementRef, injector); | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2ComponentX`
 | 
					
						
							|  |  |  |            @Component({selector: 'ng2-x', template: 'ng2X(<ng1A></ng1A>)'}) | 
					
						
							|  |  |  |            class Ng2ComponentX { | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Module`
 | 
					
						
							|  |  |  |            const ng1Module = angular.module('ng1', []) | 
					
						
							|  |  |  |                                  .component('ng1A', ng1ComponentA) | 
					
						
							|  |  |  |                                  .directive('ng1B', () => ng1DirectiveB) | 
					
						
							|  |  |  |                                  .directive('ng2X', downgradeComponent({component: Ng2ComponentX})); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Module`
 | 
					
						
							|  |  |  |            @NgModule({ | 
					
						
							|  |  |  |              imports: [BrowserModule, UpgradeModule], | 
					
						
							|  |  |  |              declarations: [Ng1ComponentAFacade, Ng2ComponentX], | 
					
						
							|  |  |  |              entryComponents: [Ng2ComponentX], | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Module { | 
					
						
							|  |  |  |              ngDoBootstrap() {} | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Bootstrap
 | 
					
						
							|  |  |  |            const element = html(`<ng2-x></ng2-x>`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(() => { | 
					
						
							|  |  |  |              expect(grandParentNodeName).toBe('NG2-X'); | 
					
						
							|  |  |  |            }); | 
					
						
							|  |  |  |          })); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-29 20:52:50 +03:00
										 |  |  |     describe('linking', () => { | 
					
						
							|  |  |  |       it('should run the pre-linking after instantiating the controller', async(() => { | 
					
						
							|  |  |  |            const log: string[] = []; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Directive`
 | 
					
						
							|  |  |  |            const ng1Directive: angular.IDirective = { | 
					
						
							|  |  |  |              template: '', | 
					
						
							|  |  |  |              link: {pre: () => log.push('ng1-pre')}, | 
					
						
							|  |  |  |              controller: class {constructor() { log.push('ng1-ctrl'); }} | 
					
						
							|  |  |  |            }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng1ComponentFacade`
 | 
					
						
							|  |  |  |            @Directive({selector: 'ng1'}) | 
					
						
							|  |  |  |            class Ng1ComponentFacade extends UpgradeComponent { | 
					
						
							|  |  |  |              constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                super('ng1', elementRef, injector); | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Component`
 | 
					
						
							|  |  |  |            @Component({selector: 'ng2', template: '<ng1></ng1>'}) | 
					
						
							|  |  |  |            class Ng2Component { | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Module`
 | 
					
						
							|  |  |  |            const ng1Module = angular.module('ng1', []) | 
					
						
							|  |  |  |                                  .directive('ng1', () => ng1Directive) | 
					
						
							|  |  |  |                                  .directive('ng2', downgradeComponent({component: Ng2Component})); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Module`
 | 
					
						
							|  |  |  |            @NgModule({ | 
					
						
							|  |  |  |              imports: [BrowserModule, UpgradeModule], | 
					
						
							|  |  |  |              declarations: [Ng1ComponentFacade, Ng2Component], | 
					
						
							|  |  |  |              entryComponents: [Ng2Component], | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Module { | 
					
						
							|  |  |  |              ngDoBootstrap() {} | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Bootstrap
 | 
					
						
							|  |  |  |            const element = html(`<ng2></ng2>`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(() => { | 
					
						
							|  |  |  |              expect(log).toEqual(['ng1-ctrl', 'ng1-pre']); | 
					
						
							|  |  |  |            }); | 
					
						
							|  |  |  |          })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should run the pre-linking function before linking', async(() => { | 
					
						
							|  |  |  |            const log: string[] = []; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Directive`
 | 
					
						
							|  |  |  |            const ng1DirectiveA: angular.IDirective = { | 
					
						
							|  |  |  |              template: '<ng1-b></ng1-b>', | 
					
						
							|  |  |  |              link: {pre: () => log.push('ng1A-pre')} | 
					
						
							|  |  |  |            }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            const ng1DirectiveB: angular.IDirective = {link: () => log.push('ng1B-post')}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng1ComponentAFacade`
 | 
					
						
							|  |  |  |            @Directive({selector: 'ng1A'}) | 
					
						
							|  |  |  |            class Ng1ComponentAFacade extends UpgradeComponent { | 
					
						
							|  |  |  |              constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                super('ng1A', elementRef, injector); | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Component`
 | 
					
						
							|  |  |  |            @Component({selector: 'ng2', template: '<ng1A></ng1A>'}) | 
					
						
							|  |  |  |            class Ng2Component { | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Module`
 | 
					
						
							|  |  |  |            const ng1Module = angular.module('ng1', []) | 
					
						
							|  |  |  |                                  .directive('ng1A', () => ng1DirectiveA) | 
					
						
							|  |  |  |                                  .directive('ng1B', () => ng1DirectiveB) | 
					
						
							|  |  |  |                                  .directive('ng2', downgradeComponent({component: Ng2Component})); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Module`
 | 
					
						
							|  |  |  |            @NgModule({ | 
					
						
							|  |  |  |              imports: [BrowserModule, UpgradeModule], | 
					
						
							|  |  |  |              declarations: [Ng1ComponentAFacade, Ng2Component], | 
					
						
							|  |  |  |              entryComponents: [Ng2Component], | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Module { | 
					
						
							|  |  |  |              ngDoBootstrap() {} | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Bootstrap
 | 
					
						
							|  |  |  |            const element = html(`<ng2></ng2>`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(() => { | 
					
						
							|  |  |  |              expect(log).toEqual(['ng1A-pre', 'ng1B-post']); | 
					
						
							|  |  |  |            }); | 
					
						
							|  |  |  |          })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should run the post-linking function after linking (link: object)', async(() => { | 
					
						
							|  |  |  |            const log: string[] = []; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Directive`
 | 
					
						
							|  |  |  |            const ng1DirectiveA: angular.IDirective = { | 
					
						
							|  |  |  |              template: '<ng1-b></ng1-b>', | 
					
						
							|  |  |  |              link: {post: () => log.push('ng1A-post')} | 
					
						
							|  |  |  |            }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            const ng1DirectiveB: angular.IDirective = {link: () => log.push('ng1B-post')}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng1ComponentAFacade`
 | 
					
						
							|  |  |  |            @Directive({selector: 'ng1A'}) | 
					
						
							|  |  |  |            class Ng1ComponentAFacade extends UpgradeComponent { | 
					
						
							|  |  |  |              constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                super('ng1A', elementRef, injector); | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Component`
 | 
					
						
							|  |  |  |            @Component({selector: 'ng2', template: '<ng1A></ng1A>'}) | 
					
						
							|  |  |  |            class Ng2Component { | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Module`
 | 
					
						
							|  |  |  |            const ng1Module = angular.module('ng1', []) | 
					
						
							|  |  |  |                                  .directive('ng1A', () => ng1DirectiveA) | 
					
						
							|  |  |  |                                  .directive('ng1B', () => ng1DirectiveB) | 
					
						
							|  |  |  |                                  .directive('ng2', downgradeComponent({component: Ng2Component})); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Module`
 | 
					
						
							|  |  |  |            @NgModule({ | 
					
						
							|  |  |  |              imports: [BrowserModule, UpgradeModule], | 
					
						
							|  |  |  |              declarations: [Ng1ComponentAFacade, Ng2Component], | 
					
						
							|  |  |  |              entryComponents: [Ng2Component], | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Module { | 
					
						
							|  |  |  |              ngDoBootstrap() {} | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Bootstrap
 | 
					
						
							|  |  |  |            const element = html(`<ng2></ng2>`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(() => { | 
					
						
							|  |  |  |              expect(log).toEqual(['ng1B-post', 'ng1A-post']); | 
					
						
							|  |  |  |            }); | 
					
						
							|  |  |  |          })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should run the post-linking function after linking (link: function)', async(() => { | 
					
						
							|  |  |  |            const log: string[] = []; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Directive`
 | 
					
						
							|  |  |  |            const ng1DirectiveA: angular.IDirective = { | 
					
						
							|  |  |  |              template: '<ng1-b></ng1-b>', | 
					
						
							|  |  |  |              link: () => log.push('ng1A-post') | 
					
						
							|  |  |  |            }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            const ng1DirectiveB: angular.IDirective = {link: () => log.push('ng1B-post')}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng1ComponentAFacade`
 | 
					
						
							|  |  |  |            @Directive({selector: 'ng1A'}) | 
					
						
							|  |  |  |            class Ng1ComponentAFacade extends UpgradeComponent { | 
					
						
							|  |  |  |              constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                super('ng1A', elementRef, injector); | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Component`
 | 
					
						
							|  |  |  |            @Component({selector: 'ng2', template: '<ng1A></ng1A>'}) | 
					
						
							|  |  |  |            class Ng2Component { | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Module`
 | 
					
						
							|  |  |  |            const ng1Module = angular.module('ng1', []) | 
					
						
							|  |  |  |                                  .directive('ng1A', () => ng1DirectiveA) | 
					
						
							|  |  |  |                                  .directive('ng1B', () => ng1DirectiveB) | 
					
						
							|  |  |  |                                  .directive('ng2', downgradeComponent({component: Ng2Component})); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Module`
 | 
					
						
							|  |  |  |            @NgModule({ | 
					
						
							|  |  |  |              imports: [BrowserModule, UpgradeModule], | 
					
						
							|  |  |  |              declarations: [Ng1ComponentAFacade, Ng2Component], | 
					
						
							|  |  |  |              entryComponents: [Ng2Component], | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Module { | 
					
						
							|  |  |  |              ngDoBootstrap() {} | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Bootstrap
 | 
					
						
							|  |  |  |            const element = html(`<ng2></ng2>`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(() => { | 
					
						
							|  |  |  |              expect(log).toEqual(['ng1B-post', 'ng1A-post']); | 
					
						
							|  |  |  |            }); | 
					
						
							|  |  |  |          })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should run the post-linking function before `$postLink`', async(() => { | 
					
						
							|  |  |  |            const log: string[] = []; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Directive`
 | 
					
						
							|  |  |  |            const ng1Directive: angular.IDirective = { | 
					
						
							|  |  |  |              template: '', | 
					
						
							|  |  |  |              link: () => log.push('ng1-post'), | 
					
						
							|  |  |  |              controller: class {$postLink() { log.push('ng1-$post'); }} | 
					
						
							|  |  |  |            }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng1ComponentFacade`
 | 
					
						
							|  |  |  |            @Directive({selector: 'ng1'}) | 
					
						
							|  |  |  |            class Ng1ComponentFacade extends UpgradeComponent { | 
					
						
							|  |  |  |              constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                super('ng1', elementRef, injector); | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Component`
 | 
					
						
							|  |  |  |            @Component({selector: 'ng2', template: '<ng1></ng1>'}) | 
					
						
							|  |  |  |            class Ng2Component { | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Module`
 | 
					
						
							|  |  |  |            const ng1Module = angular.module('ng1', []) | 
					
						
							|  |  |  |                                  .directive('ng1', () => ng1Directive) | 
					
						
							|  |  |  |                                  .directive('ng2', downgradeComponent({component: Ng2Component})); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Module`
 | 
					
						
							|  |  |  |            @NgModule({ | 
					
						
							|  |  |  |              imports: [BrowserModule, UpgradeModule], | 
					
						
							|  |  |  |              declarations: [Ng1ComponentFacade, Ng2Component], | 
					
						
							|  |  |  |              entryComponents: [Ng2Component], | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Module { | 
					
						
							|  |  |  |              ngDoBootstrap() {} | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Bootstrap
 | 
					
						
							|  |  |  |            const element = html(`<ng2></ng2>`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(() => { | 
					
						
							|  |  |  |              expect(log).toEqual(['ng1-post', 'ng1-$post']); | 
					
						
							|  |  |  |            }); | 
					
						
							|  |  |  |          })); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  |     describe('controller', () => { | 
					
						
							|  |  |  |       it('should support `controllerAs`', async(() => { | 
					
						
							|  |  |  |            // Define `ng1Directive`
 | 
					
						
							|  |  |  |            const ng1Directive: angular.IDirective = { | 
					
						
							|  |  |  |              template: | 
					
						
							|  |  |  |                  '{{ vm.scope }}; {{ vm.isClass }}; {{ vm.hasElement }}; {{ vm.isPublished() }}', | 
					
						
							|  |  |  |              scope: true, | 
					
						
							|  |  |  |              controllerAs: 'vm', | 
					
						
							|  |  |  |              controller: class { | 
					
						
							| 
									
										
										
										
											2018-06-18 16:38:33 -07:00
										 |  |  |                hasElement: string;  // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |                isClass !: string; | 
					
						
							|  |  |  |                scope: string; | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |                constructor(public $element: angular.IAugmentedJQuery, $scope: angular.IScope) { | 
					
						
							|  |  |  |                  this.hasElement = $element[0].nodeName; | 
					
						
							|  |  |  |                  this.scope = $scope.$parent.$parent === $scope.$root ? 'scope' : 'wrong-scope'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                  this.verifyIAmAClass(); | 
					
						
							|  |  |  |                } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                isPublished() { | 
					
						
							| 
									
										
										
										
											2017-03-24 09:59:18 -07:00
										 |  |  |                  return this.$element.controller !('ng1') === this ? 'published' : 'not-published'; | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  |                } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                verifyIAmAClass() { this.isClass = 'isClass'; } | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng1ComponentFacade`
 | 
					
						
							|  |  |  |            @Directive({selector: 'ng1'}) | 
					
						
							|  |  |  |            class Ng1ComponentFacade extends UpgradeComponent { | 
					
						
							|  |  |  |              constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                super('ng1', elementRef, injector); | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Component`
 | 
					
						
							|  |  |  |            @Component({selector: 'ng2', template: '<ng1></ng1>'}) | 
					
						
							|  |  |  |            class Ng2Component { | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Module`
 | 
					
						
							|  |  |  |            const ng1Module = angular.module('ng1Module', []) | 
					
						
							|  |  |  |                                  .directive('ng1', () => ng1Directive) | 
					
						
							|  |  |  |                                  .directive('ng2', downgradeComponent({component: Ng2Component})); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Module`
 | 
					
						
							|  |  |  |            @NgModule({ | 
					
						
							|  |  |  |              declarations: [Ng1ComponentFacade, Ng2Component], | 
					
						
							|  |  |  |              entryComponents: [Ng2Component], | 
					
						
							|  |  |  |              imports: [BrowserModule, UpgradeModule] | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Module { | 
					
						
							|  |  |  |              ngDoBootstrap() {} | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Bootstrap
 | 
					
						
							|  |  |  |            const element = html(`<ng2></ng2>`); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  |            bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(() => { | 
					
						
							|  |  |  |              expect(multiTrim(element.textContent)).toBe('scope; isClass; NG1; published'); | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  |            }); | 
					
						
							|  |  |  |          })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should support `bindToController` (boolean)', async(() => { | 
					
						
							|  |  |  |            // Define `ng1Directive`
 | 
					
						
							|  |  |  |            const ng1DirectiveA: angular.IDirective = { | 
					
						
							|  |  |  |              template: 'Scope: {{ title }}; Controller: {{ $ctrl.title }}', | 
					
						
							|  |  |  |              scope: {title: '@'}, | 
					
						
							|  |  |  |              bindToController: false, | 
					
						
							|  |  |  |              controllerAs: '$ctrl', | 
					
						
							|  |  |  |              controller: class {} | 
					
						
							|  |  |  |            }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            const ng1DirectiveB: angular.IDirective = { | 
					
						
							|  |  |  |              template: 'Scope: {{ title }}; Controller: {{ $ctrl.title }}', | 
					
						
							|  |  |  |              scope: {title: '@'}, | 
					
						
							|  |  |  |              bindToController: true, | 
					
						
							|  |  |  |              controllerAs: '$ctrl', | 
					
						
							|  |  |  |              controller: class {} | 
					
						
							|  |  |  |            }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng1ComponentFacade`
 | 
					
						
							|  |  |  |            @Directive({selector: 'ng1A'}) | 
					
						
							|  |  |  |            class Ng1ComponentAFacade extends UpgradeComponent { | 
					
						
							| 
									
										
										
										
											2018-06-18 16:38:33 -07:00
										 |  |  |              // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |              @Input() title !: string; | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |              constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                super('ng1A', elementRef, injector); | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            @Directive({selector: 'ng1B'}) | 
					
						
							|  |  |  |            class Ng1ComponentBFacade extends UpgradeComponent { | 
					
						
							| 
									
										
										
										
											2018-06-18 16:38:33 -07:00
										 |  |  |              // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |              @Input() title !: string; | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |              constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                super('ng1B', elementRef, injector); | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Component`
 | 
					
						
							|  |  |  |            @Component({ | 
					
						
							|  |  |  |              selector: 'ng2', | 
					
						
							|  |  |  |              template: `
 | 
					
						
							|  |  |  |             <ng1A title="WORKS"></ng1A> | | 
					
						
							|  |  |  |             <ng1B title="WORKS"></ng1B> | 
					
						
							|  |  |  |           `
 | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Component { | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Module`
 | 
					
						
							|  |  |  |            const ng1Module = angular.module('ng1Module', []) | 
					
						
							|  |  |  |                                  .directive('ng1A', () => ng1DirectiveA) | 
					
						
							|  |  |  |                                  .directive('ng1B', () => ng1DirectiveB) | 
					
						
							|  |  |  |                                  .directive('ng2', downgradeComponent({component: Ng2Component})); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Module`
 | 
					
						
							|  |  |  |            @NgModule({ | 
					
						
							|  |  |  |              declarations: [Ng1ComponentAFacade, Ng1ComponentBFacade, Ng2Component], | 
					
						
							|  |  |  |              entryComponents: [Ng2Component], | 
					
						
							|  |  |  |              imports: [BrowserModule, UpgradeModule], | 
					
						
							|  |  |  |              schemas: [NO_ERRORS_SCHEMA] | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Module { | 
					
						
							|  |  |  |              ngDoBootstrap() {} | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Bootstrap
 | 
					
						
							|  |  |  |            const element = html(`<ng2></ng2>`); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  |            bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(() => { | 
					
						
							|  |  |  |              expect(multiTrim(element.textContent)) | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  |                  .toBe('Scope: WORKS; Controller: | Scope: ; Controller: WORKS'); | 
					
						
							|  |  |  |            }); | 
					
						
							|  |  |  |          })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should support `bindToController` (object)', async(() => { | 
					
						
							|  |  |  |            // Define `ng1Directive`
 | 
					
						
							|  |  |  |            const ng1Directive: angular.IDirective = { | 
					
						
							|  |  |  |              template: '{{ $ctrl.title }}', | 
					
						
							|  |  |  |              scope: {}, | 
					
						
							|  |  |  |              bindToController: {title: '@'}, | 
					
						
							|  |  |  |              controllerAs: '$ctrl', | 
					
						
							|  |  |  |              controller: class {} | 
					
						
							|  |  |  |            }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng1ComponentFacade`
 | 
					
						
							|  |  |  |            @Directive({selector: 'ng1'}) | 
					
						
							|  |  |  |            class Ng1ComponentFacade extends UpgradeComponent { | 
					
						
							| 
									
										
										
										
											2018-06-18 16:38:33 -07:00
										 |  |  |              // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |              @Input() title !: string; | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |              constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                super('ng1', elementRef, injector); | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Component`
 | 
					
						
							|  |  |  |            @Component({selector: 'ng2', template: '<ng1 title="WORKS"></ng1>'}) | 
					
						
							|  |  |  |            class Ng2Component { | 
					
						
							|  |  |  |              dataA = 'foo'; | 
					
						
							|  |  |  |              dataB = 'bar'; | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Module`
 | 
					
						
							|  |  |  |            const ng1Module = angular.module('ng1Module', []) | 
					
						
							|  |  |  |                                  .directive('ng1', () => ng1Directive) | 
					
						
							|  |  |  |                                  .directive('ng2', downgradeComponent({component: Ng2Component})); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Module`
 | 
					
						
							|  |  |  |            @NgModule({ | 
					
						
							|  |  |  |              declarations: [Ng1ComponentFacade, Ng2Component], | 
					
						
							|  |  |  |              entryComponents: [Ng2Component], | 
					
						
							|  |  |  |              imports: [BrowserModule, UpgradeModule] | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Module { | 
					
						
							|  |  |  |              ngDoBootstrap() {} | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Bootstrap
 | 
					
						
							|  |  |  |            const element = html(`<ng2></ng2>`); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  |            bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(() => { | 
					
						
							|  |  |  |              expect(multiTrim(element.textContent)).toBe('WORKS'); | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  |            }); | 
					
						
							|  |  |  |          })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should support `controller` as string', async(() => { | 
					
						
							|  |  |  |            // Define `ng1Directive`
 | 
					
						
							|  |  |  |            const ng1Directive: angular.IDirective = { | 
					
						
							|  |  |  |              template: '{{ $ctrl.title }} {{ $ctrl.text }}', | 
					
						
							|  |  |  |              scope: {title: '@'}, | 
					
						
							|  |  |  |              bindToController: true, | 
					
						
							|  |  |  |              controller: 'Ng1Controller as $ctrl' | 
					
						
							|  |  |  |            }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng1ComponentFacade`
 | 
					
						
							|  |  |  |            @Directive({selector: 'ng1'}) | 
					
						
							|  |  |  |            class Ng1ComponentFacade extends UpgradeComponent { | 
					
						
							| 
									
										
										
										
											2018-06-18 16:38:33 -07:00
										 |  |  |              // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |              @Input() title !: string; | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |              constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                super('ng1', elementRef, injector); | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Component`
 | 
					
						
							|  |  |  |            @Component({selector: 'ng2', template: '<ng1 title="WORKS"></ng1>'}) | 
					
						
							|  |  |  |            class Ng2Component { | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Module`
 | 
					
						
							|  |  |  |            const ng1Module = angular.module('ng1Module', []) | 
					
						
							|  |  |  |                                  .controller('Ng1Controller', class { text = 'GREAT'; }) | 
					
						
							|  |  |  |                                  .directive('ng1', () => ng1Directive) | 
					
						
							|  |  |  |                                  .directive('ng2', downgradeComponent({component: Ng2Component})); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Module`
 | 
					
						
							|  |  |  |            @NgModule({ | 
					
						
							|  |  |  |              declarations: [Ng1ComponentFacade, Ng2Component], | 
					
						
							|  |  |  |              entryComponents: [Ng2Component], | 
					
						
							|  |  |  |              imports: [BrowserModule, UpgradeModule] | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Module { | 
					
						
							|  |  |  |              ngDoBootstrap() {} | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Bootstrap
 | 
					
						
							|  |  |  |            const element = html(`<ng2></ng2>`); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  |            bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(() => { | 
					
						
							|  |  |  |              expect(multiTrim(element.textContent)).toBe('WORKS GREAT'); | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  |            }); | 
					
						
							|  |  |  |          })); | 
					
						
							| 
									
										
											  
											
												fix(upgrade): populate upgraded component's view before creating the controller (#14289)
Previously, the relative order of the AngularJS compiling/linking operations was
not similar to AngularJS's, resulting in inconsistent behavior for upgraded
components (which made upgrading to Angular less straight forward).
This commit fixes it, by following the compiling/linking process of AngularJS
more closely.
Main differences:
- The components view is already populated when the controller is instantiated
  (and subsequent hooks are called).
- The correct DOM content is available when running the `$onChanges`, `$onInit`,
  `$doCheck` hooks. Previously, the "content children" were still present, not
  the "view children".
- The same for pre-linking.
- The template is compiled in the correct DOM context (e.g. has access to
  ancestors). Previously, it was compiled in isolation, inside a dummy element.
For reference, here is the order of operations:
**Before**
1. Compile template
2. Instantiate controller
3. Hook: $onChanges
4. Hook: $onInit
5. Hook: $doCheck
6. Pre-linking
7. Collect content children
8. Insert compiled template
9. Linking
10. Post-linking
11. Hook: $postLink
**After**
1. Collect content children
2. Insert template
3. Compile template
4. Instantiate controller
5. Hook: $onChanges
6. Hook: $onInit
7. Hook: $doCheck
8. Pre-linking
9. Linking
10. Post-linking
11. Hook: $postLink
Fixes #13912
											
										 
											2017-03-07 19:32:52 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |       it('should insert the compiled content before instantiating the controller', async(() => { | 
					
						
							|  |  |  |            let compiledContent: string; | 
					
						
							|  |  |  |            let getCurrentContent: () => string; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Component`
 | 
					
						
							|  |  |  |            const ng1Component: angular.IComponent = { | 
					
						
							|  |  |  |              template: 'Hello, {{ $ctrl.name }}!', | 
					
						
							|  |  |  |              controller: class { | 
					
						
							|  |  |  |                name = 'world'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                constructor($element: angular.IAugmentedJQuery) { | 
					
						
							| 
									
										
										
										
											2017-03-24 09:59:18 -07:00
										 |  |  |                  getCurrentContent = () => $element.text !(); | 
					
						
							| 
									
										
											  
											
												fix(upgrade): populate upgraded component's view before creating the controller (#14289)
Previously, the relative order of the AngularJS compiling/linking operations was
not similar to AngularJS's, resulting in inconsistent behavior for upgraded
components (which made upgrading to Angular less straight forward).
This commit fixes it, by following the compiling/linking process of AngularJS
more closely.
Main differences:
- The components view is already populated when the controller is instantiated
  (and subsequent hooks are called).
- The correct DOM content is available when running the `$onChanges`, `$onInit`,
  `$doCheck` hooks. Previously, the "content children" were still present, not
  the "view children".
- The same for pre-linking.
- The template is compiled in the correct DOM context (e.g. has access to
  ancestors). Previously, it was compiled in isolation, inside a dummy element.
For reference, here is the order of operations:
**Before**
1. Compile template
2. Instantiate controller
3. Hook: $onChanges
4. Hook: $onInit
5. Hook: $doCheck
6. Pre-linking
7. Collect content children
8. Insert compiled template
9. Linking
10. Post-linking
11. Hook: $postLink
**After**
1. Collect content children
2. Insert template
3. Compile template
4. Instantiate controller
5. Hook: $onChanges
6. Hook: $onInit
7. Hook: $doCheck
8. Pre-linking
9. Linking
10. Post-linking
11. Hook: $postLink
Fixes #13912
											
										 
											2017-03-07 19:32:52 +02:00
										 |  |  |                  compiledContent = getCurrentContent(); | 
					
						
							|  |  |  |                } | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng1ComponentFacade`
 | 
					
						
							|  |  |  |            @Directive({selector: 'ng1'}) | 
					
						
							|  |  |  |            class Ng1ComponentFacade extends UpgradeComponent { | 
					
						
							|  |  |  |              constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                super('ng1', elementRef, injector); | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Component`
 | 
					
						
							|  |  |  |            @Component({selector: 'ng2', template: '<ng1></ng1>'}) | 
					
						
							|  |  |  |            class Ng2Component { | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Module`
 | 
					
						
							|  |  |  |            const ng1Module = angular.module('ng1Module', []) | 
					
						
							|  |  |  |                                  .component('ng1', ng1Component) | 
					
						
							|  |  |  |                                  .directive('ng2', downgradeComponent({component: Ng2Component})); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Module`
 | 
					
						
							|  |  |  |            @NgModule({ | 
					
						
							|  |  |  |              imports: [BrowserModule, UpgradeModule], | 
					
						
							|  |  |  |              declarations: [Ng1ComponentFacade, Ng2Component], | 
					
						
							|  |  |  |              entryComponents: [Ng2Component] | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Module { | 
					
						
							|  |  |  |              ngDoBootstrap() {} | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Bootstrap
 | 
					
						
							|  |  |  |            const element = html(`<ng2></ng2>`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(() => { | 
					
						
							|  |  |  |              expect(multiTrim(compiledContent)).toBe('Hello, {{ $ctrl.name }}!'); | 
					
						
							|  |  |  |              expect(multiTrim(getCurrentContent())).toBe('Hello, world!'); | 
					
						
							|  |  |  |            }); | 
					
						
							|  |  |  |          })); | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  |     describe('require', () => { | 
					
						
							|  |  |  |       // NOT YET SUPPORTED
 | 
					
						
							|  |  |  |       xdescribe('in pre-/post-link', () => { | 
					
						
							|  |  |  |         it('should resolve to its own controller if falsy', async(() => { | 
					
						
							|  |  |  |              // Define `ng1Directive`
 | 
					
						
							|  |  |  |              const ng1Directive: angular.IDirective = { | 
					
						
							|  |  |  |                template: 'Pre: {{ pre }} | Post: {{ post }}', | 
					
						
							|  |  |  |                controller: class {value = 'foo';}, | 
					
						
							|  |  |  |                link: { | 
					
						
							|  |  |  |                  pre: function(scope: any, elem: any, attrs: any, ctrl: any) { | 
					
						
							|  |  |  |                    scope['pre'] = ctrl.value; | 
					
						
							|  |  |  |                  }, | 
					
						
							|  |  |  |                  post: function(scope: any, elem: any, attrs: any, ctrl: any) { | 
					
						
							|  |  |  |                    scope['post'] = ctrl.value; | 
					
						
							|  |  |  |                  } | 
					
						
							|  |  |  |                } | 
					
						
							|  |  |  |              }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              // Define `Ng1ComponentFacade`
 | 
					
						
							|  |  |  |              @Directive({selector: 'ng1'}) | 
					
						
							|  |  |  |              class Ng1ComponentFacade extends UpgradeComponent { | 
					
						
							|  |  |  |                constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                  super('ng1', elementRef, injector); | 
					
						
							|  |  |  |                } | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              // Define `Ng2Component`
 | 
					
						
							|  |  |  |              @Component({selector: 'ng2', template: '<ng1></ng1>'}) | 
					
						
							|  |  |  |              class Ng2Component { | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              // Define `ng1Module`
 | 
					
						
							|  |  |  |              const ng1Module = angular.module('ng1Module', []) | 
					
						
							|  |  |  |                                    .directive('ng1', () => ng1Directive) | 
					
						
							|  |  |  |                                    .directive('ng2', downgradeComponent({component: Ng2Component})); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              // Define `Ng2Module`
 | 
					
						
							|  |  |  |              @NgModule({ | 
					
						
							|  |  |  |                declarations: [Ng1ComponentFacade, Ng2Component], | 
					
						
							|  |  |  |                entryComponents: [Ng2Component], | 
					
						
							|  |  |  |                imports: [BrowserModule, UpgradeModule] | 
					
						
							|  |  |  |              }) | 
					
						
							|  |  |  |              class Ng2Module { | 
					
						
							|  |  |  |                ngDoBootstrap() {} | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              // Bootstrap
 | 
					
						
							|  |  |  |              const element = html(`<ng2></ng2>`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(() => { | 
					
						
							|  |  |  |                expect(multiTrim(document.body.textContent)).toBe('Pre: foo | Post: foo'); | 
					
						
							|  |  |  |              }); | 
					
						
							|  |  |  |            })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // TODO: Add more tests
 | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       describe('in controller', () => { | 
					
						
							|  |  |  |         it('should be available to children', async(() => { | 
					
						
							|  |  |  |              // Define `ng1Component`
 | 
					
						
							|  |  |  |              const ng1ComponentA: angular.IComponent = { | 
					
						
							|  |  |  |                template: '<ng1-b></ng1-b>', | 
					
						
							|  |  |  |                controller: class {value = 'ng1A';} | 
					
						
							|  |  |  |              }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              const ng1ComponentB: angular.IComponent = { | 
					
						
							|  |  |  |                template: 'Required: {{ $ctrl.required.value }}', | 
					
						
							|  |  |  |                require: {required: '^^ng1A'} | 
					
						
							|  |  |  |              }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              // Define `Ng1ComponentFacade`
 | 
					
						
							|  |  |  |              @Directive({selector: 'ng1A'}) | 
					
						
							|  |  |  |              class Ng1ComponentAFacade extends UpgradeComponent { | 
					
						
							|  |  |  |                constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                  super('ng1A', elementRef, injector); | 
					
						
							|  |  |  |                } | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              // Define `Ng2Component`
 | 
					
						
							|  |  |  |              @Component({selector: 'ng2', template: '<ng1A></ng1A>'}) | 
					
						
							|  |  |  |              class Ng2Component { | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              // Define `ng1Module`
 | 
					
						
							|  |  |  |              const ng1Module = angular.module('ng1Module', []) | 
					
						
							|  |  |  |                                    .component('ng1A', ng1ComponentA) | 
					
						
							|  |  |  |                                    .component('ng1B', ng1ComponentB) | 
					
						
							|  |  |  |                                    .directive('ng2', downgradeComponent({component: Ng2Component})); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              // Define `Ng2Module`
 | 
					
						
							|  |  |  |              @NgModule({ | 
					
						
							|  |  |  |                declarations: [Ng1ComponentAFacade, Ng2Component], | 
					
						
							|  |  |  |                entryComponents: [Ng2Component], | 
					
						
							|  |  |  |                imports: [BrowserModule, UpgradeModule] | 
					
						
							|  |  |  |              }) | 
					
						
							|  |  |  |              class Ng2Module { | 
					
						
							|  |  |  |                ngDoBootstrap() {} | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              // Bootstrap
 | 
					
						
							|  |  |  |              const element = html(`<ng2></ng2>`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(() => { | 
					
						
							|  |  |  |                expect(multiTrim(element.textContent)).toBe('Required: ng1A'); | 
					
						
							|  |  |  |              }); | 
					
						
							|  |  |  |            })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         it('should throw if required controller cannot be found', async(() => { | 
					
						
							|  |  |  |              // Define `ng1Component`
 | 
					
						
							|  |  |  |              const ng1ComponentA: angular.IComponent = {require: {foo: 'iDoNotExist'}}; | 
					
						
							|  |  |  |              const ng1ComponentB: angular.IComponent = {require: {foo: '^iDoNotExist'}}; | 
					
						
							|  |  |  |              const ng1ComponentC: angular.IComponent = {require: {foo: '^^iDoNotExist'}}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              // Define `Ng1ComponentFacade`
 | 
					
						
							|  |  |  |              @Directive({selector: 'ng1A'}) | 
					
						
							|  |  |  |              class Ng1ComponentAFacade extends UpgradeComponent { | 
					
						
							|  |  |  |                constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                  super('ng1A', elementRef, injector); | 
					
						
							|  |  |  |                } | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              @Directive({selector: 'ng1B'}) | 
					
						
							|  |  |  |              class Ng1ComponentBFacade extends UpgradeComponent { | 
					
						
							|  |  |  |                constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                  super('ng1B', elementRef, injector); | 
					
						
							|  |  |  |                } | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              @Directive({selector: 'ng1C'}) | 
					
						
							|  |  |  |              class Ng1ComponentCFacade extends UpgradeComponent { | 
					
						
							|  |  |  |                constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                  super('ng1C', elementRef, injector); | 
					
						
							|  |  |  |                } | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              // Define `Ng2Component`
 | 
					
						
							|  |  |  |              @Component({selector: 'ng2-a', template: '<ng1A></ng1A>'}) | 
					
						
							|  |  |  |              class Ng2ComponentA { | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              @Component({selector: 'ng2-b', template: '<ng1B></ng1B>'}) | 
					
						
							|  |  |  |              class Ng2ComponentB { | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              @Component({selector: 'ng2-c', template: '<ng1C></ng1C>'}) | 
					
						
							|  |  |  |              class Ng2ComponentC { | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              // Define `ng1Module`
 | 
					
						
							| 
									
										
										
										
											2018-10-11 17:44:59 +03:00
										 |  |  |              const mockExceptionHandler = jasmine.createSpy($EXCEPTION_HANDLER); | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  |              const ng1Module = | 
					
						
							|  |  |  |                  angular.module('ng1Module', []) | 
					
						
							|  |  |  |                      .component('ng1A', ng1ComponentA) | 
					
						
							|  |  |  |                      .component('ng1B', ng1ComponentB) | 
					
						
							|  |  |  |                      .component('ng1C', ng1ComponentC) | 
					
						
							|  |  |  |                      .directive('ng2A', downgradeComponent({component: Ng2ComponentA})) | 
					
						
							|  |  |  |                      .directive('ng2B', downgradeComponent({component: Ng2ComponentB})) | 
					
						
							|  |  |  |                      .directive('ng2C', downgradeComponent({component: Ng2ComponentC})) | 
					
						
							| 
									
										
										
										
											2018-10-11 17:44:59 +03:00
										 |  |  |                      .value($EXCEPTION_HANDLER, mockExceptionHandler); | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |              // Define `Ng2Module`
 | 
					
						
							|  |  |  |              @NgModule({ | 
					
						
							|  |  |  |                declarations: [ | 
					
						
							|  |  |  |                  Ng1ComponentAFacade, Ng1ComponentBFacade, Ng1ComponentCFacade, Ng2ComponentA, | 
					
						
							|  |  |  |                  Ng2ComponentB, Ng2ComponentC | 
					
						
							|  |  |  |                ], | 
					
						
							|  |  |  |                entryComponents: [Ng2ComponentA, Ng2ComponentB, Ng2ComponentC], | 
					
						
							|  |  |  |                imports: [BrowserModule, UpgradeModule] | 
					
						
							|  |  |  |              }) | 
					
						
							|  |  |  |              class Ng2Module { | 
					
						
							|  |  |  |                ngDoBootstrap() {} | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              // Bootstrap
 | 
					
						
							|  |  |  |              const elementA = html(`<ng2-a></ng2-a>`); | 
					
						
							|  |  |  |              const elementB = html(`<ng2-b></ng2-b>`); | 
					
						
							|  |  |  |              const elementC = html(`<ng2-c></ng2-c>`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              bootstrap(platformBrowserDynamic(), Ng2Module, elementA, ng1Module).then(() => { | 
					
						
							| 
									
										
										
										
											2017-03-14 09:16:15 -07:00
										 |  |  |                expect(mockExceptionHandler) | 
					
						
							|  |  |  |                    .toHaveBeenCalledWith(new Error( | 
					
						
							|  |  |  |                        'Unable to find required \'iDoNotExist\' in upgraded directive \'ng1A\'.')); | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  |              }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              bootstrap(platformBrowserDynamic(), Ng2Module, elementB, ng1Module).then(() => { | 
					
						
							| 
									
										
										
										
											2017-03-14 09:16:15 -07:00
										 |  |  |                expect(mockExceptionHandler) | 
					
						
							|  |  |  |                    .toHaveBeenCalledWith(new Error( | 
					
						
							|  |  |  |                        'Unable to find required \'^iDoNotExist\' in upgraded directive \'ng1B\'.')); | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  |              }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              bootstrap(platformBrowserDynamic(), Ng2Module, elementC, ng1Module).then(() => { | 
					
						
							| 
									
										
										
										
											2017-03-14 09:16:15 -07:00
										 |  |  |                expect(mockExceptionHandler) | 
					
						
							|  |  |  |                    .toHaveBeenCalledWith(new Error( | 
					
						
							|  |  |  |                        'Unable to find required \'^^iDoNotExist\' in upgraded directive \'ng1C\'.')); | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  |              }); | 
					
						
							|  |  |  |            })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         it('should not throw if missing required controller is optional', async(() => { | 
					
						
							|  |  |  |              // Define `ng1Component`
 | 
					
						
							|  |  |  |              const ng1Component: angular.IComponent = { | 
					
						
							|  |  |  |                require: { | 
					
						
							|  |  |  |                  foo: '?iDoNotExist', | 
					
						
							|  |  |  |                  bar: '^?iDoNotExist', | 
					
						
							|  |  |  |                  baz: '?^^iDoNotExist', | 
					
						
							|  |  |  |                } | 
					
						
							|  |  |  |              }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              // Define `Ng1ComponentFacade`
 | 
					
						
							|  |  |  |              @Directive({selector: 'ng1'}) | 
					
						
							|  |  |  |              class Ng1ComponentFacade extends UpgradeComponent { | 
					
						
							|  |  |  |                constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                  super('ng1', elementRef, injector); | 
					
						
							|  |  |  |                } | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              // Define `Ng2Component`
 | 
					
						
							|  |  |  |              @Component({selector: 'ng2', template: '<ng1></ng1>'}) | 
					
						
							|  |  |  |              class Ng2Component { | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              // Define `ng1Module`
 | 
					
						
							| 
									
										
										
										
											2018-10-11 17:44:59 +03:00
										 |  |  |              const mockExceptionHandler = jasmine.createSpy($EXCEPTION_HANDLER); | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  |              const ng1Module = angular.module('ng1Module', []) | 
					
						
							|  |  |  |                                    .component('ng1', ng1Component) | 
					
						
							|  |  |  |                                    .directive('ng2', downgradeComponent({component: Ng2Component})) | 
					
						
							| 
									
										
										
										
											2018-10-11 17:44:59 +03:00
										 |  |  |                                    .value($EXCEPTION_HANDLER, mockExceptionHandler); | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |              // Define `Ng2Module`
 | 
					
						
							|  |  |  |              @NgModule({ | 
					
						
							|  |  |  |                declarations: [Ng1ComponentFacade, Ng2Component], | 
					
						
							|  |  |  |                entryComponents: [Ng2Component], | 
					
						
							|  |  |  |                imports: [BrowserModule, UpgradeModule] | 
					
						
							|  |  |  |              }) | 
					
						
							|  |  |  |              class Ng2Module { | 
					
						
							|  |  |  |                ngDoBootstrap() {} | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              // Bootstrap
 | 
					
						
							|  |  |  |              const element = html(`<ng2></ng2>`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(() => { | 
					
						
							|  |  |  |                expect(mockExceptionHandler).not.toHaveBeenCalled(); | 
					
						
							|  |  |  |              }); | 
					
						
							|  |  |  |            })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         it('should assign resolved values to the controller instance (if `require` is not object)', | 
					
						
							|  |  |  |            async(() => { | 
					
						
							|  |  |  |              // Define `ng1Component`
 | 
					
						
							|  |  |  |              const ng1ComponentA: angular.IComponent = { | 
					
						
							|  |  |  |                template: 'ng1A(<div><ng2></ng2></div>)', | 
					
						
							|  |  |  |                controller: class {value = 'A';} | 
					
						
							|  |  |  |              }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              const ng1ComponentB: angular.IComponent = { | 
					
						
							|  |  |  |                template: `ng1B({{ $ctrl.getProps() }})`, | 
					
						
							|  |  |  |                require: '^ng1A', | 
					
						
							|  |  |  |                controller: class { | 
					
						
							|  |  |  |                  getProps() { | 
					
						
							|  |  |  |                    // If all goes well, there should be no keys on `this`
 | 
					
						
							|  |  |  |                    return Object.keys(this).join(', '); | 
					
						
							|  |  |  |                  } | 
					
						
							|  |  |  |                } | 
					
						
							|  |  |  |              }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              const ng1ComponentC: angular.IComponent = { | 
					
						
							|  |  |  |                template: `ng1C({{ $ctrl.getProps() }})`, | 
					
						
							|  |  |  |                require: ['?ng1A', '^ng1A', '^^ng1A', 'ng1C', '^ng1C', '?^^ng1C'], | 
					
						
							|  |  |  |                controller: class { | 
					
						
							|  |  |  |                  getProps() { | 
					
						
							|  |  |  |                    // If all goes well, there should be no keys on `this`
 | 
					
						
							|  |  |  |                    return Object.keys(this).join(', '); | 
					
						
							|  |  |  |                  } | 
					
						
							|  |  |  |                } | 
					
						
							|  |  |  |              }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              // Define `Ng1ComponentFacade`
 | 
					
						
							|  |  |  |              @Directive({selector: 'ng1B'}) | 
					
						
							|  |  |  |              class Ng1ComponentBFacade extends UpgradeComponent { | 
					
						
							|  |  |  |                constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                  super('ng1B', elementRef, injector); | 
					
						
							|  |  |  |                } | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              @Directive({selector: 'ng1C'}) | 
					
						
							|  |  |  |              class Ng1ComponentCFacade extends UpgradeComponent { | 
					
						
							|  |  |  |                constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                  super('ng1C', elementRef, injector); | 
					
						
							|  |  |  |                } | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              // Define `Ng2Component`
 | 
					
						
							|  |  |  |              @Component( | 
					
						
							|  |  |  |                  {selector: 'ng2', template: 'ng2(<div><ng1B></ng1B> | <ng1C></ng1C></div>)'}) | 
					
						
							|  |  |  |              class Ng2Component { | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              // Define `ng1Module`
 | 
					
						
							|  |  |  |              const ng1Module = angular.module('ng1Module', []) | 
					
						
							|  |  |  |                                    .component('ng1A', ng1ComponentA) | 
					
						
							|  |  |  |                                    .component('ng1B', ng1ComponentB) | 
					
						
							|  |  |  |                                    .component('ng1C', ng1ComponentC) | 
					
						
							|  |  |  |                                    .directive('ng2', downgradeComponent({component: Ng2Component})); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              // Define `Ng2Module`
 | 
					
						
							|  |  |  |              @NgModule({ | 
					
						
							|  |  |  |                declarations: [Ng1ComponentBFacade, Ng1ComponentCFacade, Ng2Component], | 
					
						
							|  |  |  |                entryComponents: [Ng2Component], | 
					
						
							|  |  |  |                imports: [BrowserModule, UpgradeModule] | 
					
						
							|  |  |  |              }) | 
					
						
							|  |  |  |              class Ng2Module { | 
					
						
							|  |  |  |                ngDoBootstrap() {} | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              // Bootstrap
 | 
					
						
							|  |  |  |              const element = html(`<ng1-a></ng1-a>`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(() => { | 
					
						
							|  |  |  |                expect(multiTrim(element.textContent)).toBe('ng1A(ng2(ng1B() | ng1C()))'); | 
					
						
							|  |  |  |              }); | 
					
						
							|  |  |  |            })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         it('should assign resolved values to the controller instance (if `require` is object)', | 
					
						
							|  |  |  |            async(() => { | 
					
						
							|  |  |  |              // Define `ng1Component`
 | 
					
						
							|  |  |  |              const ng1ComponentA: angular.IComponent = { | 
					
						
							|  |  |  |                template: 'ng1A(<div><ng2></ng2></div>)', | 
					
						
							|  |  |  |                controller: class {value = 'A';} | 
					
						
							|  |  |  |              }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              const ng1ComponentB: angular.IComponent = { | 
					
						
							|  |  |  |                template: `ng1B(
 | 
					
						
							|  |  |  |                  ng1A: {{ $ctrl.ng1ASelf.value }} | | 
					
						
							|  |  |  |                  ^ng1A: {{ $ctrl.ng1ASelfUp.value }} | | 
					
						
							|  |  |  |                  ^^ng1A: {{ $ctrl.ng1AParentUp.value }} | | 
					
						
							|  |  |  |                  ng1B: {{ $ctrl.ng1BSelf.value }} | | 
					
						
							|  |  |  |                  ^ng1B: {{ $ctrl.ng1BSelfUp.value }} | | 
					
						
							|  |  |  |                  ^^ng1B: {{ $ctrl.ng1BParentUp.value }} | 
					
						
							|  |  |  |                )`,
 | 
					
						
							|  |  |  |                require: { | 
					
						
							|  |  |  |                  ng1ASelf: '?ng1A', | 
					
						
							|  |  |  |                  ng1ASelfUp: '^ng1A', | 
					
						
							|  |  |  |                  ng1AParentUp: '^^ng1A', | 
					
						
							|  |  |  |                  ng1BSelf: 'ng1B', | 
					
						
							|  |  |  |                  ng1BSelfUp: '^ng1B', | 
					
						
							|  |  |  |                  ng1BParentUp: '?^^ng1B', | 
					
						
							|  |  |  |                }, | 
					
						
							|  |  |  |                controller: class {value = 'B';} | 
					
						
							|  |  |  |              }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              // Define `Ng1ComponentFacade`
 | 
					
						
							|  |  |  |              @Directive({selector: 'ng1B'}) | 
					
						
							|  |  |  |              class Ng1ComponentBFacade extends UpgradeComponent { | 
					
						
							|  |  |  |                constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                  super('ng1B', elementRef, injector); | 
					
						
							|  |  |  |                } | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              // Define `Ng2Component`
 | 
					
						
							|  |  |  |              @Component({selector: 'ng2', template: 'ng2(<div><ng1B></ng1B></div>)'}) | 
					
						
							|  |  |  |              class Ng2Component { | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              // Define `ng1Module`
 | 
					
						
							|  |  |  |              const ng1Module = angular.module('ng1Module', []) | 
					
						
							|  |  |  |                                    .component('ng1A', ng1ComponentA) | 
					
						
							|  |  |  |                                    .component('ng1B', ng1ComponentB) | 
					
						
							|  |  |  |                                    .directive('ng2', downgradeComponent({component: Ng2Component})); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              // Define `Ng2Module`
 | 
					
						
							|  |  |  |              @NgModule({ | 
					
						
							|  |  |  |                declarations: [Ng1ComponentBFacade, Ng2Component], | 
					
						
							|  |  |  |                entryComponents: [Ng2Component], | 
					
						
							|  |  |  |                imports: [BrowserModule, UpgradeModule] | 
					
						
							|  |  |  |              }) | 
					
						
							|  |  |  |              class Ng2Module { | 
					
						
							|  |  |  |                ngDoBootstrap() {} | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              // Bootstrap
 | 
					
						
							|  |  |  |              const element = html(`<ng1-a></ng1-a>`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(() => { | 
					
						
							|  |  |  |                expect(multiTrim(element.textContent)) | 
					
						
							|  |  |  |                    .toBe( | 
					
						
							|  |  |  |                        'ng1A(ng2(ng1B( ng1A: | ^ng1A: A | ^^ng1A: A | ng1B: B | ^ng1B: B | ^^ng1B: )))'); | 
					
						
							|  |  |  |              }); | 
					
						
							|  |  |  |            })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         it('should assign to controller before calling `$onInit()`', async(() => { | 
					
						
							|  |  |  |              // Define `ng1Component`
 | 
					
						
							|  |  |  |              const ng1ComponentA: angular.IComponent = { | 
					
						
							|  |  |  |                template: '<ng2></ng2>', | 
					
						
							|  |  |  |                controller: class {value = 'ng1A';} | 
					
						
							|  |  |  |              }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              const ng1ComponentB: angular.IComponent = { | 
					
						
							|  |  |  |                template: '$onInit: {{ $ctrl.onInitValue }}', | 
					
						
							|  |  |  |                require: {required: '^^ng1A'}, | 
					
						
							|  |  |  |                controller: class { | 
					
						
							|  |  |  |                  $onInit() { | 
					
						
							|  |  |  |                    const self = this as any; | 
					
						
							|  |  |  |                    self.onInitValue = self.required.value; | 
					
						
							|  |  |  |                  } | 
					
						
							|  |  |  |                } | 
					
						
							|  |  |  |              }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              // Define `Ng1ComponentFacade`
 | 
					
						
							|  |  |  |              @Directive({selector: 'ng1B'}) | 
					
						
							|  |  |  |              class Ng1ComponentBFacade extends UpgradeComponent { | 
					
						
							|  |  |  |                constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                  super('ng1B', elementRef, injector); | 
					
						
							|  |  |  |                } | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              // Define `Ng2Component`
 | 
					
						
							|  |  |  |              @Component({selector: 'ng2', template: '<ng1B></ng1B>'}) | 
					
						
							|  |  |  |              class Ng2Component { | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              // Define `ng1Module`
 | 
					
						
							|  |  |  |              const ng1Module = angular.module('ng1Module', []) | 
					
						
							|  |  |  |                                    .component('ng1A', ng1ComponentA) | 
					
						
							|  |  |  |                                    .component('ng1B', ng1ComponentB) | 
					
						
							|  |  |  |                                    .directive('ng2', downgradeComponent({component: Ng2Component})); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              // Define `Ng2Module`
 | 
					
						
							|  |  |  |              @NgModule({ | 
					
						
							|  |  |  |                declarations: [Ng1ComponentBFacade, Ng2Component], | 
					
						
							|  |  |  |                entryComponents: [Ng2Component], | 
					
						
							|  |  |  |                imports: [BrowserModule, UpgradeModule] | 
					
						
							|  |  |  |              }) | 
					
						
							|  |  |  |              class Ng2Module { | 
					
						
							|  |  |  |                ngDoBootstrap() {} | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              // Bootstrap
 | 
					
						
							|  |  |  |              const element = html(`<ng1-a></ng1-a>`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(() => { | 
					
						
							|  |  |  |                expect(multiTrim(element.textContent)).toBe('$onInit: ng1A'); | 
					
						
							|  |  |  |              }); | 
					
						
							|  |  |  |            })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         it('should use the key as name if the required controller name is omitted', async(() => { | 
					
						
							|  |  |  |              // Define `ng1Component`
 | 
					
						
							|  |  |  |              const ng1ComponentA: angular.IComponent = { | 
					
						
							|  |  |  |                template: '<ng1-b></ng1-b>', | 
					
						
							|  |  |  |                controller: class {value = 'A';} | 
					
						
							|  |  |  |              }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              const ng1ComponentB: | 
					
						
							|  |  |  |                  angular.IComponent = {template: '<ng2></ng2>', controller: class {value = 'B';}}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              const ng1ComponentC: angular.IComponent = { | 
					
						
							|  |  |  |                template: | 
					
						
							|  |  |  |                    'ng1A: {{ $ctrl.ng1A.value }} | ng1B: {{ $ctrl.ng1B.value }} | ng1C: {{ $ctrl.ng1C.value }}', | 
					
						
							|  |  |  |                require: { | 
					
						
							|  |  |  |                  ng1A: '^^', | 
					
						
							|  |  |  |                  ng1B: '?^', | 
					
						
							|  |  |  |                  ng1C: '', | 
					
						
							|  |  |  |                }, | 
					
						
							|  |  |  |                controller: class {value = 'C';} | 
					
						
							|  |  |  |              }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              // Define `Ng1ComponentFacade`
 | 
					
						
							|  |  |  |              @Directive({selector: 'ng1C'}) | 
					
						
							|  |  |  |              class Ng1ComponentCFacade extends UpgradeComponent { | 
					
						
							|  |  |  |                constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                  super('ng1C', elementRef, injector); | 
					
						
							|  |  |  |                } | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              // Define `Ng2Component`
 | 
					
						
							|  |  |  |              @Component({selector: 'ng2', template: '<ng1C></ng1C>'}) | 
					
						
							|  |  |  |              class Ng2Component { | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              // Define `ng1Module`
 | 
					
						
							|  |  |  |              const ng1Module = angular.module('ng1Module', []) | 
					
						
							|  |  |  |                                    .component('ng1A', ng1ComponentA) | 
					
						
							|  |  |  |                                    .component('ng1B', ng1ComponentB) | 
					
						
							|  |  |  |                                    .component('ng1C', ng1ComponentC) | 
					
						
							|  |  |  |                                    .directive('ng2', downgradeComponent({component: Ng2Component})); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              // Define `Ng2Module`
 | 
					
						
							|  |  |  |              @NgModule({ | 
					
						
							|  |  |  |                declarations: [Ng1ComponentCFacade, Ng2Component], | 
					
						
							|  |  |  |                entryComponents: [Ng2Component], | 
					
						
							|  |  |  |                imports: [BrowserModule, UpgradeModule] | 
					
						
							|  |  |  |              }) | 
					
						
							|  |  |  |              class Ng2Module { | 
					
						
							|  |  |  |                ngDoBootstrap() {} | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              // Bootstrap
 | 
					
						
							|  |  |  |              const element = html('<ng1-a></ng1-a>'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(() => { | 
					
						
							|  |  |  |                expect(multiTrim(element.textContent)).toBe('ng1A: A | ng1B: B | ng1C: C'); | 
					
						
							|  |  |  |              }); | 
					
						
							|  |  |  |            })); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-05 13:58:27 +03:00
										 |  |  |     describe('transclusion', () => { | 
					
						
							| 
									
										
										
										
											2019-01-09 14:20:19 +01:00
										 |  |  |       it('should support single-slot transclusion', async(() => { | 
					
						
							|  |  |  |            let ng2ComponentAInstance: Ng2ComponentA; | 
					
						
							|  |  |  |            let ng2ComponentBInstance: Ng2ComponentB; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Component`
 | 
					
						
							|  |  |  |            const ng1Component: | 
					
						
							|  |  |  |                angular.IComponent = {template: 'ng1(<div ng-transclude></div>)', transclude: true}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng1ComponentFacade`
 | 
					
						
							|  |  |  |            @Directive({selector: 'ng1'}) | 
					
						
							|  |  |  |            class Ng1ComponentFacade extends UpgradeComponent { | 
					
						
							|  |  |  |              constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                super('ng1', elementRef, injector); | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Component`
 | 
					
						
							|  |  |  |            @Component({ | 
					
						
							|  |  |  |              selector: 'ng2A', | 
					
						
							|  |  |  |              template: 'ng2A(<ng1>{{ value }} | <ng2B *ngIf="showB"></ng2B></ng1>)' | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2ComponentA { | 
					
						
							|  |  |  |              value = 'foo'; | 
					
						
							|  |  |  |              showB = false; | 
					
						
							|  |  |  |              constructor() { ng2ComponentAInstance = this; } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            @Component({selector: 'ng2B', template: 'ng2B({{ value }})'}) | 
					
						
							|  |  |  |            class Ng2ComponentB { | 
					
						
							|  |  |  |              value = 'bar'; | 
					
						
							|  |  |  |              constructor() { ng2ComponentBInstance = this; } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Module`
 | 
					
						
							|  |  |  |            const ng1Module = angular.module('ng1Module', []) | 
					
						
							|  |  |  |                                  .component('ng1', ng1Component) | 
					
						
							|  |  |  |                                  .directive('ng2A', downgradeComponent({component: Ng2ComponentA})); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Module`
 | 
					
						
							|  |  |  |            @NgModule({ | 
					
						
							|  |  |  |              imports: [BrowserModule, UpgradeModule], | 
					
						
							|  |  |  |              declarations: [Ng1ComponentFacade, Ng2ComponentA, Ng2ComponentB], | 
					
						
							|  |  |  |              entryComponents: [Ng2ComponentA] | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Module { | 
					
						
							|  |  |  |              ngDoBootstrap() {} | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Bootstrap
 | 
					
						
							|  |  |  |            const element = html(`<ng2-a></ng2-a>`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(adapter => { | 
					
						
							|  |  |  |              expect(multiTrim(element.textContent)).toBe('ng2A(ng1(foo | ))'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              ng2ComponentAInstance.value = 'baz'; | 
					
						
							|  |  |  |              ng2ComponentAInstance.showB = true; | 
					
						
							|  |  |  |              $digest(adapter); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(multiTrim(element.textContent)).toBe('ng2A(ng1(baz | ng2B(bar)))'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              ng2ComponentBInstance.value = 'qux'; | 
					
						
							|  |  |  |              $digest(adapter); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(multiTrim(element.textContent)).toBe('ng2A(ng1(baz | ng2B(qux)))'); | 
					
						
							|  |  |  |            }); | 
					
						
							|  |  |  |          })); | 
					
						
							| 
									
										
										
										
											2017-07-05 13:58:27 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |       it('should support single-slot transclusion with fallback content', async(() => { | 
					
						
							|  |  |  |            let ng1ControllerInstances: any[] = []; | 
					
						
							|  |  |  |            let ng2ComponentInstance: Ng2Component; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Component`
 | 
					
						
							|  |  |  |            const ng1Component: angular.IComponent = { | 
					
						
							|  |  |  |              template: 'ng1(<div ng-transclude>{{ $ctrl.value }}</div>)', | 
					
						
							|  |  |  |              transclude: true, | 
					
						
							|  |  |  |              controller: | 
					
						
							|  |  |  |                  class {value = 'from-ng1'; constructor() { ng1ControllerInstances.push(this); }} | 
					
						
							|  |  |  |            }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng1ComponentFacade`
 | 
					
						
							|  |  |  |            @Directive({selector: 'ng1'}) | 
					
						
							|  |  |  |            class Ng1ComponentFacade extends UpgradeComponent { | 
					
						
							|  |  |  |              constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                super('ng1', elementRef, injector); | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Component`
 | 
					
						
							|  |  |  |            @Component({selector: 'ng2', template: 'ng2(<ng1>{{ value }}</ng1> | <ng1></ng1>)'}) | 
					
						
							|  |  |  |            class Ng2Component { | 
					
						
							|  |  |  |              value = 'from-ng2'; | 
					
						
							|  |  |  |              constructor() { ng2ComponentInstance = this; } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Module`
 | 
					
						
							|  |  |  |            const ng1Module = angular.module('ng1Module', []) | 
					
						
							|  |  |  |                                  .component('ng1', ng1Component) | 
					
						
							|  |  |  |                                  .directive('ng2', downgradeComponent({component: Ng2Component})); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Module`
 | 
					
						
							|  |  |  |            @NgModule({ | 
					
						
							|  |  |  |              imports: [BrowserModule, UpgradeModule], | 
					
						
							|  |  |  |              declarations: [Ng1ComponentFacade, Ng2Component], | 
					
						
							|  |  |  |              entryComponents: [Ng2Component] | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Module { | 
					
						
							|  |  |  |              ngDoBootstrap() {} | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Bootstrap
 | 
					
						
							|  |  |  |            const element = html(`<ng2></ng2>`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(adapter => { | 
					
						
							|  |  |  |              expect(multiTrim(element.textContent)).toBe('ng2(ng1(from-ng2) | ng1(from-ng1))'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              ng1ControllerInstances.forEach(ctrl => ctrl.value = 'ng1-foo'); | 
					
						
							|  |  |  |              ng2ComponentInstance.value = 'ng2-bar'; | 
					
						
							|  |  |  |              $digest(adapter); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(multiTrim(element.textContent)).toBe('ng2(ng1(ng2-bar) | ng1(ng1-foo))'); | 
					
						
							|  |  |  |            }); | 
					
						
							|  |  |  |          })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should support multi-slot transclusion', async(() => { | 
					
						
							|  |  |  |            let ng2ComponentInstance: Ng2Component; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Component`
 | 
					
						
							|  |  |  |            const ng1Component: angular.IComponent = { | 
					
						
							|  |  |  |              template: | 
					
						
							|  |  |  |                  'ng1(x(<div ng-transclude="slotX"></div>) | y(<div ng-transclude="slotY"></div>))', | 
					
						
							|  |  |  |              transclude: {slotX: 'contentX', slotY: 'contentY'} | 
					
						
							|  |  |  |            }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng1ComponentFacade`
 | 
					
						
							|  |  |  |            @Directive({selector: 'ng1'}) | 
					
						
							|  |  |  |            class Ng1ComponentFacade extends UpgradeComponent { | 
					
						
							|  |  |  |              constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                super('ng1', elementRef, injector); | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Component`
 | 
					
						
							|  |  |  |            @Component({ | 
					
						
							|  |  |  |              selector: 'ng2', | 
					
						
							|  |  |  |              template: `
 | 
					
						
							|  |  |  |                ng2( | 
					
						
							|  |  |  |                  <ng1> | 
					
						
							|  |  |  |                    <content-x>{{ x }}1</content-x> | 
					
						
							|  |  |  |                    <content-y>{{ y }}1</content-y> | 
					
						
							|  |  |  |                    <content-x>{{ x }}2</content-x> | 
					
						
							|  |  |  |                    <content-y>{{ y }}2</content-y> | 
					
						
							|  |  |  |                  </ng1> | 
					
						
							|  |  |  |                )`
 | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Component { | 
					
						
							|  |  |  |              x = 'foo'; | 
					
						
							|  |  |  |              y = 'bar'; | 
					
						
							|  |  |  |              constructor() { ng2ComponentInstance = this; } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Module`
 | 
					
						
							|  |  |  |            const ng1Module = angular.module('ng1Module', []) | 
					
						
							|  |  |  |                                  .component('ng1', ng1Component) | 
					
						
							|  |  |  |                                  .directive('ng2', downgradeComponent({component: Ng2Component})); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Module`
 | 
					
						
							|  |  |  |            @NgModule({ | 
					
						
							|  |  |  |              imports: [BrowserModule, UpgradeModule], | 
					
						
							|  |  |  |              declarations: [Ng1ComponentFacade, Ng2Component], | 
					
						
							|  |  |  |              entryComponents: [Ng2Component], | 
					
						
							|  |  |  |              schemas: [NO_ERRORS_SCHEMA] | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Module { | 
					
						
							|  |  |  |              ngDoBootstrap() {} | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Bootstrap
 | 
					
						
							|  |  |  |            const element = html(`<ng2></ng2>`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(adapter => { | 
					
						
							|  |  |  |              expect(multiTrim(element.textContent, true)).toBe('ng2(ng1(x(foo1foo2)|y(bar1bar2)))'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              ng2ComponentInstance.x = 'baz'; | 
					
						
							|  |  |  |              ng2ComponentInstance.y = 'qux'; | 
					
						
							|  |  |  |              $digest(adapter); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(multiTrim(element.textContent, true)).toBe('ng2(ng1(x(baz1baz2)|y(qux1qux2)))'); | 
					
						
							|  |  |  |            }); | 
					
						
							|  |  |  |          })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should support default slot (with fallback content)', async(() => { | 
					
						
							|  |  |  |            let ng1ControllerInstances: any[] = []; | 
					
						
							|  |  |  |            let ng2ComponentInstance: Ng2Component; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Component`
 | 
					
						
							|  |  |  |            const ng1Component: angular.IComponent = { | 
					
						
							|  |  |  |              template: 'ng1(default(<div ng-transclude="">fallback-{{ $ctrl.value }}</div>))', | 
					
						
							|  |  |  |              transclude: {slotX: 'contentX', slotY: 'contentY'}, | 
					
						
							|  |  |  |              controller: | 
					
						
							|  |  |  |                  class {value = 'ng1'; constructor() { ng1ControllerInstances.push(this); }} | 
					
						
							|  |  |  |            }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng1ComponentFacade`
 | 
					
						
							|  |  |  |            @Directive({selector: 'ng1'}) | 
					
						
							|  |  |  |            class Ng1ComponentFacade extends UpgradeComponent { | 
					
						
							|  |  |  |              constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                super('ng1', elementRef, injector); | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Component`
 | 
					
						
							|  |  |  |            @Component({ | 
					
						
							|  |  |  |              selector: 'ng2', | 
					
						
							|  |  |  |              template: `
 | 
					
						
							|  |  |  |                ng2( | 
					
						
							|  |  |  |                  <ng1> | 
					
						
							|  |  |  |                    ({{ x }}) | 
					
						
							|  |  |  |                    <content-x>ignored x</content-x> | 
					
						
							|  |  |  |                    {{ x }}-<span>{{ y }}</span> | 
					
						
							|  |  |  |                    <content-y>ignored y</content-y> | 
					
						
							|  |  |  |                    <span>({{ y }})</span> | 
					
						
							|  |  |  |                  </ng1> | | 
					
						
							|  |  |  |                  <!--
 | 
					
						
							|  |  |  |                    Remove any whitespace, because in AngularJS versions prior to 1.6 | 
					
						
							|  |  |  |                    even whitespace counts as transcluded content. | 
					
						
							|  |  |  |                  --> | 
					
						
							|  |  |  |                  <ng1><content-x>ignored x</content-x><content-y>ignored y</content-y></ng1> | 
					
						
							|  |  |  |                )`
 | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Component { | 
					
						
							|  |  |  |              x = 'foo'; | 
					
						
							|  |  |  |              y = 'bar'; | 
					
						
							|  |  |  |              constructor() { ng2ComponentInstance = this; } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Module`
 | 
					
						
							|  |  |  |            const ng1Module = angular.module('ng1Module', []) | 
					
						
							|  |  |  |                                  .component('ng1', ng1Component) | 
					
						
							|  |  |  |                                  .directive('ng2', downgradeComponent({component: Ng2Component})); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Module`
 | 
					
						
							|  |  |  |            @NgModule({ | 
					
						
							|  |  |  |              imports: [BrowserModule, UpgradeModule], | 
					
						
							|  |  |  |              declarations: [Ng1ComponentFacade, Ng2Component], | 
					
						
							|  |  |  |              entryComponents: [Ng2Component], | 
					
						
							|  |  |  |              schemas: [NO_ERRORS_SCHEMA] | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Module { | 
					
						
							|  |  |  |              ngDoBootstrap() {} | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Bootstrap
 | 
					
						
							|  |  |  |            const element = html(`<ng2></ng2>`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(adapter => { | 
					
						
							|  |  |  |              expect(multiTrim(element.textContent, true)) | 
					
						
							|  |  |  |                  .toBe('ng2(ng1(default((foo)foo-bar(bar)))|ng1(default(fallback-ng1)))'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              ng1ControllerInstances.forEach(ctrl => ctrl.value = 'ng1-plus'); | 
					
						
							|  |  |  |              ng2ComponentInstance.x = 'baz'; | 
					
						
							|  |  |  |              ng2ComponentInstance.y = 'qux'; | 
					
						
							|  |  |  |              $digest(adapter); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(multiTrim(element.textContent, true)) | 
					
						
							|  |  |  |                  .toBe('ng2(ng1(default((baz)baz-qux(qux)))|ng1(default(fallback-ng1-plus)))'); | 
					
						
							|  |  |  |            }); | 
					
						
							|  |  |  |          })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should support optional transclusion slots (with fallback content)', async(() => { | 
					
						
							|  |  |  |            let ng1ControllerInstances: any[] = []; | 
					
						
							|  |  |  |            let ng2ComponentInstance: Ng2Component; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Component`
 | 
					
						
							|  |  |  |            const ng1Component: angular.IComponent = { | 
					
						
							|  |  |  |              template: `
 | 
					
						
							|  |  |  |                ng1( | 
					
						
							|  |  |  |                 x(<div ng-transclude="slotX">{{ $ctrl.x }}</div>) | | 
					
						
							|  |  |  |                 y(<div ng-transclude="slotY">{{ $ctrl.y }}</div>) | 
					
						
							|  |  |  |                )`,
 | 
					
						
							|  |  |  |              transclude: {slotX: '?contentX', slotY: '?contentY'}, | 
					
						
							|  |  |  |              controller: class { | 
					
						
							|  |  |  |                x = 'ng1X'; y = 'ng1Y'; constructor() { ng1ControllerInstances.push(this); } | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng1ComponentFacade`
 | 
					
						
							|  |  |  |            @Directive({selector: 'ng1'}) | 
					
						
							|  |  |  |            class Ng1ComponentFacade extends UpgradeComponent { | 
					
						
							|  |  |  |              constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                super('ng1', elementRef, injector); | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Component`
 | 
					
						
							|  |  |  |            @Component({ | 
					
						
							|  |  |  |              selector: 'ng2', | 
					
						
							|  |  |  |              template: `
 | 
					
						
							|  |  |  |                ng2( | 
					
						
							|  |  |  |                  <ng1><content-x>{{ x }}</content-x></ng1> | | 
					
						
							|  |  |  |                  <ng1><content-y>{{ y }}</content-y></ng1> | 
					
						
							|  |  |  |                )`
 | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Component { | 
					
						
							|  |  |  |              x = 'ng2X'; | 
					
						
							|  |  |  |              y = 'ng2Y'; | 
					
						
							|  |  |  |              constructor() { ng2ComponentInstance = this; } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Module`
 | 
					
						
							|  |  |  |            const ng1Module = angular.module('ng1Module', []) | 
					
						
							|  |  |  |                                  .component('ng1', ng1Component) | 
					
						
							|  |  |  |                                  .directive('ng2', downgradeComponent({component: Ng2Component})); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Module`
 | 
					
						
							|  |  |  |            @NgModule({ | 
					
						
							|  |  |  |              imports: [BrowserModule, UpgradeModule], | 
					
						
							|  |  |  |              declarations: [Ng1ComponentFacade, Ng2Component], | 
					
						
							|  |  |  |              entryComponents: [Ng2Component], | 
					
						
							|  |  |  |              schemas: [NO_ERRORS_SCHEMA] | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Module { | 
					
						
							|  |  |  |              ngDoBootstrap() {} | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Bootstrap
 | 
					
						
							|  |  |  |            const element = html(`<ng2></ng2>`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(adapter => { | 
					
						
							|  |  |  |              expect(multiTrim(element.textContent, true)) | 
					
						
							|  |  |  |                  .toBe('ng2(ng1(x(ng2X)|y(ng1Y))|ng1(x(ng1X)|y(ng2Y)))'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              ng1ControllerInstances.forEach(ctrl => { | 
					
						
							|  |  |  |                ctrl.x = 'ng1X-foo'; | 
					
						
							|  |  |  |                ctrl.y = 'ng1Y-bar'; | 
					
						
							|  |  |  |              }); | 
					
						
							|  |  |  |              ng2ComponentInstance.x = 'ng2X-baz'; | 
					
						
							|  |  |  |              ng2ComponentInstance.y = 'ng2Y-qux'; | 
					
						
							|  |  |  |              $digest(adapter); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(multiTrim(element.textContent, true)) | 
					
						
							|  |  |  |                  .toBe('ng2(ng1(x(ng2X-baz)|y(ng1Y-bar))|ng1(x(ng1X-foo)|y(ng2Y-qux)))'); | 
					
						
							|  |  |  |            }); | 
					
						
							|  |  |  |          })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should throw if a non-optional slot is not filled', async(() => { | 
					
						
							|  |  |  |            let errorMessage: string; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Component`
 | 
					
						
							|  |  |  |            const ng1Component: angular.IComponent = { | 
					
						
							|  |  |  |              template: '', | 
					
						
							|  |  |  |              transclude: {slotX: '?contentX', slotY: 'contentY'} | 
					
						
							|  |  |  |            }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng1ComponentFacade`
 | 
					
						
							|  |  |  |            @Directive({selector: 'ng1'}) | 
					
						
							|  |  |  |            class Ng1ComponentFacade extends UpgradeComponent { | 
					
						
							|  |  |  |              constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                super('ng1', elementRef, injector); | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Component`
 | 
					
						
							|  |  |  |            @Component({selector: 'ng2', template: '<ng1></ng1>'}) | 
					
						
							|  |  |  |            class Ng2Component { | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Module`
 | 
					
						
							|  |  |  |            const ng1Module = | 
					
						
							|  |  |  |                angular.module('ng1Module', []) | 
					
						
							| 
									
										
										
										
											2018-10-11 17:44:59 +03:00
										 |  |  |                    .value($EXCEPTION_HANDLER, (error: Error) => errorMessage = error.message) | 
					
						
							| 
									
										
										
										
											2017-07-05 13:58:27 +03:00
										 |  |  |                    .component('ng1', ng1Component) | 
					
						
							|  |  |  |                    .directive('ng2', downgradeComponent({component: Ng2Component})); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Module`
 | 
					
						
							|  |  |  |            @NgModule({ | 
					
						
							|  |  |  |              imports: [BrowserModule, UpgradeModule], | 
					
						
							|  |  |  |              declarations: [Ng1ComponentFacade, Ng2Component], | 
					
						
							|  |  |  |              entryComponents: [Ng2Component] | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Module { | 
					
						
							|  |  |  |              ngDoBootstrap() {} | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Bootstrap
 | 
					
						
							|  |  |  |            const element = html(`<ng2></ng2>`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(adapter => { | 
					
						
							|  |  |  |              expect(errorMessage) | 
					
						
							|  |  |  |                  .toContain('Required transclusion slot \'slotY\' on directive: ng1'); | 
					
						
							|  |  |  |            }); | 
					
						
							|  |  |  |          })); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-09 14:20:19 +01:00
										 |  |  |       it('should support structural directives in transcluded content', async(() => { | 
					
						
							|  |  |  |            let ng2ComponentInstance: Ng2Component; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Component`
 | 
					
						
							|  |  |  |            const ng1Component: angular.IComponent = { | 
					
						
							|  |  |  |              template: | 
					
						
							|  |  |  |                  'ng1(x(<div ng-transclude="slotX"></div>) | default(<div ng-transclude=""></div>))', | 
					
						
							|  |  |  |              transclude: {slotX: 'contentX'} | 
					
						
							|  |  |  |            }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng1ComponentFacade`
 | 
					
						
							|  |  |  |            @Directive({selector: 'ng1'}) | 
					
						
							|  |  |  |            class Ng1ComponentFacade extends UpgradeComponent { | 
					
						
							|  |  |  |              constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                super('ng1', elementRef, injector); | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Component`
 | 
					
						
							|  |  |  |            @Component({ | 
					
						
							|  |  |  |              selector: 'ng2', | 
					
						
							|  |  |  |              template: `
 | 
					
						
							| 
									
										
										
										
											2017-07-05 13:58:27 +03:00
										 |  |  |                ng2( | 
					
						
							|  |  |  |                  <ng1> | 
					
						
							|  |  |  |                    <content-x><div *ngIf="show">{{ x }}1</div></content-x> | 
					
						
							|  |  |  |                    <div *ngIf="!show">{{ y }}1</div> | 
					
						
							|  |  |  |                    <content-x><div *ngIf="!show">{{ x }}2</div></content-x> | 
					
						
							|  |  |  |                    <div *ngIf="show">{{ y }}2</div> | 
					
						
							|  |  |  |                  </ng1> | 
					
						
							|  |  |  |                )`
 | 
					
						
							| 
									
										
										
										
											2019-01-09 14:20:19 +01:00
										 |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Component { | 
					
						
							|  |  |  |              x = 'foo'; | 
					
						
							|  |  |  |              y = 'bar'; | 
					
						
							|  |  |  |              show = true; | 
					
						
							|  |  |  |              constructor() { ng2ComponentInstance = this; } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Module`
 | 
					
						
							|  |  |  |            const ng1Module = angular.module('ng1Module', []) | 
					
						
							|  |  |  |                                  .component('ng1', ng1Component) | 
					
						
							|  |  |  |                                  .directive('ng2', downgradeComponent({component: Ng2Component})); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Module`
 | 
					
						
							|  |  |  |            @NgModule({ | 
					
						
							|  |  |  |              imports: [BrowserModule, UpgradeModule], | 
					
						
							|  |  |  |              declarations: [Ng1ComponentFacade, Ng2Component], | 
					
						
							|  |  |  |              entryComponents: [Ng2Component], | 
					
						
							|  |  |  |              schemas: [NO_ERRORS_SCHEMA] | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Module { | 
					
						
							|  |  |  |              ngDoBootstrap() {} | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Bootstrap
 | 
					
						
							|  |  |  |            const element = html(`<ng2></ng2>`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(adapter => { | 
					
						
							|  |  |  |              expect(multiTrim(element.textContent, true)).toBe('ng2(ng1(x(foo1)|default(bar2)))'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              ng2ComponentInstance.x = 'baz'; | 
					
						
							|  |  |  |              ng2ComponentInstance.y = 'qux'; | 
					
						
							|  |  |  |              ng2ComponentInstance.show = false; | 
					
						
							|  |  |  |              $digest(adapter); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(multiTrim(element.textContent, true)).toBe('ng2(ng1(x(baz2)|default(qux1)))'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              ng2ComponentInstance.show = true; | 
					
						
							|  |  |  |              $digest(adapter); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(multiTrim(element.textContent, true)).toBe('ng2(ng1(x(baz1)|default(qux2)))'); | 
					
						
							|  |  |  |            }); | 
					
						
							|  |  |  |          })); | 
					
						
							| 
									
										
										
										
											2017-07-05 13:58:27 +03:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  |     describe('lifecycle hooks', () => { | 
					
						
							| 
									
										
										
										
											2016-10-20 13:42:57 +03:00
										 |  |  |       it('should call `$onChanges()` on binding destination (prototype)', fakeAsync(() => { | 
					
						
							|  |  |  |            const scopeOnChanges = jasmine.createSpy('scopeOnChanges'); | 
					
						
							|  |  |  |            const controllerOnChangesA = jasmine.createSpy('controllerOnChangesA'); | 
					
						
							|  |  |  |            const controllerOnChangesB = jasmine.createSpy('controllerOnChangesB'); | 
					
						
							|  |  |  |            let ng2ComponentInstance: Ng2Component; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Directive`
 | 
					
						
							|  |  |  |            const ng1DirectiveA: angular.IDirective = { | 
					
						
							|  |  |  |              template: '', | 
					
						
							|  |  |  |              scope: {inputA: '<'}, | 
					
						
							|  |  |  |              bindToController: false, | 
					
						
							|  |  |  |              controllerAs: '$ctrl', | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  |              controller: | 
					
						
							|  |  |  |                  class {$onChanges(changes: SimpleChanges) { controllerOnChangesA(changes); }} | 
					
						
							| 
									
										
										
										
											2016-10-20 13:42:57 +03:00
										 |  |  |            }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            const ng1DirectiveB: angular.IDirective = { | 
					
						
							|  |  |  |              template: '', | 
					
						
							|  |  |  |              scope: {inputB: '<'}, | 
					
						
							|  |  |  |              bindToController: true, | 
					
						
							|  |  |  |              controllerAs: '$ctrl', | 
					
						
							| 
									
										
											  
											
												fix(upgrade): populate upgraded component's view before creating the controller (#14289)
Previously, the relative order of the AngularJS compiling/linking operations was
not similar to AngularJS's, resulting in inconsistent behavior for upgraded
components (which made upgrading to Angular less straight forward).
This commit fixes it, by following the compiling/linking process of AngularJS
more closely.
Main differences:
- The components view is already populated when the controller is instantiated
  (and subsequent hooks are called).
- The correct DOM content is available when running the `$onChanges`, `$onInit`,
  `$doCheck` hooks. Previously, the "content children" were still present, not
  the "view children".
- The same for pre-linking.
- The template is compiled in the correct DOM context (e.g. has access to
  ancestors). Previously, it was compiled in isolation, inside a dummy element.
For reference, here is the order of operations:
**Before**
1. Compile template
2. Instantiate controller
3. Hook: $onChanges
4. Hook: $onInit
5. Hook: $doCheck
6. Pre-linking
7. Collect content children
8. Insert compiled template
9. Linking
10. Post-linking
11. Hook: $postLink
**After**
1. Collect content children
2. Insert template
3. Compile template
4. Instantiate controller
5. Hook: $onChanges
6. Hook: $onInit
7. Hook: $doCheck
8. Pre-linking
9. Linking
10. Post-linking
11. Hook: $postLink
Fixes #13912
											
										 
											2017-03-07 19:32:52 +02:00
										 |  |  |              controller: | 
					
						
							|  |  |  |                  class {$onChanges(changes: SimpleChanges) { controllerOnChangesB(changes); }} | 
					
						
							| 
									
										
										
										
											2016-10-20 13:42:57 +03:00
										 |  |  |            }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng1ComponentFacade`
 | 
					
						
							|  |  |  |            @Directive({selector: 'ng1A'}) | 
					
						
							|  |  |  |            class Ng1ComponentAFacade extends UpgradeComponent { | 
					
						
							|  |  |  |              @Input() inputA: any; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                super('ng1A', elementRef, injector); | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            @Directive({selector: 'ng1B'}) | 
					
						
							|  |  |  |            class Ng1ComponentBFacade extends UpgradeComponent { | 
					
						
							|  |  |  |              @Input() inputB: any; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                super('ng1B', elementRef, injector); | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Component`
 | 
					
						
							|  |  |  |            @Component({ | 
					
						
							|  |  |  |              selector: 'ng2', | 
					
						
							|  |  |  |              template: '<ng1A [inputA]="data"></ng1A> | <ng1B [inputB]="data"></ng1B>' | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Component { | 
					
						
							|  |  |  |              data = {foo: 'bar'}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              constructor() { ng2ComponentInstance = this; } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Module`
 | 
					
						
							|  |  |  |            const ng1Module = angular.module('ng1Module', []) | 
					
						
							|  |  |  |                                  .directive('ng1A', () => ng1DirectiveA) | 
					
						
							|  |  |  |                                  .directive('ng1B', () => ng1DirectiveB) | 
					
						
							| 
									
										
											  
											
												fix(upgrade): populate upgraded component's view before creating the controller (#14289)
Previously, the relative order of the AngularJS compiling/linking operations was
not similar to AngularJS's, resulting in inconsistent behavior for upgraded
components (which made upgrading to Angular less straight forward).
This commit fixes it, by following the compiling/linking process of AngularJS
more closely.
Main differences:
- The components view is already populated when the controller is instantiated
  (and subsequent hooks are called).
- The correct DOM content is available when running the `$onChanges`, `$onInit`,
  `$doCheck` hooks. Previously, the "content children" were still present, not
  the "view children".
- The same for pre-linking.
- The template is compiled in the correct DOM context (e.g. has access to
  ancestors). Previously, it was compiled in isolation, inside a dummy element.
For reference, here is the order of operations:
**Before**
1. Compile template
2. Instantiate controller
3. Hook: $onChanges
4. Hook: $onInit
5. Hook: $doCheck
6. Pre-linking
7. Collect content children
8. Insert compiled template
9. Linking
10. Post-linking
11. Hook: $postLink
**After**
1. Collect content children
2. Insert template
3. Compile template
4. Instantiate controller
5. Hook: $onChanges
6. Hook: $onInit
7. Hook: $doCheck
8. Pre-linking
9. Linking
10. Post-linking
11. Hook: $postLink
Fixes #13912
											
										 
											2017-03-07 19:32:52 +02:00
										 |  |  |                                  .directive('ng2', downgradeComponent({component: Ng2Component})) | 
					
						
							|  |  |  |                                  .run(($rootScope: angular.IRootScopeService) => { | 
					
						
							|  |  |  |                                    Object.getPrototypeOf($rootScope)['$onChanges'] = scopeOnChanges; | 
					
						
							|  |  |  |                                  }); | 
					
						
							| 
									
										
										
										
											2016-10-20 13:42:57 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Module`
 | 
					
						
							|  |  |  |            @NgModule({ | 
					
						
							|  |  |  |              declarations: [Ng1ComponentAFacade, Ng1ComponentBFacade, Ng2Component], | 
					
						
							|  |  |  |              entryComponents: [Ng2Component], | 
					
						
							|  |  |  |              imports: [BrowserModule, UpgradeModule] | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Module { | 
					
						
							|  |  |  |              ngDoBootstrap() {} | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Bootstrap
 | 
					
						
							|  |  |  |            const element = html(`<ng2></ng2>`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(adapter => { | 
					
						
							|  |  |  |              // Initial change
 | 
					
						
							|  |  |  |              expect(scopeOnChanges.calls.count()).toBe(1); | 
					
						
							|  |  |  |              expect(controllerOnChangesA).not.toHaveBeenCalled(); | 
					
						
							|  |  |  |              expect(controllerOnChangesB.calls.count()).toBe(1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(scopeOnChanges.calls.argsFor(0)[0]).toEqual({inputA: jasmine.any(Object)}); | 
					
						
							|  |  |  |              expect(scopeOnChanges.calls.argsFor(0)[0].inputA.currentValue).toEqual({foo: 'bar'}); | 
					
						
							|  |  |  |              expect(scopeOnChanges.calls.argsFor(0)[0].inputA.isFirstChange()).toBe(true); | 
					
						
							|  |  |  |              expect(controllerOnChangesB.calls.argsFor(0)[0].inputB.currentValue).toEqual({ | 
					
						
							|  |  |  |                foo: 'bar' | 
					
						
							|  |  |  |              }); | 
					
						
							|  |  |  |              expect(controllerOnChangesB.calls.argsFor(0)[0].inputB.isFirstChange()).toBe(true); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              // Change: Re-assign `data`
 | 
					
						
							|  |  |  |              ng2ComponentInstance.data = {foo: 'baz'}; | 
					
						
							| 
									
										
										
										
											2017-02-04 17:19:09 +02:00
										 |  |  |              $digest(adapter); | 
					
						
							| 
									
										
										
										
											2016-10-20 13:42:57 +03:00
										 |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(scopeOnChanges.calls.count()).toBe(2); | 
					
						
							|  |  |  |              expect(controllerOnChangesA).not.toHaveBeenCalled(); | 
					
						
							|  |  |  |              expect(controllerOnChangesB.calls.count()).toBe(2); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(scopeOnChanges.calls.argsFor(1)[0]).toEqual({inputA: jasmine.any(Object)}); | 
					
						
							|  |  |  |              expect(scopeOnChanges.calls.argsFor(1)[0].inputA.previousValue).toEqual({foo: 'bar'}); | 
					
						
							|  |  |  |              expect(scopeOnChanges.calls.argsFor(1)[0].inputA.currentValue).toEqual({foo: 'baz'}); | 
					
						
							|  |  |  |              expect(scopeOnChanges.calls.argsFor(1)[0].inputA.isFirstChange()).toBe(false); | 
					
						
							|  |  |  |              expect(controllerOnChangesB.calls.argsFor(1)[0].inputB.previousValue).toEqual({ | 
					
						
							|  |  |  |                foo: 'bar' | 
					
						
							|  |  |  |              }); | 
					
						
							|  |  |  |              expect(controllerOnChangesB.calls.argsFor(1)[0].inputB.currentValue).toEqual({ | 
					
						
							|  |  |  |                foo: 'baz' | 
					
						
							|  |  |  |              }); | 
					
						
							|  |  |  |              expect(controllerOnChangesB.calls.argsFor(1)[0].inputB.isFirstChange()).toBe(false); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              // No change: Update internal property
 | 
					
						
							|  |  |  |              ng2ComponentInstance.data.foo = 'qux'; | 
					
						
							| 
									
										
										
										
											2017-02-04 17:19:09 +02:00
										 |  |  |              $digest(adapter); | 
					
						
							| 
									
										
										
										
											2016-10-20 13:42:57 +03:00
										 |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(scopeOnChanges.calls.count()).toBe(2); | 
					
						
							|  |  |  |              expect(controllerOnChangesA).not.toHaveBeenCalled(); | 
					
						
							|  |  |  |              expect(controllerOnChangesB.calls.count()).toBe(2); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              // Change: Re-assign `data` (even if it looks the same)
 | 
					
						
							|  |  |  |              ng2ComponentInstance.data = {foo: 'qux'}; | 
					
						
							| 
									
										
										
										
											2017-02-04 17:19:09 +02:00
										 |  |  |              $digest(adapter); | 
					
						
							| 
									
										
										
										
											2016-10-20 13:42:57 +03:00
										 |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(scopeOnChanges.calls.count()).toBe(3); | 
					
						
							|  |  |  |              expect(controllerOnChangesA).not.toHaveBeenCalled(); | 
					
						
							|  |  |  |              expect(controllerOnChangesB.calls.count()).toBe(3); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(scopeOnChanges.calls.argsFor(2)[0]).toEqual({inputA: jasmine.any(Object)}); | 
					
						
							|  |  |  |              expect(scopeOnChanges.calls.argsFor(2)[0].inputA.previousValue).toEqual({foo: 'qux'}); | 
					
						
							|  |  |  |              expect(scopeOnChanges.calls.argsFor(2)[0].inputA.currentValue).toEqual({foo: 'qux'}); | 
					
						
							|  |  |  |              expect(scopeOnChanges.calls.argsFor(2)[0].inputA.isFirstChange()).toBe(false); | 
					
						
							|  |  |  |              expect(controllerOnChangesB.calls.argsFor(2)[0].inputB.previousValue).toEqual({ | 
					
						
							|  |  |  |                foo: 'qux' | 
					
						
							|  |  |  |              }); | 
					
						
							|  |  |  |              expect(controllerOnChangesB.calls.argsFor(2)[0].inputB.currentValue).toEqual({ | 
					
						
							|  |  |  |                foo: 'qux' | 
					
						
							|  |  |  |              }); | 
					
						
							|  |  |  |              expect(controllerOnChangesB.calls.argsFor(2)[0].inputB.isFirstChange()).toBe(false); | 
					
						
							|  |  |  |            }); | 
					
						
							|  |  |  |          })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should call `$onChanges()` on binding destination (instance)', fakeAsync(() => { | 
					
						
							|  |  |  |            const scopeOnChangesA = jasmine.createSpy('scopeOnChangesA'); | 
					
						
							|  |  |  |            const scopeOnChangesB = jasmine.createSpy('scopeOnChangesB'); | 
					
						
							|  |  |  |            const controllerOnChangesA = jasmine.createSpy('controllerOnChangesA'); | 
					
						
							|  |  |  |            const controllerOnChangesB = jasmine.createSpy('controllerOnChangesB'); | 
					
						
							|  |  |  |            let ng2ComponentInstance: Ng2Component; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Directive`
 | 
					
						
							|  |  |  |            const ng1DirectiveA: angular.IDirective = { | 
					
						
							|  |  |  |              template: '', | 
					
						
							|  |  |  |              scope: {inputA: '<'}, | 
					
						
							|  |  |  |              bindToController: false, | 
					
						
							|  |  |  |              controllerAs: '$ctrl', | 
					
						
							|  |  |  |              controller: class { | 
					
						
							|  |  |  |                constructor($scope: angular.IScope) { | 
					
						
							|  |  |  |                  $scope['$onChanges'] = scopeOnChangesA; | 
					
						
							|  |  |  |                  (this as any).$onChanges = controllerOnChangesA; | 
					
						
							|  |  |  |                } | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            const ng1DirectiveB: angular.IDirective = { | 
					
						
							|  |  |  |              template: '', | 
					
						
							|  |  |  |              scope: {inputB: '<'}, | 
					
						
							|  |  |  |              bindToController: true, | 
					
						
							|  |  |  |              controllerAs: '$ctrl', | 
					
						
							|  |  |  |              controller: class { | 
					
						
							|  |  |  |                constructor($scope: angular.IScope) { | 
					
						
							|  |  |  |                  $scope['$onChanges'] = scopeOnChangesB; | 
					
						
							|  |  |  |                  (this as any).$onChanges = controllerOnChangesB; | 
					
						
							|  |  |  |                } | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng1ComponentFacade`
 | 
					
						
							|  |  |  |            @Directive({selector: 'ng1A'}) | 
					
						
							|  |  |  |            class Ng1ComponentAFacade extends UpgradeComponent { | 
					
						
							|  |  |  |              @Input() inputA: any; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                super('ng1A', elementRef, injector); | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            @Directive({selector: 'ng1B'}) | 
					
						
							|  |  |  |            class Ng1ComponentBFacade extends UpgradeComponent { | 
					
						
							|  |  |  |              @Input() inputB: any; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                super('ng1B', elementRef, injector); | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Component`
 | 
					
						
							|  |  |  |            @Component({ | 
					
						
							|  |  |  |              selector: 'ng2', | 
					
						
							|  |  |  |              template: '<ng1A [inputA]="data"></ng1A> | <ng1B [inputB]="data"></ng1B>' | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Component { | 
					
						
							|  |  |  |              data = {foo: 'bar'}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              constructor() { ng2ComponentInstance = this; } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Module`
 | 
					
						
							|  |  |  |            const ng1Module = angular.module('ng1Module', []) | 
					
						
							|  |  |  |                                  .directive('ng1A', () => ng1DirectiveA) | 
					
						
							|  |  |  |                                  .directive('ng1B', () => ng1DirectiveB) | 
					
						
							|  |  |  |                                  .directive('ng2', downgradeComponent({component: Ng2Component})); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Module`
 | 
					
						
							|  |  |  |            @NgModule({ | 
					
						
							|  |  |  |              declarations: [Ng1ComponentAFacade, Ng1ComponentBFacade, Ng2Component], | 
					
						
							|  |  |  |              entryComponents: [Ng2Component], | 
					
						
							|  |  |  |              imports: [BrowserModule, UpgradeModule] | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Module { | 
					
						
							|  |  |  |              ngDoBootstrap() {} | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Bootstrap
 | 
					
						
							|  |  |  |            const element = html(`<ng2></ng2>`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(adapter => { | 
					
						
							|  |  |  |              // Initial change
 | 
					
						
							|  |  |  |              expect(scopeOnChangesA.calls.count()).toBe(1); | 
					
						
							|  |  |  |              expect(scopeOnChangesB).not.toHaveBeenCalled(); | 
					
						
							|  |  |  |              expect(controllerOnChangesA).not.toHaveBeenCalled(); | 
					
						
							|  |  |  |              expect(controllerOnChangesB.calls.count()).toBe(1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(scopeOnChangesA.calls.argsFor(0)[0].inputA.currentValue).toEqual({foo: 'bar'}); | 
					
						
							|  |  |  |              expect(scopeOnChangesA.calls.argsFor(0)[0].inputA.isFirstChange()).toBe(true); | 
					
						
							|  |  |  |              expect(controllerOnChangesB.calls.argsFor(0)[0].inputB.currentValue).toEqual({ | 
					
						
							|  |  |  |                foo: 'bar' | 
					
						
							|  |  |  |              }); | 
					
						
							|  |  |  |              expect(controllerOnChangesB.calls.argsFor(0)[0].inputB.isFirstChange()).toBe(true); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              // Change: Re-assign `data`
 | 
					
						
							|  |  |  |              ng2ComponentInstance.data = {foo: 'baz'}; | 
					
						
							| 
									
										
										
										
											2017-02-04 17:19:09 +02:00
										 |  |  |              $digest(adapter); | 
					
						
							| 
									
										
										
										
											2016-10-20 13:42:57 +03:00
										 |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(scopeOnChangesA.calls.count()).toBe(2); | 
					
						
							|  |  |  |              expect(scopeOnChangesB).not.toHaveBeenCalled(); | 
					
						
							|  |  |  |              expect(controllerOnChangesA).not.toHaveBeenCalled(); | 
					
						
							|  |  |  |              expect(controllerOnChangesB.calls.count()).toBe(2); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(scopeOnChangesA.calls.argsFor(1)[0].inputA.previousValue).toEqual({foo: 'bar'}); | 
					
						
							|  |  |  |              expect(scopeOnChangesA.calls.argsFor(1)[0].inputA.currentValue).toEqual({foo: 'baz'}); | 
					
						
							|  |  |  |              expect(scopeOnChangesA.calls.argsFor(1)[0].inputA.isFirstChange()).toBe(false); | 
					
						
							|  |  |  |              expect(controllerOnChangesB.calls.argsFor(1)[0].inputB.previousValue).toEqual({ | 
					
						
							|  |  |  |                foo: 'bar' | 
					
						
							|  |  |  |              }); | 
					
						
							|  |  |  |              expect(controllerOnChangesB.calls.argsFor(1)[0].inputB.currentValue).toEqual({ | 
					
						
							|  |  |  |                foo: 'baz' | 
					
						
							|  |  |  |              }); | 
					
						
							|  |  |  |              expect(controllerOnChangesB.calls.argsFor(1)[0].inputB.isFirstChange()).toBe(false); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              // No change: Update internal property
 | 
					
						
							|  |  |  |              ng2ComponentInstance.data.foo = 'qux'; | 
					
						
							| 
									
										
										
										
											2017-02-04 17:19:09 +02:00
										 |  |  |              $digest(adapter); | 
					
						
							| 
									
										
										
										
											2016-10-20 13:42:57 +03:00
										 |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(scopeOnChangesA.calls.count()).toBe(2); | 
					
						
							|  |  |  |              expect(scopeOnChangesB).not.toHaveBeenCalled(); | 
					
						
							|  |  |  |              expect(controllerOnChangesA).not.toHaveBeenCalled(); | 
					
						
							|  |  |  |              expect(controllerOnChangesB.calls.count()).toBe(2); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              // Change: Re-assign `data` (even if it looks the same)
 | 
					
						
							|  |  |  |              ng2ComponentInstance.data = {foo: 'qux'}; | 
					
						
							| 
									
										
										
										
											2017-02-04 17:19:09 +02:00
										 |  |  |              $digest(adapter); | 
					
						
							| 
									
										
										
										
											2016-10-20 13:42:57 +03:00
										 |  |  |              tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(scopeOnChangesA.calls.count()).toBe(3); | 
					
						
							|  |  |  |              expect(scopeOnChangesB).not.toHaveBeenCalled(); | 
					
						
							|  |  |  |              expect(controllerOnChangesA).not.toHaveBeenCalled(); | 
					
						
							|  |  |  |              expect(controllerOnChangesB.calls.count()).toBe(3); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(scopeOnChangesA.calls.argsFor(2)[0].inputA.previousValue).toEqual({foo: 'qux'}); | 
					
						
							|  |  |  |              expect(scopeOnChangesA.calls.argsFor(2)[0].inputA.currentValue).toEqual({foo: 'qux'}); | 
					
						
							|  |  |  |              expect(scopeOnChangesA.calls.argsFor(2)[0].inputA.isFirstChange()).toBe(false); | 
					
						
							|  |  |  |              expect(controllerOnChangesB.calls.argsFor(2)[0].inputB.previousValue).toEqual({ | 
					
						
							|  |  |  |                foo: 'qux' | 
					
						
							|  |  |  |              }); | 
					
						
							|  |  |  |              expect(controllerOnChangesB.calls.argsFor(2)[0].inputB.currentValue).toEqual({ | 
					
						
							|  |  |  |                foo: 'qux' | 
					
						
							|  |  |  |              }); | 
					
						
							|  |  |  |              expect(controllerOnChangesB.calls.argsFor(2)[0].inputB.isFirstChange()).toBe(false); | 
					
						
							|  |  |  |            }); | 
					
						
							|  |  |  |          })); | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |       it('should call `$onInit()` on controller', async(() => { | 
					
						
							|  |  |  |            // Define `ng1Directive`
 | 
					
						
							|  |  |  |            const ng1DirectiveA: angular.IDirective = { | 
					
						
							|  |  |  |              template: 'Called: {{ called }}', | 
					
						
							|  |  |  |              bindToController: false, | 
					
						
							|  |  |  |              controller: class { | 
					
						
							|  |  |  |                constructor(private $scope: angular.IScope) { $scope['called'] = 'no'; } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                $onInit() { this.$scope['called'] = 'yes'; } | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            const ng1DirectiveB: angular.IDirective = { | 
					
						
							|  |  |  |              template: 'Called: {{ called }}', | 
					
						
							|  |  |  |              bindToController: true, | 
					
						
							|  |  |  |              controller: class { | 
					
						
							| 
									
										
										
										
											2016-10-20 13:42:57 +03:00
										 |  |  |                constructor($scope: angular.IScope) { | 
					
						
							|  |  |  |                  $scope['called'] = 'no'; | 
					
						
							|  |  |  |                  (this as any)['$onInit'] = () => $scope['called'] = 'yes'; | 
					
						
							|  |  |  |                } | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  |              } | 
					
						
							|  |  |  |            }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng1ComponentFacade`
 | 
					
						
							|  |  |  |            @Directive({selector: 'ng1A'}) | 
					
						
							|  |  |  |            class Ng1ComponentAFacade extends UpgradeComponent { | 
					
						
							|  |  |  |              constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                super('ng1A', elementRef, injector); | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            @Directive({selector: 'ng1B'}) | 
					
						
							|  |  |  |            class Ng1ComponentBFacade extends UpgradeComponent { | 
					
						
							|  |  |  |              constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                super('ng1B', elementRef, injector); | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Component`
 | 
					
						
							|  |  |  |            @Component({selector: 'ng2', template: '<ng1A></ng1A> | <ng1B></ng1B>'}) | 
					
						
							|  |  |  |            class Ng2Component { | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Module`
 | 
					
						
							|  |  |  |            const ng1Module = angular.module('ng1Module', []) | 
					
						
							|  |  |  |                                  .directive('ng1A', () => ng1DirectiveA) | 
					
						
							|  |  |  |                                  .directive('ng1B', () => ng1DirectiveB) | 
					
						
							|  |  |  |                                  .directive('ng2', downgradeComponent({component: Ng2Component})); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Module`
 | 
					
						
							|  |  |  |            @NgModule({ | 
					
						
							|  |  |  |              declarations: [Ng1ComponentAFacade, Ng1ComponentBFacade, Ng2Component], | 
					
						
							|  |  |  |              entryComponents: [Ng2Component], | 
					
						
							|  |  |  |              imports: [BrowserModule, UpgradeModule] | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Module { | 
					
						
							|  |  |  |              ngDoBootstrap() {} | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Bootstrap
 | 
					
						
							|  |  |  |            const element = html(`<ng2></ng2>`); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-20 13:42:57 +03:00
										 |  |  |            bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(() => { | 
					
						
							|  |  |  |              expect(multiTrim(element.textContent)).toBe('Called: yes | Called: yes'); | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  |            }); | 
					
						
							|  |  |  |          })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should not call `$onInit()` on scope', async(() => { | 
					
						
							|  |  |  |            // Define `ng1Directive`
 | 
					
						
							|  |  |  |            const ng1DirectiveA: angular.IDirective = { | 
					
						
							|  |  |  |              template: 'Called: {{ called }}', | 
					
						
							|  |  |  |              bindToController: false, | 
					
						
							|  |  |  |              controller: class { | 
					
						
							|  |  |  |                constructor($scope: angular.IScope) { | 
					
						
							|  |  |  |                  $scope['called'] = 'no'; | 
					
						
							|  |  |  |                  $scope['$onInit'] = () => $scope['called'] = 'yes'; | 
					
						
							| 
									
										
										
										
											2016-10-20 13:42:57 +03:00
										 |  |  |                  Object.getPrototypeOf($scope)['$onInit'] = () => $scope['called'] = 'yes'; | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  |                } | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            const ng1DirectiveB: angular.IDirective = { | 
					
						
							|  |  |  |              template: 'Called: {{ called }}', | 
					
						
							|  |  |  |              bindToController: true, | 
					
						
							|  |  |  |              controller: class { | 
					
						
							|  |  |  |                constructor($scope: angular.IScope) { | 
					
						
							|  |  |  |                  $scope['called'] = 'no'; | 
					
						
							|  |  |  |                  $scope['$onInit'] = () => $scope['called'] = 'yes'; | 
					
						
							| 
									
										
										
										
											2016-10-20 13:42:57 +03:00
										 |  |  |                  Object.getPrototypeOf($scope)['$onInit'] = () => $scope['called'] = 'yes'; | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  |                } | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng1ComponentFacade`
 | 
					
						
							|  |  |  |            @Directive({selector: 'ng1A'}) | 
					
						
							|  |  |  |            class Ng1ComponentAFacade extends UpgradeComponent { | 
					
						
							|  |  |  |              constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                super('ng1A', elementRef, injector); | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            @Directive({selector: 'ng1B'}) | 
					
						
							|  |  |  |            class Ng1ComponentBFacade extends UpgradeComponent { | 
					
						
							|  |  |  |              constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                super('ng1B', elementRef, injector); | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Component`
 | 
					
						
							|  |  |  |            @Component({selector: 'ng2', template: '<ng1A></ng1A> | <ng1B></ng1B>'}) | 
					
						
							|  |  |  |            class Ng2Component { | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Module`
 | 
					
						
							|  |  |  |            const ng1Module = angular.module('ng1Module', []) | 
					
						
							|  |  |  |                                  .directive('ng1A', () => ng1DirectiveA) | 
					
						
							|  |  |  |                                  .directive('ng1B', () => ng1DirectiveB) | 
					
						
							|  |  |  |                                  .directive('ng2', downgradeComponent({component: Ng2Component})); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Module`
 | 
					
						
							|  |  |  |            @NgModule({ | 
					
						
							|  |  |  |              declarations: [Ng1ComponentAFacade, Ng1ComponentBFacade, Ng2Component], | 
					
						
							|  |  |  |              entryComponents: [Ng2Component], | 
					
						
							|  |  |  |              imports: [BrowserModule, UpgradeModule] | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Module { | 
					
						
							|  |  |  |              ngDoBootstrap() {} | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Bootstrap
 | 
					
						
							|  |  |  |            const element = html(`<ng2></ng2>`); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-20 13:42:57 +03:00
										 |  |  |            bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(() => { | 
					
						
							|  |  |  |              expect(multiTrim(element.textContent)).toBe('Called: no | Called: no'); | 
					
						
							|  |  |  |            }); | 
					
						
							|  |  |  |          })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should call `$postLink()` on controller', async(() => { | 
					
						
							|  |  |  |            // Define `ng1Directive`
 | 
					
						
							|  |  |  |            const ng1DirectiveA: angular.IDirective = { | 
					
						
							|  |  |  |              template: 'Called: {{ called }}', | 
					
						
							|  |  |  |              bindToController: false, | 
					
						
							|  |  |  |              controller: class { | 
					
						
							|  |  |  |                constructor(private $scope: angular.IScope) { $scope['called'] = 'no'; } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                $postLink() { this.$scope['called'] = 'yes'; } | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            const ng1DirectiveB: angular.IDirective = { | 
					
						
							|  |  |  |              template: 'Called: {{ called }}', | 
					
						
							|  |  |  |              bindToController: true, | 
					
						
							|  |  |  |              controller: class { | 
					
						
							|  |  |  |                constructor($scope: angular.IScope) { | 
					
						
							|  |  |  |                  $scope['called'] = 'no'; | 
					
						
							|  |  |  |                  (this as any)['$postLink'] = () => $scope['called'] = 'yes'; | 
					
						
							|  |  |  |                } | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng1ComponentFacade`
 | 
					
						
							|  |  |  |            @Directive({selector: 'ng1A'}) | 
					
						
							|  |  |  |            class Ng1ComponentAFacade extends UpgradeComponent { | 
					
						
							|  |  |  |              constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                super('ng1A', elementRef, injector); | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            @Directive({selector: 'ng1B'}) | 
					
						
							|  |  |  |            class Ng1ComponentBFacade extends UpgradeComponent { | 
					
						
							|  |  |  |              constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                super('ng1B', elementRef, injector); | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Component`
 | 
					
						
							|  |  |  |            @Component({selector: 'ng2', template: '<ng1A></ng1A> | <ng1B></ng1B>'}) | 
					
						
							|  |  |  |            class Ng2Component { | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Module`
 | 
					
						
							|  |  |  |            const ng1Module = angular.module('ng1Module', []) | 
					
						
							|  |  |  |                                  .directive('ng1A', () => ng1DirectiveA) | 
					
						
							|  |  |  |                                  .directive('ng1B', () => ng1DirectiveB) | 
					
						
							|  |  |  |                                  .directive('ng2', downgradeComponent({component: Ng2Component})); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Module`
 | 
					
						
							|  |  |  |            @NgModule({ | 
					
						
							|  |  |  |              declarations: [Ng1ComponentAFacade, Ng1ComponentBFacade, Ng2Component], | 
					
						
							|  |  |  |              entryComponents: [Ng2Component], | 
					
						
							|  |  |  |              imports: [BrowserModule, UpgradeModule] | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Module { | 
					
						
							|  |  |  |              ngDoBootstrap() {} | 
					
						
							|  |  |  |            } | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-20 13:42:57 +03:00
										 |  |  |            // Bootstrap
 | 
					
						
							|  |  |  |            const element = html(`<ng2></ng2>`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(() => { | 
					
						
							|  |  |  |              expect(multiTrim(element.textContent)).toBe('Called: yes | Called: yes'); | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  |            }); | 
					
						
							|  |  |  |          })); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-20 13:42:57 +03:00
										 |  |  |       it('should not call `$postLink()` on scope', async(() => { | 
					
						
							|  |  |  |            // Define `ng1Directive`
 | 
					
						
							|  |  |  |            const ng1DirectiveA: angular.IDirective = { | 
					
						
							|  |  |  |              template: 'Called: {{ called }}', | 
					
						
							|  |  |  |              bindToController: false, | 
					
						
							|  |  |  |              controller: class { | 
					
						
							|  |  |  |                constructor($scope: angular.IScope) { | 
					
						
							|  |  |  |                  $scope['called'] = 'no'; | 
					
						
							|  |  |  |                  $scope['$postLink'] = () => $scope['called'] = 'yes'; | 
					
						
							|  |  |  |                  Object.getPrototypeOf($scope)['$postLink'] = () => $scope['called'] = 'yes'; | 
					
						
							|  |  |  |                } | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            }; | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-20 13:42:57 +03:00
										 |  |  |            const ng1DirectiveB: angular.IDirective = { | 
					
						
							|  |  |  |              template: 'Called: {{ called }}', | 
					
						
							|  |  |  |              bindToController: true, | 
					
						
							|  |  |  |              controller: class { | 
					
						
							|  |  |  |                constructor($scope: angular.IScope) { | 
					
						
							|  |  |  |                  $scope['called'] = 'no'; | 
					
						
							|  |  |  |                  $scope['$postLink'] = () => $scope['called'] = 'yes'; | 
					
						
							|  |  |  |                  Object.getPrototypeOf($scope)['$postLink'] = () => $scope['called'] = 'yes'; | 
					
						
							|  |  |  |                } | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng1ComponentFacade`
 | 
					
						
							|  |  |  |            @Directive({selector: 'ng1A'}) | 
					
						
							|  |  |  |            class Ng1ComponentAFacade extends UpgradeComponent { | 
					
						
							|  |  |  |              constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                super('ng1A', elementRef, injector); | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            @Directive({selector: 'ng1B'}) | 
					
						
							|  |  |  |            class Ng1ComponentBFacade extends UpgradeComponent { | 
					
						
							|  |  |  |              constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                super('ng1B', elementRef, injector); | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Component`
 | 
					
						
							|  |  |  |            @Component({selector: 'ng2', template: '<ng1A></ng1A> | <ng1B></ng1B>'}) | 
					
						
							|  |  |  |            class Ng2Component { | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Module`
 | 
					
						
							|  |  |  |            const ng1Module = angular.module('ng1Module', []) | 
					
						
							|  |  |  |                                  .directive('ng1A', () => ng1DirectiveA) | 
					
						
							|  |  |  |                                  .directive('ng1B', () => ng1DirectiveB) | 
					
						
							|  |  |  |                                  .directive('ng2', downgradeComponent({component: Ng2Component})); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Module`
 | 
					
						
							|  |  |  |            @NgModule({ | 
					
						
							|  |  |  |              declarations: [Ng1ComponentAFacade, Ng1ComponentBFacade, Ng2Component], | 
					
						
							|  |  |  |              entryComponents: [Ng2Component], | 
					
						
							|  |  |  |              imports: [BrowserModule, UpgradeModule] | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Module { | 
					
						
							|  |  |  |              ngDoBootstrap() {} | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Bootstrap
 | 
					
						
							|  |  |  |            const element = html(`<ng2></ng2>`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(() => { | 
					
						
							|  |  |  |              expect(multiTrim(element.textContent)).toBe('Called: no | Called: no'); | 
					
						
							|  |  |  |            }); | 
					
						
							|  |  |  |          })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-21 02:18:43 +02:00
										 |  |  |       it('should call `$doCheck()` on controller', async(() => { | 
					
						
							|  |  |  |            const controllerDoCheckA = jasmine.createSpy('controllerDoCheckA'); | 
					
						
							|  |  |  |            const controllerDoCheckB = jasmine.createSpy('controllerDoCheckB'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Directive`
 | 
					
						
							|  |  |  |            const ng1DirectiveA: angular.IDirective = { | 
					
						
							|  |  |  |              template: 'ng1A', | 
					
						
							|  |  |  |              bindToController: false, | 
					
						
							|  |  |  |              controller: class {$doCheck() { controllerDoCheckA(); }} | 
					
						
							|  |  |  |            }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            const ng1DirectiveB: angular.IDirective = { | 
					
						
							|  |  |  |              template: 'ng1B', | 
					
						
							|  |  |  |              bindToController: true, | 
					
						
							|  |  |  |              controller: class {constructor() { (this as any)['$doCheck'] = controllerDoCheckB; }} | 
					
						
							|  |  |  |            }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng1ComponentFacade`
 | 
					
						
							|  |  |  |            @Directive({selector: 'ng1A'}) | 
					
						
							|  |  |  |            class Ng1ComponentAFacade extends UpgradeComponent { | 
					
						
							|  |  |  |              constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                super('ng1A', elementRef, injector); | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            @Directive({selector: 'ng1B'}) | 
					
						
							|  |  |  |            class Ng1ComponentBFacade extends UpgradeComponent { | 
					
						
							|  |  |  |              constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                super('ng1B', elementRef, injector); | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Component`
 | 
					
						
							|  |  |  |            @Component({selector: 'ng2', template: '<ng1A></ng1A> | <ng1B></ng1B>'}) | 
					
						
							|  |  |  |            class Ng2Component { | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Module`
 | 
					
						
							|  |  |  |            const ng1Module = angular.module('ng1Module', []) | 
					
						
							|  |  |  |                                  .directive('ng1A', () => ng1DirectiveA) | 
					
						
							|  |  |  |                                  .directive('ng1B', () => ng1DirectiveB) | 
					
						
							|  |  |  |                                  .directive('ng2', downgradeComponent({component: Ng2Component})); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Module`
 | 
					
						
							|  |  |  |            @NgModule({ | 
					
						
							|  |  |  |              declarations: [Ng1ComponentAFacade, Ng1ComponentBFacade, Ng2Component], | 
					
						
							|  |  |  |              entryComponents: [Ng2Component], | 
					
						
							|  |  |  |              imports: [BrowserModule, UpgradeModule] | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Module { | 
					
						
							|  |  |  |              ngDoBootstrap() {} | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Bootstrap
 | 
					
						
							|  |  |  |            const element = html(`<ng2></ng2>`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(adapter => { | 
					
						
							| 
									
										
										
										
											2018-02-15 19:21:18 +02:00
										 |  |  |              // Get to a stable `$digest` state.
 | 
					
						
							|  |  |  |              $digest(adapter); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              // Initial change.
 | 
					
						
							|  |  |  |              // (Do not use a specific number due to differences between AngularJS 1.5/1.6.)
 | 
					
						
							|  |  |  |              expect(controllerDoCheckA.calls.count()).toBeGreaterThan(0); | 
					
						
							|  |  |  |              expect(controllerDoCheckB.calls.count()).toBeGreaterThan(0); | 
					
						
							|  |  |  |              controllerDoCheckA.calls.reset(); | 
					
						
							|  |  |  |              controllerDoCheckB.calls.reset(); | 
					
						
							| 
									
										
										
										
											2016-12-21 02:18:43 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |              // Run a `$digest`
 | 
					
						
							| 
									
										
										
										
											2017-02-04 17:19:09 +02:00
										 |  |  |              $digest(adapter); | 
					
						
							| 
									
										
										
										
											2018-02-15 19:21:18 +02:00
										 |  |  |              expect(controllerDoCheckA.calls.count()).toBe(1); | 
					
						
							|  |  |  |              expect(controllerDoCheckB.calls.count()).toBe(1); | 
					
						
							| 
									
										
										
										
											2016-12-21 02:18:43 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |              // Run another `$digest`
 | 
					
						
							| 
									
										
										
										
											2017-02-04 17:19:09 +02:00
										 |  |  |              $digest(adapter); | 
					
						
							| 
									
										
										
										
											2018-02-15 19:21:18 +02:00
										 |  |  |              expect(controllerDoCheckA.calls.count()).toBe(2); | 
					
						
							|  |  |  |              expect(controllerDoCheckB.calls.count()).toBe(2); | 
					
						
							| 
									
										
										
										
											2016-12-21 02:18:43 +02:00
										 |  |  |            }); | 
					
						
							|  |  |  |          })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should not call `$doCheck()` on scope', async(() => { | 
					
						
							|  |  |  |            const scopeDoCheck = jasmine.createSpy('scopeDoCheck'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Directive`
 | 
					
						
							|  |  |  |            const ng1DirectiveA: angular.IDirective = { | 
					
						
							|  |  |  |              template: 'ng1A', | 
					
						
							|  |  |  |              bindToController: false, | 
					
						
							|  |  |  |              controller: class { | 
					
						
							|  |  |  |                constructor(private $scope: angular.IScope) { $scope['$doCheck'] = scopeDoCheck; } | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            const ng1DirectiveB: angular.IDirective = { | 
					
						
							|  |  |  |              template: 'ng1B', | 
					
						
							|  |  |  |              bindToController: true, | 
					
						
							|  |  |  |              controller: class { | 
					
						
							|  |  |  |                constructor(private $scope: angular.IScope) { $scope['$doCheck'] = scopeDoCheck; } | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng1ComponentFacade`
 | 
					
						
							|  |  |  |            @Directive({selector: 'ng1A'}) | 
					
						
							|  |  |  |            class Ng1ComponentAFacade extends UpgradeComponent { | 
					
						
							|  |  |  |              constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                super('ng1A', elementRef, injector); | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            @Directive({selector: 'ng1B'}) | 
					
						
							|  |  |  |            class Ng1ComponentBFacade extends UpgradeComponent { | 
					
						
							|  |  |  |              constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                super('ng1B', elementRef, injector); | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Component`
 | 
					
						
							|  |  |  |            @Component({selector: 'ng2', template: '<ng1A></ng1A> | <ng1B></ng1B>'}) | 
					
						
							|  |  |  |            class Ng2Component { | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Module`
 | 
					
						
							|  |  |  |            const ng1Module = angular.module('ng1Module', []) | 
					
						
							|  |  |  |                                  .directive('ng1A', () => ng1DirectiveA) | 
					
						
							|  |  |  |                                  .directive('ng1B', () => ng1DirectiveB) | 
					
						
							|  |  |  |                                  .directive('ng2', downgradeComponent({component: Ng2Component})); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Module`
 | 
					
						
							|  |  |  |            @NgModule({ | 
					
						
							|  |  |  |              declarations: [Ng1ComponentAFacade, Ng1ComponentBFacade, Ng2Component], | 
					
						
							|  |  |  |              entryComponents: [Ng2Component], | 
					
						
							|  |  |  |              imports: [BrowserModule, UpgradeModule] | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Module { | 
					
						
							|  |  |  |              ngDoBootstrap() {} | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Bootstrap
 | 
					
						
							|  |  |  |            const element = html(`<ng2></ng2>`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(adapter => { | 
					
						
							|  |  |  |              // Initial change
 | 
					
						
							|  |  |  |              expect(scopeDoCheck).not.toHaveBeenCalled(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              // Run a `$digest`
 | 
					
						
							| 
									
										
										
										
											2017-02-04 17:19:09 +02:00
										 |  |  |              $digest(adapter); | 
					
						
							| 
									
										
										
										
											2016-12-21 02:18:43 +02:00
										 |  |  |              expect(scopeDoCheck).not.toHaveBeenCalled(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              // Run another `$digest`
 | 
					
						
							| 
									
										
										
										
											2017-02-04 17:19:09 +02:00
										 |  |  |              $digest(adapter); | 
					
						
							| 
									
										
										
										
											2016-12-21 02:18:43 +02:00
										 |  |  |              expect(scopeDoCheck).not.toHaveBeenCalled(); | 
					
						
							|  |  |  |            }); | 
					
						
							|  |  |  |          })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-18 11:49:20 -08:00
										 |  |  |       it('should call `$onDestroy()` on controller', async(() => { | 
					
						
							|  |  |  |            const controllerOnDestroyA = jasmine.createSpy('controllerOnDestroyA'); | 
					
						
							|  |  |  |            const controllerOnDestroyB = jasmine.createSpy('controllerOnDestroyB'); | 
					
						
							| 
									
										
										
										
											2018-12-03 17:57:07 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-18 11:49:20 -08:00
										 |  |  |            // Define `ng1Directive`
 | 
					
						
							|  |  |  |            const ng1DirectiveA: angular.IDirective = { | 
					
						
							|  |  |  |              template: 'ng1A', | 
					
						
							|  |  |  |              scope: {}, | 
					
						
							|  |  |  |              bindToController: false, | 
					
						
							|  |  |  |              controllerAs: '$ctrl', | 
					
						
							|  |  |  |              controller: class {$onDestroy() { controllerOnDestroyA(); }} | 
					
						
							|  |  |  |            }; | 
					
						
							| 
									
										
										
										
											2018-12-03 17:57:07 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-18 11:49:20 -08:00
										 |  |  |            const ng1DirectiveB: angular.IDirective = { | 
					
						
							|  |  |  |              template: 'ng1B', | 
					
						
							|  |  |  |              scope: {}, | 
					
						
							|  |  |  |              bindToController: true, | 
					
						
							|  |  |  |              controllerAs: '$ctrl', | 
					
						
							|  |  |  |              controller: | 
					
						
							|  |  |  |                  class {constructor() { (this as any)['$onDestroy'] = controllerOnDestroyB; }} | 
					
						
							|  |  |  |            }; | 
					
						
							| 
									
										
										
										
											2018-12-03 17:57:07 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-18 11:49:20 -08:00
										 |  |  |            // Define `Ng1ComponentFacade`
 | 
					
						
							|  |  |  |            @Directive({selector: 'ng1A'}) | 
					
						
							|  |  |  |            class Ng1ComponentAFacade extends UpgradeComponent { | 
					
						
							|  |  |  |              constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                super('ng1A', elementRef, injector); | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            } | 
					
						
							| 
									
										
										
										
											2018-12-03 17:57:07 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-18 11:49:20 -08:00
										 |  |  |            @Directive({selector: 'ng1B'}) | 
					
						
							|  |  |  |            class Ng1ComponentBFacade extends UpgradeComponent { | 
					
						
							|  |  |  |              constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                super('ng1B', elementRef, injector); | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            } | 
					
						
							| 
									
										
										
										
											2018-12-03 17:57:07 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-18 11:49:20 -08:00
										 |  |  |            // Define `Ng2Component`
 | 
					
						
							|  |  |  |            @Component( | 
					
						
							|  |  |  |                {selector: 'ng2', template: '<div *ngIf="show"><ng1A></ng1A> | <ng1B></ng1B></div>'}) | 
					
						
							|  |  |  |            class Ng2Component { | 
					
						
							|  |  |  |              // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |              @Input() show !: boolean; | 
					
						
							|  |  |  |            } | 
					
						
							| 
									
										
										
										
											2018-12-03 17:57:07 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-18 11:49:20 -08:00
										 |  |  |            // Define `ng1Module`
 | 
					
						
							|  |  |  |            const ng1Module = angular.module('ng1Module', []) | 
					
						
							|  |  |  |                                  .directive('ng1A', () => ng1DirectiveA) | 
					
						
							|  |  |  |                                  .directive('ng1B', () => ng1DirectiveB) | 
					
						
							|  |  |  |                                  .directive('ng2', downgradeComponent({component: Ng2Component})); | 
					
						
							| 
									
										
										
										
											2018-12-03 17:57:07 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-18 11:49:20 -08:00
										 |  |  |            // Define `Ng2Module`
 | 
					
						
							|  |  |  |            @NgModule({ | 
					
						
							|  |  |  |              declarations: [Ng1ComponentAFacade, Ng1ComponentBFacade, Ng2Component], | 
					
						
							|  |  |  |              entryComponents: [Ng2Component], | 
					
						
							|  |  |  |              imports: [BrowserModule, UpgradeModule] | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Module { | 
					
						
							|  |  |  |              ngDoBootstrap() {} | 
					
						
							|  |  |  |            } | 
					
						
							| 
									
										
										
										
											2018-12-03 17:57:07 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-18 11:49:20 -08:00
										 |  |  |            // Bootstrap
 | 
					
						
							|  |  |  |            const element = html('<ng2 [show]="!destroyFromNg2" ng-if="!destroyFromNg1"></ng2>'); | 
					
						
							| 
									
										
										
										
											2018-12-03 17:57:07 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-18 11:49:20 -08:00
										 |  |  |            bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(adapter => { | 
					
						
							|  |  |  |              const $rootScope = adapter.$injector.get('$rootScope') as angular.IRootScopeService; | 
					
						
							| 
									
										
										
										
											2018-12-03 17:57:07 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-18 11:49:20 -08:00
										 |  |  |              expect(multiTrim(document.body.textContent)).toBe('ng1A | ng1B'); | 
					
						
							|  |  |  |              expect(controllerOnDestroyA).not.toHaveBeenCalled(); | 
					
						
							|  |  |  |              expect(controllerOnDestroyB).not.toHaveBeenCalled(); | 
					
						
							| 
									
										
										
										
											2018-12-03 17:57:07 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-18 11:49:20 -08:00
										 |  |  |              $rootScope.$apply('destroyFromNg1 = true'); | 
					
						
							| 
									
										
										
										
											2018-12-03 17:57:07 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-18 11:49:20 -08:00
										 |  |  |              expect(multiTrim(document.body.textContent)).toBe(''); | 
					
						
							|  |  |  |              expect(controllerOnDestroyA).toHaveBeenCalled(); | 
					
						
							|  |  |  |              expect(controllerOnDestroyB).toHaveBeenCalled(); | 
					
						
							| 
									
										
										
										
											2018-12-03 17:57:07 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-18 11:49:20 -08:00
										 |  |  |              controllerOnDestroyA.calls.reset(); | 
					
						
							|  |  |  |              controllerOnDestroyB.calls.reset(); | 
					
						
							|  |  |  |              $rootScope.$apply('destroyFromNg1 = false'); | 
					
						
							| 
									
										
										
										
											2018-12-03 17:57:07 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-18 11:49:20 -08:00
										 |  |  |              expect(multiTrim(document.body.textContent)).toBe('ng1A | ng1B'); | 
					
						
							|  |  |  |              expect(controllerOnDestroyA).not.toHaveBeenCalled(); | 
					
						
							|  |  |  |              expect(controllerOnDestroyB).not.toHaveBeenCalled(); | 
					
						
							| 
									
										
										
										
											2018-12-03 17:57:07 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-18 11:49:20 -08:00
										 |  |  |              $rootScope.$apply('destroyFromNg2 = true'); | 
					
						
							| 
									
										
										
										
											2018-12-03 17:57:07 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-18 11:49:20 -08:00
										 |  |  |              expect(multiTrim(document.body.textContent)).toBe(''); | 
					
						
							|  |  |  |              expect(controllerOnDestroyA).toHaveBeenCalled(); | 
					
						
							|  |  |  |              expect(controllerOnDestroyB).toHaveBeenCalled(); | 
					
						
							|  |  |  |            }); | 
					
						
							|  |  |  |          })); | 
					
						
							| 
									
										
										
										
											2016-10-20 13:42:57 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |       it('should not call `$onDestroy()` on scope', async(() => { | 
					
						
							|  |  |  |            const scopeOnDestroy = jasmine.createSpy('scopeOnDestroy'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Directive`
 | 
					
						
							|  |  |  |            const ng1DirectiveA: angular.IDirective = { | 
					
						
							|  |  |  |              template: 'ng1A', | 
					
						
							|  |  |  |              scope: {}, | 
					
						
							|  |  |  |              bindToController: false, | 
					
						
							|  |  |  |              controllerAs: '$ctrl', | 
					
						
							|  |  |  |              controller: class { | 
					
						
							|  |  |  |                constructor($scope: angular.IScope) { | 
					
						
							|  |  |  |                  $scope['$onDestroy'] = scopeOnDestroy; | 
					
						
							|  |  |  |                  Object.getPrototypeOf($scope)['$onDestroy'] = scopeOnDestroy; | 
					
						
							|  |  |  |                } | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            const ng1DirectiveB: angular.IDirective = { | 
					
						
							|  |  |  |              template: 'ng1B', | 
					
						
							|  |  |  |              scope: {}, | 
					
						
							|  |  |  |              bindToController: true, | 
					
						
							|  |  |  |              controllerAs: '$ctrl', | 
					
						
							|  |  |  |              controller: class { | 
					
						
							|  |  |  |                constructor($scope: angular.IScope) { | 
					
						
							|  |  |  |                  $scope['$onDestroy'] = scopeOnDestroy; | 
					
						
							|  |  |  |                  Object.getPrototypeOf($scope)['$onDestroy'] = scopeOnDestroy; | 
					
						
							|  |  |  |                } | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng1ComponentFacade`
 | 
					
						
							|  |  |  |            @Directive({selector: 'ng1A'}) | 
					
						
							|  |  |  |            class Ng1ComponentAFacade extends UpgradeComponent { | 
					
						
							|  |  |  |              constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                super('ng1A', elementRef, injector); | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            @Directive({selector: 'ng1B'}) | 
					
						
							|  |  |  |            class Ng1ComponentBFacade extends UpgradeComponent { | 
					
						
							|  |  |  |              constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                super('ng1B', elementRef, injector); | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Component`
 | 
					
						
							|  |  |  |            @Component( | 
					
						
							|  |  |  |                {selector: 'ng2', template: '<div *ngIf="show"><ng1A></ng1A> | <ng1B></ng1B></div>'}) | 
					
						
							|  |  |  |            class Ng2Component { | 
					
						
							| 
									
										
										
										
											2018-06-18 16:38:33 -07:00
										 |  |  |              // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |              @Input() show !: boolean; | 
					
						
							| 
									
										
										
										
											2016-10-20 13:42:57 +03:00
										 |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Module`
 | 
					
						
							| 
									
										
										
										
											2017-03-14 14:55:37 -07:00
										 |  |  |            const ng1Module = angular.module('ng1Module', []) | 
					
						
							|  |  |  |                                  .directive('ng1A', () => ng1DirectiveA) | 
					
						
							|  |  |  |                                  .directive('ng1B', () => ng1DirectiveB) | 
					
						
							|  |  |  |                                  .directive('ng2', downgradeComponent({component: Ng2Component})); | 
					
						
							| 
									
										
										
										
											2016-10-20 13:42:57 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Module`
 | 
					
						
							|  |  |  |            @NgModule({ | 
					
						
							|  |  |  |              declarations: [Ng1ComponentAFacade, Ng1ComponentBFacade, Ng2Component], | 
					
						
							|  |  |  |              entryComponents: [Ng2Component], | 
					
						
							|  |  |  |              imports: [BrowserModule, UpgradeModule] | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Module { | 
					
						
							|  |  |  |              ngDoBootstrap() {} | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Bootstrap
 | 
					
						
							|  |  |  |            const element = html('<ng2 [show]="!destroyFromNg2" ng-if="!destroyFromNg1"></ng2>'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(adapter => { | 
					
						
							|  |  |  |              const $rootScope = adapter.$injector.get('$rootScope') as angular.IRootScopeService; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(multiTrim(document.body.textContent)).toBe('ng1A | ng1B'); | 
					
						
							|  |  |  |              expect(scopeOnDestroy).not.toHaveBeenCalled(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              $rootScope.$apply('destroyFromNg1 = true'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(multiTrim(document.body.textContent)).toBe(''); | 
					
						
							|  |  |  |              expect(scopeOnDestroy).not.toHaveBeenCalled(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              $rootScope.$apply('destroyFromNg1 = false'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(multiTrim(document.body.textContent)).toBe('ng1A | ng1B'); | 
					
						
							|  |  |  |              expect(scopeOnDestroy).not.toHaveBeenCalled(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              $rootScope.$apply('destroyFromNg2 = true'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(multiTrim(document.body.textContent)).toBe(''); | 
					
						
							|  |  |  |              expect(scopeOnDestroy).not.toHaveBeenCalled(); | 
					
						
							|  |  |  |            }); | 
					
						
							|  |  |  |          })); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-21 02:18:43 +02:00
										 |  |  |       it('should be called in order `$onChanges()` > `$onInit()` > `$doCheck()` > `$postLink()`', | 
					
						
							|  |  |  |          async(() => { | 
					
						
							| 
									
										
										
										
											2016-10-20 13:42:57 +03:00
										 |  |  |            // Define `ng1Component`
 | 
					
						
							|  |  |  |            const ng1Component: angular.IComponent = { | 
					
						
							| 
									
										
										
										
											2016-12-21 02:18:43 +02:00
										 |  |  |              // `$doCheck()` will keep getting called as long as the interpolated value keeps
 | 
					
						
							|  |  |  |              // changing (by appending `> $doCheck`). Only care about the first 4 values.
 | 
					
						
							|  |  |  |              template: '{{ $ctrl.calls.slice(0, 4).join(" > ") }}', | 
					
						
							| 
									
										
										
										
											2016-10-20 13:42:57 +03:00
										 |  |  |              bindings: {value: '<'}, | 
					
						
							|  |  |  |              controller: class { | 
					
						
							|  |  |  |                calls: string[] = []; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-21 02:18:43 +02:00
										 |  |  |                $onChanges() { this.calls.push('$onChanges'); } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                $onInit() { this.calls.push('$onInit'); } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                $doCheck() { this.calls.push('$doCheck'); } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                $postLink() { this.calls.push('$postLink'); } | 
					
						
							| 
									
										
										
										
											2016-10-20 13:42:57 +03:00
										 |  |  |              } | 
					
						
							|  |  |  |            }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng1ComponentFacade`
 | 
					
						
							|  |  |  |            @Directive({selector: 'ng1'}) | 
					
						
							|  |  |  |            class Ng1ComponentFacade extends UpgradeComponent { | 
					
						
							|  |  |  |              @Input() value: any; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                super('ng1', elementRef, injector); | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Component`
 | 
					
						
							|  |  |  |            @Component({selector: 'ng2', template: '<ng1 value="foo"></ng1>'}) | 
					
						
							|  |  |  |            class Ng2Component { | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Module`
 | 
					
						
							|  |  |  |            const ng1Module = angular.module('ng1Module', []) | 
					
						
							|  |  |  |                                  .component('ng1', ng1Component) | 
					
						
							|  |  |  |                                  .directive('ng2', downgradeComponent({component: Ng2Component})); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Module`
 | 
					
						
							|  |  |  |            @NgModule({ | 
					
						
							|  |  |  |              declarations: [Ng1ComponentFacade, Ng2Component], | 
					
						
							|  |  |  |              entryComponents: [Ng2Component], | 
					
						
							|  |  |  |              imports: [BrowserModule, UpgradeModule] | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Module { | 
					
						
							|  |  |  |              ngDoBootstrap() {} | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Bootstrap
 | 
					
						
							|  |  |  |            const element = html(`<ng2></ng2>`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(() => { | 
					
						
							| 
									
										
										
										
											2016-12-21 02:18:43 +02:00
										 |  |  |              expect(multiTrim(element.textContent)) | 
					
						
							|  |  |  |                  .toBe('$onChanges > $onInit > $doCheck > $postLink'); | 
					
						
							| 
									
										
										
										
											2016-10-20 13:42:57 +03:00
										 |  |  |            }); | 
					
						
							|  |  |  |          })); | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-04 19:03:43 +02:00
										 |  |  |     describe('destroying the upgraded component', () => { | 
					
						
							|  |  |  |       it('should destroy `$componentScope`', async(() => { | 
					
						
							|  |  |  |            const scopeDestroyListener = jasmine.createSpy('scopeDestroyListener'); | 
					
						
							|  |  |  |            let ng2ComponentAInstance: Ng2ComponentA; | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-04 19:03:43 +02:00
										 |  |  |            // Define `ng1Component`
 | 
					
						
							|  |  |  |            const ng1Component: angular.IComponent = { | 
					
						
							|  |  |  |              controller: class { | 
					
						
							|  |  |  |                constructor($scope: angular.IScope) { $scope.$on('$destroy', scopeDestroyListener); } | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng1ComponentFacade`
 | 
					
						
							|  |  |  |            @Directive({selector: 'ng1'}) | 
					
						
							|  |  |  |            class Ng1ComponentFacade extends UpgradeComponent { | 
					
						
							|  |  |  |              constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                super('ng1', elementRef, injector); | 
					
						
							|  |  |  |              } | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-04 19:03:43 +02:00
										 |  |  |            // Define `Ng2Component`
 | 
					
						
							|  |  |  |            @Component({selector: 'ng2A', template: '<ng2B *ngIf="!destroyIt"></ng2B>'}) | 
					
						
							|  |  |  |            class Ng2ComponentA { | 
					
						
							|  |  |  |              destroyIt = false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              constructor() { ng2ComponentAInstance = this; } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            @Component({selector: 'ng2B', template: '<ng1></ng1>'}) | 
					
						
							|  |  |  |            class Ng2ComponentB { | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Module`
 | 
					
						
							|  |  |  |            const ng1Module = angular.module('ng1Module', []) | 
					
						
							|  |  |  |                                  .component('ng1', ng1Component) | 
					
						
							|  |  |  |                                  .directive('ng2A', downgradeComponent({component: Ng2ComponentA})); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Module`
 | 
					
						
							|  |  |  |            @NgModule({ | 
					
						
							|  |  |  |              declarations: [Ng1ComponentFacade, Ng2ComponentA, Ng2ComponentB], | 
					
						
							|  |  |  |              entryComponents: [Ng2ComponentA], | 
					
						
							|  |  |  |              imports: [BrowserModule, UpgradeModule] | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Module { | 
					
						
							|  |  |  |              ngDoBootstrap() {} | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Bootstrap
 | 
					
						
							|  |  |  |            const element = html(`<ng2-a></ng2-a>`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(adapter => { | 
					
						
							|  |  |  |              expect(scopeDestroyListener).not.toHaveBeenCalled(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              ng2ComponentAInstance.destroyIt = true; | 
					
						
							|  |  |  |              $digest(adapter); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-07 17:38:35 +03:00
										 |  |  |              expect(scopeDestroyListener).toHaveBeenCalledTimes(1); | 
					
						
							|  |  |  |            }); | 
					
						
							|  |  |  |          })); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-01 21:29:38 -07:00
										 |  |  |       it('should emit `$destroy` on `$element` and descendants', async(() => { | 
					
						
							| 
									
										
										
										
											2018-08-07 17:38:35 +03:00
										 |  |  |            const elementDestroyListener = jasmine.createSpy('elementDestroyListener'); | 
					
						
							| 
									
										
										
										
											2018-10-01 21:29:38 -07:00
										 |  |  |            const descendantDestroyListener = jasmine.createSpy('descendantDestroyListener'); | 
					
						
							| 
									
										
										
										
											2018-08-07 17:38:35 +03:00
										 |  |  |            let ng2ComponentAInstance: Ng2ComponentA; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Component`
 | 
					
						
							|  |  |  |            const ng1Component: angular.IComponent = { | 
					
						
							|  |  |  |              controller: class { | 
					
						
							|  |  |  |                constructor($element: angular.IAugmentedJQuery) { | 
					
						
							|  |  |  |                  $element.on !('$destroy', elementDestroyListener); | 
					
						
							| 
									
										
										
										
											2018-10-01 21:29:38 -07:00
										 |  |  |                  $element.contents !().on !('$destroy', descendantDestroyListener); | 
					
						
							| 
									
										
										
										
											2018-08-07 17:38:35 +03:00
										 |  |  |                } | 
					
						
							| 
									
										
										
										
											2018-10-01 21:29:38 -07:00
										 |  |  |              }, | 
					
						
							|  |  |  |              template: '<div></div>' | 
					
						
							| 
									
										
										
										
											2018-08-07 17:38:35 +03:00
										 |  |  |            }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng1ComponentFacade`
 | 
					
						
							|  |  |  |            @Directive({selector: 'ng1'}) | 
					
						
							|  |  |  |            class Ng1ComponentFacade extends UpgradeComponent { | 
					
						
							|  |  |  |              constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                super('ng1', elementRef, injector); | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Component`
 | 
					
						
							|  |  |  |            @Component({selector: 'ng2A', template: '<ng2B *ngIf="!destroyIt"></ng2B>'}) | 
					
						
							|  |  |  |            class Ng2ComponentA { | 
					
						
							|  |  |  |              destroyIt = false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              constructor() { ng2ComponentAInstance = this; } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            @Component({selector: 'ng2B', template: '<ng1></ng1>'}) | 
					
						
							|  |  |  |            class Ng2ComponentB { | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Module`
 | 
					
						
							|  |  |  |            const ng1Module = angular.module('ng1Module', []) | 
					
						
							|  |  |  |                                  .component('ng1', ng1Component) | 
					
						
							|  |  |  |                                  .directive('ng2A', downgradeComponent({component: Ng2ComponentA})); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Module`
 | 
					
						
							|  |  |  |            @NgModule({ | 
					
						
							|  |  |  |              declarations: [Ng1ComponentFacade, Ng2ComponentA, Ng2ComponentB], | 
					
						
							|  |  |  |              entryComponents: [Ng2ComponentA], | 
					
						
							|  |  |  |              imports: [BrowserModule, UpgradeModule] | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Module { | 
					
						
							|  |  |  |              ngDoBootstrap() {} | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Bootstrap
 | 
					
						
							|  |  |  |            const element = html(`<ng2-a></ng2-a>`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(adapter => { | 
					
						
							|  |  |  |              expect(elementDestroyListener).not.toHaveBeenCalled(); | 
					
						
							| 
									
										
										
										
											2018-10-01 21:29:38 -07:00
										 |  |  |              expect(descendantDestroyListener).not.toHaveBeenCalled(); | 
					
						
							| 
									
										
										
										
											2018-08-07 17:38:35 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |              ng2ComponentAInstance.destroyIt = true; | 
					
						
							|  |  |  |              $digest(adapter); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(elementDestroyListener).toHaveBeenCalledTimes(1); | 
					
						
							| 
									
										
										
										
											2018-10-01 21:29:38 -07:00
										 |  |  |              expect(descendantDestroyListener).toHaveBeenCalledTimes(1); | 
					
						
							|  |  |  |            }); | 
					
						
							|  |  |  |          })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should clear data on `$element` and descendants`', async(() => { | 
					
						
							|  |  |  |            let ng1ComponentElement: angular.IAugmentedJQuery; | 
					
						
							|  |  |  |            let ng2ComponentAInstance: Ng2ComponentA; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Component`
 | 
					
						
							|  |  |  |            const ng1Component: angular.IComponent = { | 
					
						
							|  |  |  |              controller: class { | 
					
						
							|  |  |  |                constructor($element: angular.IAugmentedJQuery) { | 
					
						
							|  |  |  |                  $element.data !('test', 1); | 
					
						
							|  |  |  |                  $element.contents !().data !('test', 2); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                  ng1ComponentElement = $element; | 
					
						
							|  |  |  |                } | 
					
						
							|  |  |  |              }, | 
					
						
							|  |  |  |              template: '<div></div>' | 
					
						
							|  |  |  |            }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng1ComponentFacade`
 | 
					
						
							|  |  |  |            @Directive({selector: 'ng1'}) | 
					
						
							|  |  |  |            class Ng1ComponentFacade extends UpgradeComponent { | 
					
						
							|  |  |  |              constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                super('ng1', elementRef, injector); | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Component`
 | 
					
						
							|  |  |  |            @Component({selector: 'ng2A', template: '<ng2B *ngIf="!destroyIt"></ng2B>'}) | 
					
						
							|  |  |  |            class Ng2ComponentA { | 
					
						
							|  |  |  |              destroyIt = false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              constructor() { ng2ComponentAInstance = this; } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            @Component({selector: 'ng2B', template: '<ng1></ng1>'}) | 
					
						
							|  |  |  |            class Ng2ComponentB { | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Module`
 | 
					
						
							|  |  |  |            const ng1Module = angular.module('ng1Module', []) | 
					
						
							|  |  |  |                                  .component('ng1', ng1Component) | 
					
						
							|  |  |  |                                  .directive('ng2A', downgradeComponent({component: Ng2ComponentA})); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Module`
 | 
					
						
							|  |  |  |            @NgModule({ | 
					
						
							|  |  |  |              declarations: [Ng1ComponentFacade, Ng2ComponentA, Ng2ComponentB], | 
					
						
							|  |  |  |              entryComponents: [Ng2ComponentA], | 
					
						
							|  |  |  |              imports: [BrowserModule, UpgradeModule] | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Module { | 
					
						
							|  |  |  |              ngDoBootstrap() {} | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Bootstrap
 | 
					
						
							|  |  |  |            const element = html(`<ng2-a></ng2-a>`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(adapter => { | 
					
						
							|  |  |  |              expect(ng1ComponentElement.data !('test')).toBe(1); | 
					
						
							|  |  |  |              expect(ng1ComponentElement.contents !().data !('test')).toBe(2); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              ng2ComponentAInstance.destroyIt = true; | 
					
						
							|  |  |  |              $digest(adapter); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(ng1ComponentElement.data !('test')).toBeUndefined(); | 
					
						
							|  |  |  |              expect(ng1ComponentElement.contents !().data !('test')).toBeUndefined(); | 
					
						
							|  |  |  |            }); | 
					
						
							|  |  |  |          })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should clear dom listeners on `$element` and descendants`', async(() => { | 
					
						
							|  |  |  |            const elementClickListener = jasmine.createSpy('elementClickListener'); | 
					
						
							|  |  |  |            const descendantClickListener = jasmine.createSpy('descendantClickListener'); | 
					
						
							|  |  |  |            let ng1DescendantElement: angular.IAugmentedJQuery; | 
					
						
							|  |  |  |            let ng2ComponentAInstance: Ng2ComponentA; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Component`
 | 
					
						
							|  |  |  |            const ng1Component: angular.IComponent = { | 
					
						
							|  |  |  |              controller: class { | 
					
						
							|  |  |  |                constructor($element: angular.IAugmentedJQuery) { | 
					
						
							|  |  |  |                  ng1DescendantElement = $element.contents !(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                  $element.on !('click', elementClickListener); | 
					
						
							|  |  |  |                  ng1DescendantElement.on !('click', descendantClickListener); | 
					
						
							|  |  |  |                } | 
					
						
							|  |  |  |              }, | 
					
						
							|  |  |  |              template: '<div></div>' | 
					
						
							|  |  |  |            }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng1ComponentFacade`
 | 
					
						
							|  |  |  |            @Directive({selector: 'ng1'}) | 
					
						
							|  |  |  |            class Ng1ComponentFacade extends UpgradeComponent { | 
					
						
							|  |  |  |              constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                super('ng1', elementRef, injector); | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Component`
 | 
					
						
							|  |  |  |            @Component({selector: 'ng2A', template: '<ng2B *ngIf="!destroyIt"></ng2B>'}) | 
					
						
							|  |  |  |            class Ng2ComponentA { | 
					
						
							|  |  |  |              destroyIt = false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              constructor() { ng2ComponentAInstance = this; } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            @Component({selector: 'ng2B', template: '<ng1></ng1>'}) | 
					
						
							|  |  |  |            class Ng2ComponentB { | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Module`
 | 
					
						
							|  |  |  |            const ng1Module = angular.module('ng1Module', []) | 
					
						
							|  |  |  |                                  .component('ng1', ng1Component) | 
					
						
							|  |  |  |                                  .directive('ng2A', downgradeComponent({component: Ng2ComponentA})); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng2Module`
 | 
					
						
							|  |  |  |            @NgModule({ | 
					
						
							|  |  |  |              declarations: [Ng1ComponentFacade, Ng2ComponentA, Ng2ComponentB], | 
					
						
							|  |  |  |              entryComponents: [Ng2ComponentA], | 
					
						
							|  |  |  |              imports: [BrowserModule, UpgradeModule] | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Module { | 
					
						
							|  |  |  |              ngDoBootstrap() {} | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Bootstrap
 | 
					
						
							|  |  |  |            const element = html(`<ng2-a></ng2-a>`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(adapter => { | 
					
						
							|  |  |  |              (ng1DescendantElement[0] as HTMLElement).click(); | 
					
						
							|  |  |  |              expect(elementClickListener).toHaveBeenCalledTimes(1); | 
					
						
							|  |  |  |              expect(descendantClickListener).toHaveBeenCalledTimes(1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              ng2ComponentAInstance.destroyIt = true; | 
					
						
							|  |  |  |              $digest(adapter); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              (ng1DescendantElement[0] as HTMLElement).click(); | 
					
						
							|  |  |  |              expect(elementClickListener).toHaveBeenCalledTimes(1); | 
					
						
							|  |  |  |              expect(descendantClickListener).toHaveBeenCalledTimes(1); | 
					
						
							| 
									
										
										
										
											2017-02-04 19:03:43 +02:00
										 |  |  |            }); | 
					
						
							|  |  |  |          })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should clean up `$doCheck()` watchers from the parent scope', async(() => { | 
					
						
							|  |  |  |            let ng2Component: Ng2Component; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `ng1Component`
 | 
					
						
							|  |  |  |            const ng1Component: | 
					
						
							|  |  |  |                angular.IComponent = {template: 'ng1', controller: class {$doCheck() {}}}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Define `Ng1ComponentFacade`
 | 
					
						
							|  |  |  |            @Directive({selector: 'ng1'}) | 
					
						
							|  |  |  |            class Ng1ComponentFacade extends UpgradeComponent { | 
					
						
							|  |  |  |              constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |                super('ng1', elementRef, injector); | 
					
						
							|  |  |  |              } | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  |            } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-04 19:03:43 +02:00
										 |  |  |            // Define `Ng2Component`
 | 
					
						
							|  |  |  |            @Component({selector: 'ng2', template: '<ng1 *ngIf="doShow"></ng1>'}) | 
					
						
							|  |  |  |            class Ng2Component { | 
					
						
							|  |  |  |              doShow: boolean = false; | 
					
						
							|  |  |  |              constructor(@Inject($SCOPE) public $scope: angular.IScope) { ng2Component = this; } | 
					
						
							|  |  |  |            } | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-04 19:03:43 +02:00
										 |  |  |            // Define `ng1Module`
 | 
					
						
							|  |  |  |            const ng1Module = angular.module('ng1Module', []) | 
					
						
							|  |  |  |                                  .component('ng1', ng1Component) | 
					
						
							|  |  |  |                                  .directive('ng2', downgradeComponent({component: Ng2Component})); | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-04 19:03:43 +02:00
										 |  |  |            // Define `Ng2Module`
 | 
					
						
							|  |  |  |            @NgModule({ | 
					
						
							|  |  |  |              imports: [BrowserModule, UpgradeModule], | 
					
						
							|  |  |  |              declarations: [Ng1ComponentFacade, Ng2Component], | 
					
						
							|  |  |  |              entryComponents: [Ng2Component] | 
					
						
							|  |  |  |            }) | 
					
						
							|  |  |  |            class Ng2Module { | 
					
						
							|  |  |  |              ngDoBootstrap() {} | 
					
						
							|  |  |  |            } | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-04 19:03:43 +02:00
										 |  |  |            // Bootstrap
 | 
					
						
							|  |  |  |            const element = html(`<ng2></ng2>`); | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-04 19:03:43 +02:00
										 |  |  |            bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(adapter => { | 
					
						
							|  |  |  |              const getWatcherCount: () => number = () => | 
					
						
							|  |  |  |                  (ng2Component.$scope as any).$$watchers.length; | 
					
						
							|  |  |  |              const baseWatcherCount = getWatcherCount(); | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-04 19:03:43 +02:00
										 |  |  |              expect(multiTrim(document.body.textContent)).toBe(''); | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-04 19:03:43 +02:00
										 |  |  |              ng2Component.doShow = true; | 
					
						
							|  |  |  |              $digest(adapter); | 
					
						
							|  |  |  |              expect(multiTrim(document.body.textContent)).toBe('ng1'); | 
					
						
							|  |  |  |              expect(getWatcherCount()).toBe(baseWatcherCount + 1); | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-04 19:03:43 +02:00
										 |  |  |              ng2Component.doShow = false; | 
					
						
							|  |  |  |              $digest(adapter); | 
					
						
							|  |  |  |              expect(multiTrim(document.body.textContent)).toBe(''); | 
					
						
							|  |  |  |              expect(getWatcherCount()).toBe(baseWatcherCount); | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-04 19:03:43 +02:00
										 |  |  |              ng2Component.doShow = true; | 
					
						
							|  |  |  |              $digest(adapter); | 
					
						
							|  |  |  |              expect(multiTrim(document.body.textContent)).toBe('ng1'); | 
					
						
							|  |  |  |              expect(getWatcherCount()).toBe(baseWatcherCount + 1); | 
					
						
							|  |  |  |            }); | 
					
						
							|  |  |  |          })); | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |     it('should support ng2 > ng1 > ng2 (no inputs/outputs)', async(() => { | 
					
						
							|  |  |  |          // Define `ng1Component`
 | 
					
						
							|  |  |  |          const ng1Component: angular.IComponent = {template: 'ng1X(<ng2-b></ng2-b>)'}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          // Define `Ng1ComponentFacade`
 | 
					
						
							|  |  |  |          @Directive({selector: 'ng1X'}) | 
					
						
							|  |  |  |          class Ng1ComponentFacade extends UpgradeComponent { | 
					
						
							|  |  |  |            constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |              super('ng1X', elementRef, injector); | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  |          } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          // Define `Ng2Component`
 | 
					
						
							|  |  |  |          @Component({selector: 'ng2-a', template: 'ng2A(<ng1X></ng1X>)'}) | 
					
						
							|  |  |  |          class Ng2ComponentA { | 
					
						
							|  |  |  |          } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          @Component({selector: 'ng2-b', template: 'ng2B'}) | 
					
						
							|  |  |  |          class Ng2ComponentB { | 
					
						
							|  |  |  |          } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          // Define `ng1Module`
 | 
					
						
							|  |  |  |          const ng1Module = angular.module('ng1', []) | 
					
						
							|  |  |  |                                .component('ng1X', ng1Component) | 
					
						
							|  |  |  |                                .directive('ng2A', downgradeComponent({component: Ng2ComponentA})) | 
					
						
							|  |  |  |                                .directive('ng2B', downgradeComponent({component: Ng2ComponentB})); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          // Define `Ng2Module`
 | 
					
						
							|  |  |  |          @NgModule({ | 
					
						
							|  |  |  |            declarations: [Ng1ComponentFacade, Ng2ComponentA, Ng2ComponentB], | 
					
						
							|  |  |  |            entryComponents: [Ng2ComponentA, Ng2ComponentB], | 
					
						
							|  |  |  |            imports: [BrowserModule, UpgradeModule], | 
					
						
							|  |  |  |            schemas: [NO_ERRORS_SCHEMA], | 
					
						
							|  |  |  |          }) | 
					
						
							|  |  |  |          class Ng2Module { | 
					
						
							|  |  |  |            ngDoBootstrap() {} | 
					
						
							|  |  |  |          } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          // Bootstrap
 | 
					
						
							|  |  |  |          const element = html(`<ng2-a></ng2-a>`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(() => { | 
					
						
							|  |  |  |            expect(multiTrim(document.body.textContent)).toBe('ng2A(ng1X(ng2B))'); | 
					
						
							|  |  |  |          }); | 
					
						
							|  |  |  |        })); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-04 10:55:03 +00:00
										 |  |  |     it('should support ng2 > ng1 > ng2 (with inputs/outputs)', fakeAsync(() => { | 
					
						
							|  |  |  |          let ng2ComponentAInstance: Ng2ComponentA; | 
					
						
							|  |  |  |          let ng2ComponentBInstance: Ng2ComponentB; | 
					
						
							|  |  |  |          let ng1ControllerXInstance: Ng1ControllerX; | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-04 10:55:03 +00:00
										 |  |  |          // Define `ng1Component`
 | 
					
						
							|  |  |  |          class Ng1ControllerX { | 
					
						
							|  |  |  |            // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |            ng1XInputA !: string; | 
					
						
							|  |  |  |            ng1XInputB: any; | 
					
						
							|  |  |  |            ng1XInputC: any; | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-04 10:55:03 +00:00
										 |  |  |            constructor() { ng1ControllerXInstance = this; } | 
					
						
							|  |  |  |          } | 
					
						
							|  |  |  |          const ng1Component: angular.IComponent = { | 
					
						
							|  |  |  |            template: `
 | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  |               ng1X({{ $ctrl.ng1XInputA }}, {{ $ctrl.ng1XInputB.value }}, {{ $ctrl.ng1XInputC.value }}) | | 
					
						
							|  |  |  |               <ng2-b | 
					
						
							|  |  |  |                 [ng2-b-input1]="$ctrl.ng1XInputA" | 
					
						
							|  |  |  |                 [ng2-b-input-c]="$ctrl.ng1XInputC.value" | 
					
						
							|  |  |  |                 (ng2-b-output-c)="$ctrl.ng1XInputC = {value: $event}"> | 
					
						
							|  |  |  |               </ng2-b> | 
					
						
							|  |  |  |             `,
 | 
					
						
							| 
									
										
										
										
											2018-12-04 10:55:03 +00:00
										 |  |  |            bindings: { | 
					
						
							|  |  |  |              ng1XInputA: '@', | 
					
						
							|  |  |  |              ng1XInputB: '<', | 
					
						
							|  |  |  |              ng1XInputC: '=', | 
					
						
							|  |  |  |              ng1XOutputA: '&', | 
					
						
							|  |  |  |              ng1XOutputB: '&' | 
					
						
							|  |  |  |            }, | 
					
						
							|  |  |  |            controller: Ng1ControllerX | 
					
						
							|  |  |  |          }; | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-04 10:55:03 +00:00
										 |  |  |          // Define `Ng1ComponentFacade`
 | 
					
						
							|  |  |  |          @Directive({selector: 'ng1X'}) | 
					
						
							|  |  |  |          class Ng1ComponentXFacade extends UpgradeComponent { | 
					
						
							|  |  |  |            // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |            @Input() ng1XInputA !: string; | 
					
						
							|  |  |  |            @Input() ng1XInputB: any; | 
					
						
							|  |  |  |            @Input() ng1XInputC: any; | 
					
						
							|  |  |  |            // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |            @Output() ng1XInputCChange !: EventEmitter<any>; | 
					
						
							|  |  |  |            // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |            @Output() ng1XOutputA !: EventEmitter<any>; | 
					
						
							|  |  |  |            // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |            @Output() ng1XOutputB !: EventEmitter<any>; | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-04 10:55:03 +00:00
										 |  |  |            constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |              super('ng1X', elementRef, injector); | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  |          } | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-04 10:55:03 +00:00
										 |  |  |          // Define `Ng2Component`
 | 
					
						
							|  |  |  |          @Component({ | 
					
						
							|  |  |  |            selector: 'ng2-a', | 
					
						
							|  |  |  |            template: `
 | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  |               ng2A({{ ng2ADataA.value }}, {{ ng2ADataB.value }}, {{ ng2ADataC.value }}) | | 
					
						
							|  |  |  |               <ng1X | 
					
						
							|  |  |  |                   ng1XInputA="{{ ng2ADataA.value }}" | 
					
						
							|  |  |  |                   bind-ng1XInputB="ng2ADataB" | 
					
						
							|  |  |  |                   [(ng1XInputC)]="ng2ADataC" | 
					
						
							|  |  |  |                   (ng1XOutputA)="ng2ADataA = $event" | 
					
						
							|  |  |  |                   on-ng1XOutputB="ng2ADataB.value = $event"> | 
					
						
							|  |  |  |               </ng1X> | 
					
						
							|  |  |  |             `
 | 
					
						
							| 
									
										
										
										
											2018-12-04 10:55:03 +00:00
										 |  |  |          }) | 
					
						
							|  |  |  |          class Ng2ComponentA { | 
					
						
							|  |  |  |            ng2ADataA = {value: 'foo'}; | 
					
						
							|  |  |  |            ng2ADataB = {value: 'bar'}; | 
					
						
							|  |  |  |            ng2ADataC = {value: 'baz'}; | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-04 10:55:03 +00:00
										 |  |  |            constructor() { ng2ComponentAInstance = this; } | 
					
						
							|  |  |  |          } | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-04 10:55:03 +00:00
										 |  |  |          @Component({selector: 'ng2-b', template: 'ng2B({{ ng2BInputA }}, {{ ng2BInputC }})'}) | 
					
						
							|  |  |  |          class Ng2ComponentB { | 
					
						
							|  |  |  |            @Input('ng2BInput1') ng2BInputA: any; | 
					
						
							|  |  |  |            @Input() ng2BInputC: any; | 
					
						
							|  |  |  |            @Output() ng2BOutputC = new EventEmitter(); | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-04 10:55:03 +00:00
										 |  |  |            constructor() { ng2ComponentBInstance = this; } | 
					
						
							|  |  |  |          } | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-04 10:55:03 +00:00
										 |  |  |          // Define `ng1Module`
 | 
					
						
							|  |  |  |          const ng1Module = angular.module('ng1', []) | 
					
						
							|  |  |  |                                .component('ng1X', ng1Component) | 
					
						
							|  |  |  |                                .directive('ng2A', downgradeComponent({component: Ng2ComponentA})) | 
					
						
							|  |  |  |                                .directive('ng2B', downgradeComponent({component: Ng2ComponentB})); | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-04 10:55:03 +00:00
										 |  |  |          // Define `Ng2Module`
 | 
					
						
							|  |  |  |          @NgModule({ | 
					
						
							|  |  |  |            declarations: [Ng1ComponentXFacade, Ng2ComponentA, Ng2ComponentB], | 
					
						
							|  |  |  |            entryComponents: [Ng2ComponentA, Ng2ComponentB], | 
					
						
							|  |  |  |            imports: [BrowserModule, UpgradeModule], | 
					
						
							|  |  |  |            schemas: [NO_ERRORS_SCHEMA], | 
					
						
							|  |  |  |          }) | 
					
						
							|  |  |  |          class Ng2Module { | 
					
						
							|  |  |  |            ngDoBootstrap() {} | 
					
						
							|  |  |  |          } | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-04 10:55:03 +00:00
										 |  |  |          // Bootstrap
 | 
					
						
							|  |  |  |          const element = html(`<ng2-a></ng2-a>`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(adapter => { | 
					
						
							|  |  |  |            // Initial value propagation.
 | 
					
						
							|  |  |  |            // (ng2A > ng1X > ng2B)
 | 
					
						
							|  |  |  |            expect(multiTrim(document.body.textContent)) | 
					
						
							|  |  |  |                .toBe('ng2A(foo, bar, baz) | ng1X(foo, bar, baz) | ng2B(foo, baz)'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Update `ng2BInputA`/`ng2BInputC`.
 | 
					
						
							|  |  |  |            // (Should not propagate upwards.)
 | 
					
						
							|  |  |  |            ng2ComponentBInstance.ng2BInputA = 'foo2'; | 
					
						
							|  |  |  |            ng2ComponentBInstance.ng2BInputC = 'baz2'; | 
					
						
							|  |  |  |            $digest(adapter); | 
					
						
							|  |  |  |            tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            expect(multiTrim(document.body.textContent)) | 
					
						
							|  |  |  |                .toBe('ng2A(foo, bar, baz) | ng1X(foo, bar, baz) | ng2B(foo2, baz2)'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Emit from `ng2BOutputC`.
 | 
					
						
							|  |  |  |            // (Should propagate all the way up to `ng1ADataC` and back all the way down to
 | 
					
						
							|  |  |  |            // `ng2BInputC`.)
 | 
					
						
							|  |  |  |            ng2ComponentBInstance.ng2BOutputC.emit('baz3'); | 
					
						
							|  |  |  |            $digest(adapter); | 
					
						
							|  |  |  |            tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            expect(multiTrim(document.body.textContent)) | 
					
						
							|  |  |  |                .toBe('ng2A(foo, bar, baz3) | ng1X(foo, bar, baz3) | ng2B(foo2, baz3)'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Update `ng1XInputA`/`ng1XInputB`.
 | 
					
						
							|  |  |  |            // (Should not propagate upwards, only downwards.)
 | 
					
						
							|  |  |  |            ng1ControllerXInstance.ng1XInputA = 'foo4'; | 
					
						
							|  |  |  |            ng1ControllerXInstance.ng1XInputB = {value: 'bar4'}; | 
					
						
							|  |  |  |            $digest(adapter); | 
					
						
							|  |  |  |            tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            expect(multiTrim(document.body.textContent)) | 
					
						
							|  |  |  |                .toBe('ng2A(foo, bar, baz3) | ng1X(foo4, bar4, baz3) | ng2B(foo4, baz3)'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Update `ng1XInputC`.
 | 
					
						
							|  |  |  |            // (Should propagate upwards and downwards.)
 | 
					
						
							|  |  |  |            ng1ControllerXInstance.ng1XInputC = {value: 'baz5'}; | 
					
						
							|  |  |  |            $digest(adapter); | 
					
						
							|  |  |  |            tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            expect(multiTrim(document.body.textContent)) | 
					
						
							|  |  |  |                .toBe('ng2A(foo, bar, baz5) | ng1X(foo4, bar4, baz5) | ng2B(foo4, baz5)'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Update a property on `ng1XInputC`.
 | 
					
						
							|  |  |  |            // (Should propagate upwards and downwards.)
 | 
					
						
							|  |  |  |            ng1ControllerXInstance.ng1XInputC.value = 'baz6'; | 
					
						
							|  |  |  |            $digest(adapter); | 
					
						
							|  |  |  |            tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            expect(multiTrim(document.body.textContent)) | 
					
						
							|  |  |  |                .toBe('ng2A(foo, bar, baz6) | ng1X(foo4, bar4, baz6) | ng2B(foo4, baz6)'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Emit from `ng1XOutputA`.
 | 
					
						
							|  |  |  |            // (Should propagate upwards to `ng1ADataA` and back all the way down to
 | 
					
						
							|  |  |  |            // `ng2BInputA`.)
 | 
					
						
							|  |  |  |            (ng1ControllerXInstance as any).ng1XOutputA({value: 'foo7'}); | 
					
						
							|  |  |  |            $digest(adapter); | 
					
						
							|  |  |  |            tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            expect(multiTrim(document.body.textContent)) | 
					
						
							|  |  |  |                .toBe('ng2A(foo7, bar, baz6) | ng1X(foo7, bar4, baz6) | ng2B(foo7, baz6)'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Emit from `ng1XOutputB`.
 | 
					
						
							|  |  |  |            // (Should propagate upwards to `ng1ADataB`, but not downwards,
 | 
					
						
							|  |  |  |            //  since `ng1XInputB` has been re-assigned (i.e. `ng2ADataB !== ng1XInputB`).)
 | 
					
						
							|  |  |  |            (ng1ControllerXInstance as any).ng1XOutputB('bar8'); | 
					
						
							|  |  |  |            $digest(adapter); | 
					
						
							|  |  |  |            tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            expect(multiTrim(document.body.textContent)) | 
					
						
							|  |  |  |                .toBe('ng2A(foo7, bar8, baz6) | ng1X(foo7, bar4, baz6) | ng2B(foo7, baz6)'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            // Update `ng2ADataA`/`ng2ADataB`/`ng2ADataC`.
 | 
					
						
							|  |  |  |            // (Should propagate everywhere.)
 | 
					
						
							|  |  |  |            ng2ComponentAInstance.ng2ADataA = {value: 'foo9'}; | 
					
						
							|  |  |  |            ng2ComponentAInstance.ng2ADataB = {value: 'bar9'}; | 
					
						
							|  |  |  |            ng2ComponentAInstance.ng2ADataC = {value: 'baz9'}; | 
					
						
							|  |  |  |            $digest(adapter); | 
					
						
							|  |  |  |            tick(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            expect(multiTrim(document.body.textContent)) | 
					
						
							|  |  |  |                .toBe('ng2A(foo9, bar9, baz9) | ng1X(foo9, bar9, baz9) | ng2B(foo9, baz9)'); | 
					
						
							|  |  |  |          }); | 
					
						
							|  |  |  |        })); | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-16 23:52:42 +02:00
										 |  |  |     it('should support ng2 > ng1 > ng2 > ng1 (with `require`)', async(() => { | 
					
						
							| 
									
										
										
										
											2016-10-20 13:47:56 +03:00
										 |  |  |          // Define `ng1Component`
 | 
					
						
							|  |  |  |          const ng1ComponentA: angular.IComponent = { | 
					
						
							|  |  |  |            template: 'ng1A(<ng2-b></ng2-b>)', | 
					
						
							|  |  |  |            controller: class {value = 'ng1A';} | 
					
						
							|  |  |  |          }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          const ng1ComponentB: angular.IComponent = { | 
					
						
							|  |  |  |            template: | 
					
						
							|  |  |  |                'ng1B(^^ng1A: {{ $ctrl.ng1A.value }} | ?^^ng1B: {{ $ctrl.ng1B.value }} | ^ng1B: {{ $ctrl.ng1BSelf.value }})', | 
					
						
							|  |  |  |            require: {ng1A: '^^', ng1B: '?^^', ng1BSelf: '^ng1B'}, | 
					
						
							|  |  |  |            controller: class {value = 'ng1B';} | 
					
						
							|  |  |  |          }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          // Define `Ng1ComponentFacade`
 | 
					
						
							|  |  |  |          @Directive({selector: 'ng1A'}) | 
					
						
							|  |  |  |          class Ng1ComponentAFacade extends UpgradeComponent { | 
					
						
							|  |  |  |            constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |              super('ng1A', elementRef, injector); | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  |          } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          @Directive({selector: 'ng1B'}) | 
					
						
							|  |  |  |          class Ng1ComponentBFacade extends UpgradeComponent { | 
					
						
							|  |  |  |            constructor(elementRef: ElementRef, injector: Injector) { | 
					
						
							|  |  |  |              super('ng1B', elementRef, injector); | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  |          } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          // Define `Ng2Component`
 | 
					
						
							|  |  |  |          @Component({selector: 'ng2-a', template: 'ng2A(<ng1A></ng1A>)'}) | 
					
						
							|  |  |  |          class Ng2ComponentA { | 
					
						
							|  |  |  |          } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          @Component({selector: 'ng2-b', template: 'ng2B(<ng1B></ng1B>)'}) | 
					
						
							|  |  |  |          class Ng2ComponentB { | 
					
						
							|  |  |  |          } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          // Define `ng1Module`
 | 
					
						
							|  |  |  |          const ng1Module = angular.module('ng1', []) | 
					
						
							|  |  |  |                                .component('ng1A', ng1ComponentA) | 
					
						
							|  |  |  |                                .component('ng1B', ng1ComponentB) | 
					
						
							|  |  |  |                                .directive('ng2A', downgradeComponent({component: Ng2ComponentA})) | 
					
						
							|  |  |  |                                .directive('ng2B', downgradeComponent({component: Ng2ComponentB})); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          // Define `Ng2Module`
 | 
					
						
							|  |  |  |          @NgModule({ | 
					
						
							|  |  |  |            declarations: [Ng1ComponentAFacade, Ng1ComponentBFacade, Ng2ComponentA, Ng2ComponentB], | 
					
						
							|  |  |  |            entryComponents: [Ng2ComponentA, Ng2ComponentB], | 
					
						
							|  |  |  |            imports: [BrowserModule, UpgradeModule], | 
					
						
							|  |  |  |            schemas: [NO_ERRORS_SCHEMA], | 
					
						
							|  |  |  |          }) | 
					
						
							|  |  |  |          class Ng2Module { | 
					
						
							|  |  |  |            ngDoBootstrap() {} | 
					
						
							|  |  |  |          } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          // Bootstrap
 | 
					
						
							|  |  |  |          const element = html(`<ng2-a></ng2-a>`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(() => { | 
					
						
							|  |  |  |            expect(multiTrim(document.body.textContent)) | 
					
						
							|  |  |  |                .toBe('ng2A(ng1A(ng2B(ng1B(^^ng1A: ng1A | ?^^ng1B: | ^ng1B: ng1B))))'); | 
					
						
							|  |  |  |          }); | 
					
						
							|  |  |  |        })); | 
					
						
							| 
									
										
										
										
											2016-10-19 21:41:04 +01:00
										 |  |  |   }); | 
					
						
							| 
									
										
										
										
											2018-02-15 19:21:18 +02:00
										 |  |  | }); |