Вот два MCVE на StackBlitz, использующих динамическое создание компонентов. Я хотел бы понять, почему:
- Это работает.
- Но это не работает, только после импорта модуля материалов (
MatButtonModule
) в динамически создаваемый модуль.
У кого-нибудь есть идея?
Пример, который работает
app.component.ts
import { Component, ChangeDetectionStrategy, OnDestroy, ChangeDetectorRef, ViewChild, ViewContainerRef, Input, Compiler, Injector, NgModuleRef, SimpleChanges, NgModule, ComponentFactoryResolver, ReflectiveInjector } from '@angular/core';
import { CommonModule } from '@angular/common';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { HttpClientModule } from '@angular/common/http';
import { MatButtonModule } from '@angular/material';
@Component({
selector: 'my-app',
template: `
<ng-container
#viewContainerRef
></ng-container>
`,
})
export class AppComponent {
@ViewChild('viewContainerRef', { read: ViewContainerRef }) viewContainerRef: ViewContainerRef;
constructor(
private compiler: Compiler,
private injector: Injector,
private ngModuleRef: NgModuleRef<any>,
private changeDetectorRef: ChangeDetectorRef,
) {
}
ngOnInit() {
const template = `
<button
mat-button
[innerHTML]="'Click me!'"
>
</button>
`
this.viewContainerRef.clear();
const component = Component({
changeDetection: ChangeDetectionStrategy.OnPush,
template
})(class { });
const ngModule = NgModule({
imports: [
CommonModule,
BrowserModule,
BrowserAnimationsModule,
HttpClientModule,
],
entryComponents: [component],
declarations: [component]
})(class { });
this.compiler.compileModuleAndAllComponentsAsync(ngModule).then((factories) => {
const factory = factories.componentFactories[0];
const componentRef = this.viewContainerRef.createComponent(
factory,
this.viewContainerRef.length,
this.injector,
[],
this.ngModuleRef
);
this.changeDetectorRef.detectChanges();
});
}
}
app.module.ts
import { NgModule, CompilerFactory, COMPILER_OPTIONS, Compiler } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { JitCompilerFactory } from '@angular/platform-browser-dynamic';
import { AppComponent } from './app.component';
export function createCompiler(compilerFactory: CompilerFactory) {
return compilerFactory.createCompiler();
}
@NgModule({
imports: [ BrowserModule, FormsModule ],
declarations: [ AppComponent ],
bootstrap: [ AppComponent ],
providers: [
{ provide: COMPILER_OPTIONS, useValue: {}, multi: true },
{ provide: CompilerFactory, useClass: JitCompilerFactory, deps: [COMPILER_OPTIONS] },
{ provide: Compiler, useFactory: createCompiler, deps: [CompilerFactory] },
],
})
export class AppModule { }
Пример, который не работает
Добавляет MatButtonModule
в импорт динамического модуля:
app.component.ts
const ngModule = NgModule({
imports: [
CommonModule,
BrowserModule,
BrowserAnimationsModule,
HttpClientModule,
MatButtonModule,
],
entryComponents: [component],
declarations: [component]
})(class { });
Поведение
Нет ошибок, но динамический компонент, похоже, не вставлен (по крайней мере, он не виден).