Skip to content

Instantly share code, notes, and snippets.

@wesleygrimes
Last active February 28, 2019 19:26
Show Gist options
  • Save wesleygrimes/fc8bd196d896b47debae0c009b6f5709 to your computer and use it in GitHub Desktop.
Save wesleygrimes/fc8bd196d896b47debae0c009b6f5709 to your computer and use it in GitHub Desktop.
Dynamic Content Outlet Service
import {
ComponentFactoryResolver,
ComponentRef,
Injectable,
Injector,
NgModuleFactoryLoader,
Type
} from '@angular/core';
import { DynamicContentOutletErrorComponent } from './dynamic-content-outlet-error.component';
import { DynamicContentOutletRegistry } from './dynamic-content-outlet.registry';
type ModuleWithDynamicComponents = Type<any> & {
dynamicComponentsMap: {};
};
@Injectable()
export class DynamicContentOutletService {
constructor(
private componentFactoryResolver: ComponentFactoryResolver,
private moduleLoader: NgModuleFactoryLoader,
private injector: Injector
) {}
async GetComponent(componentName: string): Promise<ComponentRef<any>> {
const modulePath = this.getModulePathForComponent(componentName);
if (!modulePath) {
return this.getDynamicContentErrorComponent(
`Unable to derive modulePath from component: ${componentName} in dynamic-content.registry.ts`
);
}
try {
const moduleFactory = await this.moduleLoader.load(modulePath);
const moduleReference = moduleFactory.create(this.injector);
const componentResolver = moduleReference.componentFactoryResolver;
const componentType = (moduleFactory.moduleType as ModuleWithDynamicComponents)
.dynamicComponentsMap[componentName];
const componentFactory = componentResolver.resolveComponentFactory(
componentType
);
return componentFactory.create(this.injector);
} catch (error) {
console.error(error.message);
return this.getDynamicContentErrorComponent(
`Unable to load module ${modulePath}.
Looked up using component: ${componentName}. Error Details: ${
error.message
}`
);
}
}
private getModulePathForComponent(componentName: string) {
const registryItem = DynamicContentOutletRegistry.find(
i => i.componentName === componentName
);
if (registryItem && registryItem.modulePath) {
// imported modules must be in the format 'path#moduleName'
return `${registryItem.modulePath}#${registryItem.moduleName}`;
}
return null;
}
private getDynamicContentErrorComponent(errorMessage: string) {
const factory = this.componentFactoryResolver.resolveComponentFactory(
DynamicContentOutletErrorComponent
);
const componentRef = factory.create(this.injector);
const instance = <any>componentRef.instance;
instance.errorMessage = errorMessage;
return componentRef;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment