Angular: 如何在动态组件中使用共享模块?
Angular: How to use shared modules in a Dynamic Component?
我正在使用 angular 编译器的 compileModuleAndAllComponentsAsync 在 Angular v6 中创建动态组件,代码如下。
viewChangeMethod(view: string) {
let template = `<span>${view} </span>`;
const tmpCmp = Component({ template: template })(class { });
this._compiler.clearCacheFor(this.tmpModule)
this.tmpModule = NgModule({ declarations: [tmpCmp,FRAComponent],import:[ComonModule] })(class {
});
this._compiler.compileModuleAndAllComponentsAsync(this.tmpModule)
.then((factories) => {
const f = factories.componentFactories[0];
const cmpRef = f.create(this._injector, [], null, this._m);
this._container.detach()
console.log(cmpRef.hostView)
this._container.insert(cmpRef.hostView);
})
this._compiler.clearCacheFor(this.tmpModule)
}
一切正常,但在导入任何共享模块或自定义模块时出现以下错误。
如果动态组件需要共享模块或任何附加模块,我建议您采用稍微不同的方法来创建动态组件。
我的项目使用动态组件,我也将各种模块导入其中,但我使用以下方法创建我的组件 - Full working StackBlitz
以上是我创建的 StackBlitz 示例,如果您想根据需要进行调整 ||下面是代码的副本。
import {
Component, ViewChild, AfterContentInit, ComponentFactoryResolver,
Compiler, ViewContainerRef, NgModule, NgModuleRef
} from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
@Component({
selector: 'app',
template: '<ng-template #vc></ng-template>',
styleUrls: ['./app.component.css']
})
export class AppComponent implements AfterContentInit {
@ViewChild('vc', { read: ViewContainerRef }) _container: ViewContainerRef;
private cmpRef;
constructor(
private componentFactoryResolver: ComponentFactoryResolver,
private compiler: Compiler,
private _m: NgModuleRef<any>) { }
ngAfterContentInit() {
this.addComponent();
}
public sayHello(): void{
alert("Hello!");
}
private addComponent(): void {
@Component({
template: `<h2>This is a dynamic component</h2>
<button (click)="_parent.sayHello()">Click me!</button>`
})
class DynamicComponent {
constructor(public _parent: AppComponent) { }
}
@NgModule({
imports: [
BrowserModule
],
declarations: [DynamicComponent],
}) class DynamicModule { }
const mod = this.compiler.compileModuleAndAllComponentsSync(DynamicModule);
const factory = mod.componentFactories.find((comp) =>
comp.componentType === DynamicComponent
);
this.cmpRef = this._container.createComponent(factory);
}
}
您可以按照下面的解决方案来完成您的工作,我已经验证了它以前的 NG 版本,您可以尝试集成到您的解决方案中。
像这样定义服务
import { Injectable, Type, Component, ComponentFactoryResolver, ViewContainerRef, ComponentRef, QueryList, ComponentFactory } from '@angular/core';
@Injectable()
export class DynamicComponentService {
constructor(private componentFactoryResolver: ComponentFactoryResolver) {
}
public append(componentType: Type<any>, where: ViewContainerRef): ComponentRef<any> {
const componentFactory = this.resolveFactory(componentType);
const componentRef = where.createComponent(componentFactory);
return componentRef;
}
public resolve (componentType: Type<any>): ComponentFactory<any> {
const componentFactory: ComponentFactory<any> = this.componentFactoryResolver.resolveComponentFactory(componentType);
return componentFactory;
}
}
以上服务负责动态注入您的组件。
另请注意,您不需要将组件作为字符串传递,您需要传递其类型。
在实施前请仔细阅读以上 class。
用法 –
在您的组件中注入服务
同样在组件中获取View Container Reference(在我下面的代码中this.viewContainerReference,这是必须注入动态组件的地方)
componentReference = this.dynamicComponentService.append(ComponentClass, this.viewContainerReference);
componentReference.instance.someProp = whatever;
上面的someProp是你组件的public属性,你可以传一些数据给它。
您可以像往常一样导入您的模块作为@NgModule 导入和组件的一部分
还要确保你有 模式:[NO_ERRORS_SCHEMA]
我正在使用 angular 编译器的 compileModuleAndAllComponentsAsync 在 Angular v6 中创建动态组件,代码如下。
viewChangeMethod(view: string) {
let template = `<span>${view} </span>`;
const tmpCmp = Component({ template: template })(class { });
this._compiler.clearCacheFor(this.tmpModule)
this.tmpModule = NgModule({ declarations: [tmpCmp,FRAComponent],import:[ComonModule] })(class {
});
this._compiler.compileModuleAndAllComponentsAsync(this.tmpModule)
.then((factories) => {
const f = factories.componentFactories[0];
const cmpRef = f.create(this._injector, [], null, this._m);
this._container.detach()
console.log(cmpRef.hostView)
this._container.insert(cmpRef.hostView);
})
this._compiler.clearCacheFor(this.tmpModule)
}
一切正常,但在导入任何共享模块或自定义模块时出现以下错误。
如果动态组件需要共享模块或任何附加模块,我建议您采用稍微不同的方法来创建动态组件。
我的项目使用动态组件,我也将各种模块导入其中,但我使用以下方法创建我的组件 - Full working StackBlitz
以上是我创建的 StackBlitz 示例,如果您想根据需要进行调整 ||下面是代码的副本。
import {
Component, ViewChild, AfterContentInit, ComponentFactoryResolver,
Compiler, ViewContainerRef, NgModule, NgModuleRef
} from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
@Component({
selector: 'app',
template: '<ng-template #vc></ng-template>',
styleUrls: ['./app.component.css']
})
export class AppComponent implements AfterContentInit {
@ViewChild('vc', { read: ViewContainerRef }) _container: ViewContainerRef;
private cmpRef;
constructor(
private componentFactoryResolver: ComponentFactoryResolver,
private compiler: Compiler,
private _m: NgModuleRef<any>) { }
ngAfterContentInit() {
this.addComponent();
}
public sayHello(): void{
alert("Hello!");
}
private addComponent(): void {
@Component({
template: `<h2>This is a dynamic component</h2>
<button (click)="_parent.sayHello()">Click me!</button>`
})
class DynamicComponent {
constructor(public _parent: AppComponent) { }
}
@NgModule({
imports: [
BrowserModule
],
declarations: [DynamicComponent],
}) class DynamicModule { }
const mod = this.compiler.compileModuleAndAllComponentsSync(DynamicModule);
const factory = mod.componentFactories.find((comp) =>
comp.componentType === DynamicComponent
);
this.cmpRef = this._container.createComponent(factory);
}
}
您可以按照下面的解决方案来完成您的工作,我已经验证了它以前的 NG 版本,您可以尝试集成到您的解决方案中。
像这样定义服务
import { Injectable, Type, Component, ComponentFactoryResolver, ViewContainerRef, ComponentRef, QueryList, ComponentFactory } from '@angular/core';
@Injectable()
export class DynamicComponentService {
constructor(private componentFactoryResolver: ComponentFactoryResolver) {
}
public append(componentType: Type<any>, where: ViewContainerRef): ComponentRef<any> {
const componentFactory = this.resolveFactory(componentType);
const componentRef = where.createComponent(componentFactory);
return componentRef;
}
public resolve (componentType: Type<any>): ComponentFactory<any> {
const componentFactory: ComponentFactory<any> = this.componentFactoryResolver.resolveComponentFactory(componentType);
return componentFactory;
}
}
以上服务负责动态注入您的组件。
另请注意,您不需要将组件作为字符串传递,您需要传递其类型。
在实施前请仔细阅读以上 class。
用法 –
在您的组件中注入服务 同样在组件中获取View Container Reference(在我下面的代码中this.viewContainerReference,这是必须注入动态组件的地方)
componentReference = this.dynamicComponentService.append(ComponentClass, this.viewContainerReference);
componentReference.instance.someProp = whatever;
上面的someProp是你组件的public属性,你可以传一些数据给它。
您可以像往常一样导入您的模块作为@NgModule 导入和组件的一部分 还要确保你有 模式:[NO_ERRORS_SCHEMA]