Почему добавление модуля материалов нарушает вставку динамического компонента? - PullRequest
0 голосов
/ 11 ноября 2018

Вот два 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 { });

Поведение

Нет ошибок, но динамический компонент, похоже, не вставлен (по крайней мере, он не виден).

1 Ответ

0 голосов
/ 11 ноября 2018

Причина этого в том, что вы всегда берете первую скомпилированную фабрику из массива.

const factory = factories.componentFactories[0];

пока вам нужно получить фабрику из вашего компонента:

const factory = factories.componentFactories.find(x => x.componentType === component);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...