From db8290632fd70377b3f820dfd2acee778ec2f267 Mon Sep 17 00:00:00 2001 From: Hannah Howard Date: Tue, 17 May 2016 15:55:53 -0700 Subject: [PATCH] fix(upgrade): fallback to root ng2 injector when element is compiled outside the document (#8684) Currently downgraded ng2 elements fail inside a ui-router view because they are unable to require an ng2 Injector via the require attribute of the DDO, because ui-router compiles its templates before they are inserted in a ui-view. This adds a "fallback" behavior if a parent injector cannot be found to go to the root ng2 Injector. --- modules/@angular/upgrade/src/constants.ts | 2 +- .../upgrade/src/downgrade_ng2_adapter.ts | 2 +- .../@angular/upgrade/src/upgrade_adapter.ts | 8 +++-- modules/@angular/upgrade/test/upgrade_spec.ts | 31 +++++++++++++++++++ 4 files changed, 39 insertions(+), 4 deletions(-) diff --git a/modules/@angular/upgrade/src/constants.ts b/modules/@angular/upgrade/src/constants.ts index 7dcb8ecceb..3172a58486 100644 --- a/modules/@angular/upgrade/src/constants.ts +++ b/modules/@angular/upgrade/src/constants.ts @@ -12,4 +12,4 @@ export const NG1_INJECTOR = '$injector'; export const NG1_PARSE = '$parse'; export const NG1_TEMPLATE_CACHE = '$templateCache'; export const NG1_TESTABILITY = '$$testability'; -export const REQUIRE_INJECTOR = '^' + NG2_INJECTOR; +export const REQUIRE_INJECTOR = '?^' + NG2_INJECTOR; diff --git a/modules/@angular/upgrade/src/downgrade_ng2_adapter.ts b/modules/@angular/upgrade/src/downgrade_ng2_adapter.ts index cd52147af8..dfbf35bc9b 100644 --- a/modules/@angular/upgrade/src/downgrade_ng2_adapter.ts +++ b/modules/@angular/upgrade/src/downgrade_ng2_adapter.ts @@ -42,7 +42,7 @@ export class DowngradeNg2ComponentAdapter { this.contentInsertionPoint = document.createComment('ng1 insertion point'); this.componentRef = - this.componentFactory.create(childInjector, [[this.contentInsertionPoint]], '#' + this.id); + this.componentFactory.create(childInjector, [[this.contentInsertionPoint]], this.element[0]); this.changeDetector = this.componentRef.changeDetectorRef; this.component = this.componentRef.instance; } diff --git a/modules/@angular/upgrade/src/upgrade_adapter.ts b/modules/@angular/upgrade/src/upgrade_adapter.ts index 6a242dc355..d280ac34b5 100644 --- a/modules/@angular/upgrade/src/upgrade_adapter.ts +++ b/modules/@angular/upgrade/src/upgrade_adapter.ts @@ -540,8 +540,9 @@ interface ComponentFactoryRefMap { } function ng1ComponentDirective(info: ComponentInfo, idPrefix: string): Function { - (directiveFactory).$inject = [NG2_COMPONENT_FACTORY_REF_MAP, NG1_PARSE]; - function directiveFactory(componentFactoryRefMap: ComponentFactoryRefMap, + (directiveFactory).$inject = [NG1_INJECTOR, NG2_COMPONENT_FACTORY_REF_MAP, NG1_PARSE]; + function directiveFactory(ng1Injector: angular.IInjectorService, + componentFactoryRefMap: ComponentFactoryRefMap, parse: angular.IParseService): angular.IDirective { var componentFactory: ComponentFactory = componentFactoryRefMap[info.selector]; if (!componentFactory) throw new Error('Expecting ComponentFactory for: ' + info.selector); @@ -553,6 +554,9 @@ function ng1ComponentDirective(info: ComponentInfo, idPrefix: string): Function post: (scope: angular.IScope, element: angular.IAugmentedJQuery, attrs: angular.IAttributes, parentInjector: any, transclude: angular.ITranscludeFunction): void => { var domElement = element[0]; + if (parentInjector === null) { + parentInjector = ng1Injector.get(NG2_INJECTOR); + } var facade = new DowngradeNg2ComponentAdapter(idPrefix + (idCount++), info, element, attrs, scope, parentInjector, parse, componentFactory); diff --git a/modules/@angular/upgrade/test/upgrade_spec.ts b/modules/@angular/upgrade/test/upgrade_spec.ts index 47ae40089b..0d89b86955 100644 --- a/modules/@angular/upgrade/test/upgrade_spec.ts +++ b/modules/@angular/upgrade/test/upgrade_spec.ts @@ -256,6 +256,37 @@ export function main() { async.done(); })}); })); + + + it('should fallback to the root ng2.injector when compiled outside the dom', + inject([AsyncTestCompleter], (async) => { + var adapter: UpgradeAdapter = new UpgradeAdapter(); + var ng1Module = angular.module('ng1', []); + + ng1Module.directive('ng1', ['$compile', ($compile) => { + return { + link: function($scope, $element, $attrs) { + var compiled = $compile(""); + var template = compiled($scope); + $element.append(template); + } + }; + }]); + + var Ng2 = Component({ selector: 'ng2', template: 'test' }) + .Class({ + constructor: function() { } + }); + ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2)); + var element = html(''); + adapter.bootstrap(element, ['ng1']) + .ready((ref) => { + expect(multiTrim(document.body.textContent)) + .toEqual('test'); + ref.dispose(); + async.done(); + }); + })); }); describe('upgrade ng1 component', () => {