import { NgModuleFactoryLoader , Injector , ViewContainerRef , ComponentFactoryResolver , Type , Injectable , ComponentRef , ElementRef } from "@angular/core" ; import { ComponentSelectors } from "./component-selectors" ; @ Injectable ( ) export class DynamicComponentsService { constructor ( private loader , private injector ) { } /**
     * This map keeps track of the components that are open.
     * This is important to be able to reload components when their modules are hot-reloaded.
     */ private openComponents = new Map < ComponentRef < any > , CreateComponentRequest > ( ) ; param request public createComponent ( request ) { return this . loader . load ( request . modulePath ) . then ( ( moduleFactory ) => { const module = moduleFactory . create ( this . injector ) ; const componentFactoryResolver = module . componentFactoryResolver ; const factoryClass = this . getFactoryClass ( componentFactoryResolver , request . selectorName ) ; if ( ! factoryClass ) throw new Error ( `Unrecognized component name: ${ request . selectorName }` ) ; const componentFactory = componentFactoryResolver . resolveComponentFactory ( factoryClass ) ; const componentRef = request . outlet . createComponent ( componentFactory , request . index , module . injector ) ; this . openComponents . set ( componentRef , request ) ; } ) . catch ( err => { throw err ; } ) ; } param componentFactoryResolver param selector private getFactoryClass ( componentFactoryResolver , selector ) { const factories = Array . from ( componentFactoryResolver [ '_factories' ] . keys ( ) ) ; const factoryClass = < Type < any > > factories . find ( ( x ) => componentFactoryResolver [ '_factories' ] . get ( x ) . selector === selector ) ; return factoryClass ; } param componentTypes public reloadComponents ( componentTypes ) { let componentsToReload = Array . from ( this . openComponents . keys ( ) ) . filter ( c => componentTypes . some ( t => c . instance instanceof t ) ) ; let reloadRequests = new Array < CreateComponentRequest > ( ) ; for ( let componentToReload of componentsToReload ) { let request = this . openComponents . get ( componentToReload ) ; request . index = request . outlet . indexOf ( componentToReload . hostView ) ; reloadRequests . push ( request ) ; } componentsToReload . forEach ( c => this . closeComponentRef ( c ) ) ; reloadRequests . forEach ( r => this . createComponent ( r ) ) ; } param component public closeComponent ( component ) { let componentRef = Array . from ( this . openComponents . keys ( ) ) . find ( c => c . instance === component ) ; this . closeComponentRef ( componentRef ) ; } param componentRef protected closeComponentRef ( componentRef ) { componentRef . destroy ( ) ; this . openComponents . delete ( componentRef ) ; } } export interface CreateComponentRequest { modulePath : string ; selectorName : ComponentSelectors ; outlet : ViewContainerRef ; index ? : number ; }