Отказ от ответственности: этот вопрос был вдохновлен "" Вот что вам нужно знать о динамических компонентах в Angular"пост на Medium.
Там автор показывает, как можно динамически генерировать как модуль, так и компонент, поместить последний в первый, скомпилировать модуль на лету, получить фабрику компонентов и использовать ее для генерации компонента с помощью ViewContainerRef .
Это просто отлично работает в базовой настройке.
Теперь давайте предположим, что мы хотели бы динамически генерировать компонент, но на этот раз с шаблоном, который использует async pipe.
Далее нам нужно, чтобы эта штука работала в производственной среде, что означает две вещи:
Поскольку угловой компилятор недоступен, мы можем предоставить экземпляр jit-компилятора для токена компилятора в корневом модуле приложения.
app.module.ts:
import { BrowserModule } from '@angular/platform-browser';
import {Compiler, NgModule} from '@angular/core';
import {AppComponent } from './app.component';
import {JitCompilerFactory} from '@angular/platform-browser-dynamic';
export function jitCompiler() {
/*
* Cast JitCompilerFactory to any because
* jit compiler factory constructor does not
* accept any arguments according to the @angular/platform-browser-dynamic/src/compiler_factory.d.ts
*/
const klass = (JitCompilerFactory as any);
return new klass([]).createCompiler([
{
useJit: true
}
]);
}
@NgModule({
declarations: [
AppComponent
],
providers: [
{
provide: Compiler,
useFactory: jitCompiler
}
],
imports: [
BrowserModule
],
bootstrap: [AppComponent]
})
export class AppModule { }
app.component.ts
import {
AfterViewInit,
ChangeDetectionStrategy,
Compiler,
Component,
NgModule,
ViewContainerRef
} from '@angular/core';
import {Subject} from 'rxjs';
import {CommonModule} from '@angular/common';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class AppComponent implements AfterViewInit {
constructor(
private readonly compiler: Compiler,
private readonly vcr: ViewContainerRef
) {}
ngAfterViewInit() {
const template = '<span>Hello, {{text$ }}</span>';
const cmp = Component({
template
})(class DynamicComponent {
text$: Subject<string>;
});
const module = NgModule({
declarations: [cmp],
imports: [CommonModule],
providers: []
})(class DynamicModule {});
this.compiler.compileModuleAndAllComponentsAsync(module)
.then(compiledModule => {
const dynamicComponent = this.vcr.createComponent(compiledModule.componentFactories[0]);
const sub = new Subject();
sub.next('World!');
dynamicComponent.instance.text$ = sub;
// Just to simulate some server updates
setTimeout(() => dynamicComponent.instance.text$.next('Another'), 3e3);
});
}
}
Если мы запустим это и откроем DevTools, мы увидим следующую ошибку:
ОШИБКА Ошибка: неожиданное значение 'function () {}' импортировано модулем
'Функция () {}'. Пожалуйста, добавьте аннотацию @NgModule.
Проблема возникает только в режиме разработки.
Угловая версия 7.2.0.
Отсюда вопрос - что нужно сделать, чтобы он работал в режиме AOT?