web-dev-qa-db-ja.com

Angular 4つのコンポーネントのテンプレートを動的に変更する

Angular 4.1を使用して、モジュールがレンダリングされる前にモジュールタイプのテンプレートを動的に変更しようとしています。これは可能ですか?

ページ上のコンポーネントの不明な数(既知のコンポーネントタイプのリストから)をブートストラップしており、ページには同じタイプの複数のコンポーネントが含まれている場合があります。これらのコンポーネントのそれぞれに異なるセレクターを与えて別々にレンダリングできるようにする方法を見つけました(同じタイプであっても)が、それぞれに異なるテンプレートを与える必要もあります。 テンプレートは、選択した要素の内部HTMLである必要があります。

コードは次のとおりです。

import { Component, NgModule, Inject, ApplicationRef, ComponentFactoryResolver, OpaqueToken, Type } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { MyNavComponent } from './MyNav.component';
import { MyRotatorComponent } from './MyRotator.component';
import { MySignUpComponent } from './MySignUp.component';

export const BOOTSTRAP_COMPONENTS_TOKEN = new OpaqueToken('bootstrap_components');

@NgModule({
    imports: [BrowserModule],
    declarations: [
        MyNavComponent,
        MyRotatorComponent,
        MySignUpComponent
    ],
    entryComponents: [
        MyNavComponent,
        MyRotatorComponent,
        MySignUpComponent
    ],
    providers: [
        {
            provide: BOOTSTRAP_COMPONENTS_TOKEN,
            useValue: [
                { type: MyNavComponent },
                { type: MyRotatorComponent },
                { type: MySignUpComponent }
            ]
        },
    ]
})
export class AppModule {
    constructor(
        private resolver: ComponentFactoryResolver,
        @Inject(BOOTSTRAP_COMPONENTS_TOKEN) private components: [Component],
    ) { }
    ngDoBootstrap(appRef: ApplicationRef) {
        console.log(this.components);
        this.components.forEach((componentDef: { type: Type<any>, selector: string }) => {
            const factory = this.resolver.resolveComponentFactory(componentDef.type);
            let selector = factory.selector;
            let nodes = document.querySelectorAll(selector);
            for (let i = 0; i < nodes.length; i++) {
                let node = nodes[i];
                (<any>factory).factory.selector = node;

                //The next line doesn't work... how can I dynamically set the template?
                (<any>factory).factory.template = node.innerHTML;

                appRef.bootstrap(factory);
            }
        });
    }
}

上記のコードの終わり近くで述べたように、(<any>factory).factory.template = node.innerHTML;は機能しません。また、タイプのメタデータを変更しようとしましたが、それも機能しません。

私が達成しようとしていることは別の手段で可能ですか?そうでない場合、これは機能要求として提出する価値がありますか?

(注:上記のコードは https://github.com/angular/angular/issues/7136 にある他のコードに一部基づいています。)

更新:

Angularの将来の更新で、選択した要素のinnerHTMLを含めるためにテンプレートを<ng-content></ng-content>に設定することで同じ結果を達成できるかどうか疑問に思っています。ブートストラップされたコンポーネントでは現在は不可能ですが、これに基づいて Gitの問題 になります。

8
Kirk Grover

コンポーネントファクトリは、作成後に設定することはできません。 Angularコンパイラは、ファクトリを生成するときにテンプレートを解析し、各コンポーネントのビュークラスを作成します。コンポーネントファクトリとそのビュークラスを作成した後、変更できません。この例ではComponentFactoryResolver

const factory = this.resolver.resolveComponentFactory(componentDef.type);

すでに作成されたファクトリを返します。

唯一のオプションは、コンパイラがファクトリを生成する前にテンプレートを変更することです。しかし、私はそれが可能だとは思わない。おそらく、コンポーネントの動的な生成を検討する必要があります。

詳しくは Angularの動的コンポーネントについて知っておくべきこと をお読みください。

5
Maxim Koretskyi