Angular - 在动态加载 module/component 中更改检测而不使用 `ChangeDetectorRef`
Angular - change detection in dynamically loaded module/component without using `ChangeDetectorRef`
我用编译器的 compileModuleAsync
编译了一个 Angular 模块(动态加载模块)并想将模块的一个组件插入视图。
我尝试将组件插入 ViewContainer
,但组件不会自动检测更改。每次更新组件的 属性.
时,我都应该调用 changeDetectorRef.detectChanges
有没有什么方法可以不使用 changeDetectorRef
来实现?
Angular 版本为 10.0.4
.
我加载组件的示例代码:
我加载另一个组件的组件:
<ng-template #dynamic></ng-template>
@ViewChild('dynamic', { read: ViewContainerRef })
dynamic: ViewContainerRef;
constructor(
private compiler: Compiler,
private injector: Injector
) {}
async ngAfterViewInit() {
// Load a module dynamically
const exampleModule = await import('../example/example.module').then(m => m.ExampleModule);
const moduleFactory = await this.compiler.compileModuleAsync(exampleModule);
const moduleRef = moduleFactory.create(this.injector);
const componentFactory = moduleRef.instance.resolveComponent();
const ref = container.createComponent(componentFactory, null, moduleRef.injector);
}
示例模块:
@NgModule({
declarations: [
ExampleComponent
],
imports: [...]
})
export class ExampleModule {
constructor(private componentFactoryResolver: ComponentFactoryResolver) { }
public resolveComponent(): ComponentFactory<ExampleComponent> {
return this.componentFactoryResolver.resolveComponentFactory(ExampleComponent);
}
}
调用detectChanges
的示例:
示例组件
<button (click)="toggle()">Show/Hide</button>
<span *ngIf="show">Show</span>
public toggle() {
this.show = !this.show;
this.cdr.detectChanges(); // <- I want to not use this.
}
我使用此服务创建组件并设置输入:
@Directive({
selector: '[formField]'
})
export class FormFieldDirective implements Field, OnChanges, OnInit, AfterViewInit {
@Input() config: FieldConfig;
@Input() lang: string;
@Input() group: FormGroup;
@Input('class') classList: string = 'col-12';
component: ComponentRef<Field>;
constructor(
private resolver: ComponentFactoryResolver,
private container: ViewContainerRef,
private renderer: Renderer2
) { }
ngOnChanges() {
if (this.component) {
this.component.instance.config = this.config;
this.component.instance.group = this.group;
}
}
ngOnInit() {
if (!components[this.config.type]) {
const supportedTypes = Object.keys(components).join(', ');
throw new Error(
`Trying to use an unsupported type (${this.config.type}).
Supported types: ${supportedTypes}`
);
}
const component = this.resolver.resolveComponentFactory<Field>(components[this.config.type]);
this.component = this.container.createComponent(component);
this.renderer.addClass(this.component.location.nativeElement, this.config.widthClass ? this.config.widthClass : 'col-12');
this.component.instance.config = this.config;
this.component.instance.group = this.group;
this.component.instance.lang = this.lang;
if (this.config.type === ModelType.group) {
this.component.instance.innerForm = this.group.get(this.config.name) as FormGroup;
}
}
ngAfterViewInit() {
this.config.label += 'cica';
}
}
用法:
<div [ngClass]="formClass" [formGroup]="form">
<ng-container *ngFor="let field of config;" formField [config]="field" [lang]="lang" [group]="form"> </ng-container>
<ng-content></ng-content>
</div>
我用编译器的 compileModuleAsync
编译了一个 Angular 模块(动态加载模块)并想将模块的一个组件插入视图。
我尝试将组件插入 ViewContainer
,但组件不会自动检测更改。每次更新组件的 属性.
changeDetectorRef.detectChanges
有没有什么方法可以不使用 changeDetectorRef
来实现?
Angular 版本为 10.0.4
.
我加载组件的示例代码:
我加载另一个组件的组件:
<ng-template #dynamic></ng-template>
@ViewChild('dynamic', { read: ViewContainerRef })
dynamic: ViewContainerRef;
constructor(
private compiler: Compiler,
private injector: Injector
) {}
async ngAfterViewInit() {
// Load a module dynamically
const exampleModule = await import('../example/example.module').then(m => m.ExampleModule);
const moduleFactory = await this.compiler.compileModuleAsync(exampleModule);
const moduleRef = moduleFactory.create(this.injector);
const componentFactory = moduleRef.instance.resolveComponent();
const ref = container.createComponent(componentFactory, null, moduleRef.injector);
}
示例模块:
@NgModule({
declarations: [
ExampleComponent
],
imports: [...]
})
export class ExampleModule {
constructor(private componentFactoryResolver: ComponentFactoryResolver) { }
public resolveComponent(): ComponentFactory<ExampleComponent> {
return this.componentFactoryResolver.resolveComponentFactory(ExampleComponent);
}
}
调用detectChanges
的示例:
示例组件
<button (click)="toggle()">Show/Hide</button>
<span *ngIf="show">Show</span>
public toggle() {
this.show = !this.show;
this.cdr.detectChanges(); // <- I want to not use this.
}
我使用此服务创建组件并设置输入:
@Directive({
selector: '[formField]'
})
export class FormFieldDirective implements Field, OnChanges, OnInit, AfterViewInit {
@Input() config: FieldConfig;
@Input() lang: string;
@Input() group: FormGroup;
@Input('class') classList: string = 'col-12';
component: ComponentRef<Field>;
constructor(
private resolver: ComponentFactoryResolver,
private container: ViewContainerRef,
private renderer: Renderer2
) { }
ngOnChanges() {
if (this.component) {
this.component.instance.config = this.config;
this.component.instance.group = this.group;
}
}
ngOnInit() {
if (!components[this.config.type]) {
const supportedTypes = Object.keys(components).join(', ');
throw new Error(
`Trying to use an unsupported type (${this.config.type}).
Supported types: ${supportedTypes}`
);
}
const component = this.resolver.resolveComponentFactory<Field>(components[this.config.type]);
this.component = this.container.createComponent(component);
this.renderer.addClass(this.component.location.nativeElement, this.config.widthClass ? this.config.widthClass : 'col-12');
this.component.instance.config = this.config;
this.component.instance.group = this.group;
this.component.instance.lang = this.lang;
if (this.config.type === ModelType.group) {
this.component.instance.innerForm = this.group.get(this.config.name) as FormGroup;
}
}
ngAfterViewInit() {
this.config.label += 'cica';
}
}
用法:
<div [ngClass]="formClass" [formGroup]="form">
<ng-container *ngFor="let field of config;" formField [config]="field" [lang]="lang" [group]="form"> </ng-container>
<ng-content></ng-content>
</div>