Repository: angular
Issue: UpgradeModule needs to support Hybrid Apps w/ Lazily loaded Hybrid Bundles, using the AngularJS Router
Labels: feature,freq1: low,workaround2: non-obvious,area: upgrade,P4,feature: under consideration

<!--
PLEASE HELP US PROCESS GITHUB ISSUES FASTER BY PROVIDING THE FOLLOWING INFORMATION.

ISSUES MISSING IMPORTANT INFORMATION MIGHT BE CLOSED WITHOUT INVESTIGATION.
-->

## I'm submitting a ...
<!-- Check one of the following options with "x" -->
<pre><code>
[ ] Regression (behavior that used to work and stopped working in a new release)
[ ] Bug report <!-- Please search github for a similar issue or PR before submitting -->
[x] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question
</code></pre>

## Current behavior
<!-- Describe how the issue manifests. -->
I am able to lazily load code in an AngularJS app that uses the AngularJS router, using `ocLazyLoad`. This all works. If you add Angular components to both the main app, as well as to the lazily loaded feature bundle, the Angular components in the main app are accessible to be downgraded and used inside of AngularJS templates. However, the Angular components in the lazily loaded feature bundle are able to be downgraded, but NOT able to be used in the AngularJS templates. This is due largely to the fact that the `downgradeComponent` method doesn't allow me to specify which injector it should use to access the componentFactories for the lazily loaded components. Because I can't specify which injector to use, it uses the main `AppModule`'s injector, which has no knowledge of the lazily loaded module or components. 

## Expected behavior
<!-- Describe what the desired behavior would be. -->
I should be able to optionally specify which injector I want the `downgradeComponent` to use to resolve the componentFactory. 

## Minimal reproduction of the problem with instructions
<!--
For bug reports please provide the *STEPS TO REPRODUCE* and if possible a *MINIMAL DEMO* of the problem via
https://plnkr.co or similar (you can use this template as a starting point: http://plnkr.co/edit/tpl:AvJOMERrnz94ekVua0u5).
-->
1. Create an AngularJS app, that uses the AngularJS router. 
2. Add a webpack build to your project that will allow you to easily code split, so that you can break your lazily loaded features in to separate bundles. 
3. Add `ocLazyLoad` to the app, and use it to lazily load a feature/section of the app. 
4. Add Angular to the app (`npm i @angular/common @angular/compiler @angular/compiler-cli @angular/core @angular/forms @angular/http @angular/platform-browser @angular/platform-browser-dynamic @angular/router @angular/upgrade rxjs zone.js`)
5. Create an `AppModule` that will be part of your main bundle. Add a simple component to that module, and downgrade it, and use it in your AngularJS template, to verify that Angular is working inside of the AngularJS app. As part of this step, you will need to bootstrap the Angular app first, and then in the callback from that, using the `UpgradeModule` you bootstrap the AngularJS app. 
6. Now add a `FooModule` to your lazily loaded feature bundle, and add a `FooComponent` to that modules `entryComponents`. Make sure and downgrade this component so that it can be used in the AngularJS pieces of this lazily loaded feature. 
7. Add the downgraded component to the AngularJS template. (if you refresh the page at this point, you will get an error: `No component factory found for FooComponent. Did you add it to @NgModule.entryComponents?`, but keep going)
8. Create a separate `tsconfig-aot.json` and in the `files` value, add a reference to the file containing your `FooModule`. 
9. Run `ngc -p path/to/your/tsconfig-aot.json` to generate your 'FooModuleNgFactory`. 
10. In the bundle for your lazily loaded feature, import the `FooModuleNgFactory` and call the following:
```foo.bundle.js
const appModuleRef = getAppModuleRef(); // get access to it somehow
const fooModuleRef = FooModuleNgFactory.create(appModuleRef.injector);

// now that you created an instance of your lazily loaded module, you should downgrade the component in that module
angular
    .module('angularJSModule')
    .directive('fooComponent', downgradeComponent({component:FooComponent});
```
Having done all of this, I expected that the components from my lazily loaded Angular module would be able to work. But when I add them to my AngularJS templates I get the error `No component factory found for FooComponent. Did you add it to @NgModule.entryComponents?`. The reason that it is throwing this error is because the call to `downgradeComponent` is trying to find the `FooComponentFactory` in the main `AppModule`'s injector. But it doesn't exist in that injector. It exists in the child injector that was created when I created the instance of my lazily loaded module (ie: when I called `FooModuleNgFactory.create`). 

If I hack the Angular source to allow me to optionally pass in the injector to the `downgradeComponent` method, it all works fine. Just like I would expect. 

I would like to see if the `UpgradeModule`'s `downgradeComponent` method could support an optional injector to be passed in. The hack that I made to get it to work was the following:
```foo.bundle.js
const appModuleRef = getAppModuleRef();
const fooModuleRef = FooModuleNgFactory.create(appModuleRef.injector);
const directiveConfig = downgradeComponent({component:FooComponent, injector: fooModuleRef.injector});

angular
    .module('angularJsModule')
    .directive('fooComponent', directiveConfig);
```
Notice how I pass in the injector as well. I modified the `downgradeComponent` function to look like this: 
![image](https://user-images.githubusercontent.com/662832/27116515-efc4e7fa-508e-11e7-84f4-ede516bd0c2f.png)

Doing this, I was able to get Angular modules lazily loaded and created WITHOUT using the Angular router. It would be nice if the `downgradeComponent` method supported it native. 

I spoke with @robwormald, and he agreed that this is a valid use-case that ngUpgrade should cover. He said he may speak with @petebacondarwin about it to see what his thoughts are. 

## What is the motivation / use case for changing the behavior?
<!-- Describe the motivation or the concrete use case. -->
All of the examples in the `ngUpgrade` documentation are under the assumption that I am using the Angular router. Many apps are very large, and aren't able to switch their router before they even have any Angular components in that lazily loaded section of code. It makes sense for them to need to continue using the AngularJS router. 

## Please tell us about your environment

<pre><code>
Angular version: 1.5.11
<!-- Check whether this is still an issue in the most recent Angular version -->

Browser:
- [x] Chrome (desktop) version XX
- [x] Chrome (Android) version XX
- [x] Chrome (iOS) version XX
- [x] Firefox version XX
- [x] Safari (desktop) version XX
- [x] Safari (iOS) version XX
- [x] IE version XX
- [x] Edge version XX
 
For Tooling issues:
- Node version: 7.4.0 <!-- use `node --version` -->
- Platform: Mac <!-- Mac, Linux, Windows -->

Others:
<!-- Anything else relevant?  Operating system version, IDE, package manager, HTTP server, ... -->
</code></pre>