为什么添加 Material 模块会破坏动态组件插入?

Why adding a Material Module breaks the dynamic component insertion?

这是 StackBlitz 上使用动态组件创建的两个 MCVE。我想明白为什么:

有人知道吗?

有效的示例

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 { });

行为

没有报错,但是动态组件好像没有插入(至少是看不见的)

原因是你总是从数组中获取第一个编译工厂。

const factory = factories.componentFactories[0];

当您需要从您的组件获取工厂时:

const factory = factories.componentFactories.find(x => x.componentType === component);