Angular 13 如何动态加载组件?
How do you load Components dynamically in Angular 13?
我的任务是将 Angular 库从 7 更新到 13。该库使用 Compiler 和 ComponentFactory 来动态加载组件。但是那些 classes 现在已被弃用,而且我没有找到关于如何在不使用这些 classes 的情况下执行此操作的真正指南。
这是有问题的代码:
动态-content.component.ts:
...
private createCompiledTemplateFactory = (template: string, extensionType: string): ComponentFactory<any> | undefined => {
const metadata = {
selector: `dynamic-extended-component-${extensionType}`,
template: template
};
const extType = ClassInjector.get(extensionType);
if (!extType) {
throw new Error('Type not found: ' + extensionType);
}
return this.createComponentFactorySync(metadata, null, extType);
}
private createComponentFactorySync = (metadata: Component, componentClass: any, extensionType: Type<any>)
: ComponentFactory<any> | undefined => {
const cmpClass = componentClass || class RuntimeComponent extends extensionType { };
const decoratedCmp = Component(metadata)(cmpClass);
const externalImports = this.externalImports;
@NgModule({
imports: [
CommonModule,
FormsModule,
DynamicGridModule.forChild(),
DxButtonModule,
DxSwitchModule,
TranslateModule,
RouterModule,
externalImports,
DynamicPageCommonComponentsModule
],
declarations: [decoratedCmp]
})
class RuntimeComponentModule { }
const module: ModuleWithComponentFactories<any> = this.compiler.compileModuleAndAllComponentsSync(RuntimeComponentModule);
return module.componentFactories.find(f => f.componentType === decoratedCmp);
}
...
class-injector.ts
export class ClassInjector {
private static registry: { [key: string]: Type<any> } = {};
static register(key: string, value: Type<any>) {
const registered = ClassInjector.registry[key];
if (registered) {
throw new Error(`Error: ${key} is already registered.`);
}
ClassInjector.registry[key] = value;
}
static get(key: string): Type<any> {
const registered = ClassInjector.registry[key];
if (registered) {
return registered;
} else {
throw new Error(`Error: ${key} was not registered.`);
}
}
}
export function RegisterActionHandler(name: string) {
return (target: Type<any>) => ClassInjector.register(name, target);
}
如果有人能指导我正确的方向,我将不胜感激。
您可以使用 cdkPortalOutlet
from here ,
这里是demo code to play around with as well.
您还可以监听如下渲染事件
<ng-template [cdkPortalOutlet]="portal" (attached)="onComponentRendering($event)"></ng-template>
在组件中
this.portal = new ComponentPortal(SomeComponent);
听onComponentRendering
做更多
我们发现该组件可以在不提及编译器的情况下工作:
dynamic-content.component.ts:
...
private createComponent = (template: string, extensionType: string) : Type<any> => {
const metadata = {
selector: `dynamic-extended-component-${extensionType}`,
template: template
};
const extType = ClassInjector.get(extensionType);
if (!extType) {
throw new Error('Type not found: ' + extensionType);
}
return Component(metadata)(class RuntimeComponent extends extType { });
}
private createModule = (component: Type<any>) : Type<any> => {
const externalImports = this.externalImports;
const module = NgModule({
imports: [
CommonModule,
FormsModule,
DynamicGridModule.forChild(),
DxButtonModule,
DxSwitchModule,
TranslateModule,
RouterModule,
externalImports,
DynamicPageCommonComponentsModule
],
declarations: [component]
})(
class RuntimeComponentModule { });
return module;
}
...
class-injector.ts 保持不变。
不使用工厂,就得用ViewContainerRef.createComponent
。
参考下面link
我的任务是将 Angular 库从 7 更新到 13。该库使用 Compiler 和 ComponentFactory 来动态加载组件。但是那些 classes 现在已被弃用,而且我没有找到关于如何在不使用这些 classes 的情况下执行此操作的真正指南。 这是有问题的代码:
动态-content.component.ts:
...
private createCompiledTemplateFactory = (template: string, extensionType: string): ComponentFactory<any> | undefined => {
const metadata = {
selector: `dynamic-extended-component-${extensionType}`,
template: template
};
const extType = ClassInjector.get(extensionType);
if (!extType) {
throw new Error('Type not found: ' + extensionType);
}
return this.createComponentFactorySync(metadata, null, extType);
}
private createComponentFactorySync = (metadata: Component, componentClass: any, extensionType: Type<any>)
: ComponentFactory<any> | undefined => {
const cmpClass = componentClass || class RuntimeComponent extends extensionType { };
const decoratedCmp = Component(metadata)(cmpClass);
const externalImports = this.externalImports;
@NgModule({
imports: [
CommonModule,
FormsModule,
DynamicGridModule.forChild(),
DxButtonModule,
DxSwitchModule,
TranslateModule,
RouterModule,
externalImports,
DynamicPageCommonComponentsModule
],
declarations: [decoratedCmp]
})
class RuntimeComponentModule { }
const module: ModuleWithComponentFactories<any> = this.compiler.compileModuleAndAllComponentsSync(RuntimeComponentModule);
return module.componentFactories.find(f => f.componentType === decoratedCmp);
}
...
class-injector.ts
export class ClassInjector {
private static registry: { [key: string]: Type<any> } = {};
static register(key: string, value: Type<any>) {
const registered = ClassInjector.registry[key];
if (registered) {
throw new Error(`Error: ${key} is already registered.`);
}
ClassInjector.registry[key] = value;
}
static get(key: string): Type<any> {
const registered = ClassInjector.registry[key];
if (registered) {
return registered;
} else {
throw new Error(`Error: ${key} was not registered.`);
}
}
}
export function RegisterActionHandler(name: string) {
return (target: Type<any>) => ClassInjector.register(name, target);
}
如果有人能指导我正确的方向,我将不胜感激。
您可以使用 cdkPortalOutlet
from here ,
这里是demo code to play around with as well.
您还可以监听如下渲染事件
<ng-template [cdkPortalOutlet]="portal" (attached)="onComponentRendering($event)"></ng-template>
在组件中
this.portal = new ComponentPortal(SomeComponent);
听onComponentRendering
做更多
我们发现该组件可以在不提及编译器的情况下工作:
dynamic-content.component.ts:
...
private createComponent = (template: string, extensionType: string) : Type<any> => {
const metadata = {
selector: `dynamic-extended-component-${extensionType}`,
template: template
};
const extType = ClassInjector.get(extensionType);
if (!extType) {
throw new Error('Type not found: ' + extensionType);
}
return Component(metadata)(class RuntimeComponent extends extType { });
}
private createModule = (component: Type<any>) : Type<any> => {
const externalImports = this.externalImports;
const module = NgModule({
imports: [
CommonModule,
FormsModule,
DynamicGridModule.forChild(),
DxButtonModule,
DxSwitchModule,
TranslateModule,
RouterModule,
externalImports,
DynamicPageCommonComponentsModule
],
declarations: [component]
})(
class RuntimeComponentModule { });
return module;
}
...
class-injector.ts 保持不变。
不使用工厂,就得用ViewContainerRef.createComponent
。
参考下面link