From 3f0b53ff51df90996df5a81965dba23ee1361439 Mon Sep 17 00:00:00 2001 From: Tero Parviainen Date: Thu, 11 Feb 2016 08:32:42 +0200 Subject: [PATCH] fix(upgrade): support deferred bootstrap Have UpgradeAdapter wait for Angular 1 to bootstrap before running delayed $applys. This fixes the use of UpgradeAdapter with Protractor. Closes #6547 --- modules/angular2/src/upgrade/angular_js.ts | 2 + .../angular2/src/upgrade/upgrade_adapter.ts | 73 ++++++++++--------- modules/angular2/test/upgrade/upgrade_spec.ts | 22 ++++++ 3 files changed, 62 insertions(+), 35 deletions(-) diff --git a/modules/angular2/src/upgrade/angular_js.ts b/modules/angular2/src/upgrade/angular_js.ts index 817815094f6e..d750f5de27a1 100644 --- a/modules/angular2/src/upgrade/angular_js.ts +++ b/modules/angular2/src/upgrade/angular_js.ts @@ -103,6 +103,7 @@ function noNg() { var angular: { bootstrap: (e: Element, modules: string[], config: IAngularBootstrapConfig) => void, + resumeBootstrap?: (extraModules?: string[]) => void, module: (prefix: string, dependencies?: string[]) => IModule, element: (e: Element) => IAugmentedJQuery, version: {major: number} @@ -118,6 +119,7 @@ try { } export var bootstrap = angular.bootstrap; +export var getResumeBootstrap = () => angular.resumeBootstrap; export var module = angular.module; export var element = angular.element; export var version = angular.version; diff --git a/modules/angular2/src/upgrade/upgrade_adapter.ts b/modules/angular2/src/upgrade/upgrade_adapter.ts index 2e417f06b3d6..65e4bdb64b98 100644 --- a/modules/angular2/src/upgrade/upgrade_adapter.ts +++ b/modules/angular2/src/upgrade/upgrade_adapter.ts @@ -308,46 +308,49 @@ export class UpgradeAdapter { var rootScopePrototype: any; var rootScope: angular.IRootScopeService; var hostViewFactoryRefMap: HostViewFactoryRefMap = {}; + var downgradedComponents = this.downgradedComponents; var ng1Module = angular.module(this.idPrefix, modules); - var ng1compilePromise: Promise = null; - ng1Module.value(NG2_INJECTOR, injector) - .value(NG2_ZONE, ngZone) - .value(NG2_COMPILER, compiler) - .value(NG2_HOST_VIEW_FACTORY_REF_MAP, hostViewFactoryRefMap) - .value(NG2_APP_VIEW_MANAGER, injector.get(AppViewManager)) - .config([ - '$provide', - (provide) => { - provide.decorator(NG1_ROOT_SCOPE, [ - '$delegate', - function(rootScopeDelegate: angular.IRootScopeService) { - rootScopePrototype = rootScopeDelegate.constructor.prototype; - if (rootScopePrototype.hasOwnProperty('$apply')) { - original$applyFn = rootScopePrototype.$apply; - rootScopePrototype.$apply = (exp) => delayApplyExps.push(exp); - } else { - throw new Error("Failed to find '$apply' on '$rootScope'!"); + var ng1bootstrapPromise = new Promise(function(resolveBootstrap, rejectBootstrap) { + ng1Module.value(NG2_INJECTOR, injector) + .value(NG2_ZONE, ngZone) + .value(NG2_COMPILER, compiler) + .value(NG2_HOST_VIEW_FACTORY_REF_MAP, hostViewFactoryRefMap) + .value(NG2_APP_VIEW_MANAGER, injector.get(AppViewManager)) + .config([ + '$provide', + (provide) => { + provide.decorator(NG1_ROOT_SCOPE, [ + '$delegate', + function(rootScopeDelegate: angular.IRootScopeService) { + rootScopePrototype = rootScopeDelegate.constructor.prototype; + if (rootScopePrototype.hasOwnProperty('$apply')) { + original$applyFn = rootScopePrototype.$apply; + rootScopePrototype.$apply = (exp) => delayApplyExps.push(exp); + } else { + throw new Error("Failed to find '$apply' on '$rootScope'!"); + } + return rootScope = rootScopeDelegate; } - return rootScope = rootScopeDelegate; - } - ]); - } - ]) - .run([ - '$injector', - '$rootScope', - (injector: angular.IInjectorService, rootScope: angular.IRootScopeService) => { - ng1Injector = injector; - ObservableWrapper.subscribe(ngZone.onTurnDone, - (_) => ngZone.runOutsideAngular(() => rootScope.$apply())); - ng1compilePromise = - UpgradeNg1ComponentAdapterBuilder.resolve(this.downgradedComponents, injector); - } - ]); + ]); + } + ]) + .run([ + '$injector', + '$rootScope', + (injector: angular.IInjectorService, rootScope: angular.IRootScopeService) => { + ng1Injector = injector; + ObservableWrapper.subscribe( + ngZone.onTurnDone, (_) => ngZone.runOutsideAngular(() => rootScope.$apply())); + UpgradeNg1ComponentAdapterBuilder.resolve(downgradedComponents, injector) + .then(resolveBootstrap) + .catch(rejectBootstrap); + } + ]); + }); angular.element(element).data(controllerKey(NG2_INJECTOR), injector); ngZone.run(() => { angular.bootstrap(element, [this.idPrefix], config); }); - Promise.all([this.compileNg2Components(compiler, hostViewFactoryRefMap), ng1compilePromise]) + Promise.all([this.compileNg2Components(compiler, hostViewFactoryRefMap), ng1bootstrapPromise]) .then(() => { ngZone.run(() => { if (rootScopePrototype) { diff --git a/modules/angular2/test/upgrade/upgrade_spec.ts b/modules/angular2/test/upgrade/upgrade_spec.ts index aca71573614d..778c9f9eb298 100644 --- a/modules/angular2/test/upgrade/upgrade_spec.ts +++ b/modules/angular2/test/upgrade/upgrade_spec.ts @@ -559,6 +559,28 @@ export function main() { })); }); + describe('bootstrap', () => { + + it('should support deferred bootstrap', inject([AsyncTestCompleter], (async) => { + var adapter = new UpgradeAdapter(); + var module = angular.module('myExample', []); + + window.name = 'NG_DEFER_BOOTSTRAP! test'; + var element = html(`
{{ 'ng1' }}
`); + adapter.bootstrap(element, ['myExample']) + .ready((ref) => { + expect(multiTrim(document.body.textContent)).toEqual("ng1"); + ref.dispose(); + async.done(); + }); + setTimeout(() => { + var resumeBootstrap = angular.getResumeBootstrap(); + resumeBootstrap(); + }, 0); + })); + + }); + describe('examples', () => { it('should verify UpgradeAdapter example', inject([AsyncTestCompleter], (async) => { var adapter = new UpgradeAdapter();