2017-05-30 7 views
1

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

既知のコンポーネントタイプのリストからページ上に不明な数のコンポーネントをブートストラップしています。ページには同じタイプの複数のコンポーネントが含まれている可能性があります。私はこれらのコンポーネントのそれぞれに異なるセレクタを与える方法を見つけました。(たとえ同じ型であっても)別々にレンダリングできるようになりましたが、それぞれに別のテンプレートを与える必要もあります。 テンプレートは、選択した要素の内部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で他人のコードに基づいている。)

更新:

角度の将来のアップデートでは、私はにできるようになります場合、私は思ったんだけどテンプレートを<ng-content></ng-content>に設定して、選択した要素のinnerHTMLを含めることで、同じ結果が得られます。ブートストラップされたコンポーネントでこれを行うことはできませんが、このissue on Gitに基づいて、私はすぐにそれが可能になると期待しています。

+0

あなたはAOTを使用していますか?もっと正確に言えば、@ angle/compilerを出荷する予定ですか? – yurzui

+0

@yurzui新しくAngularが登場し、まだAOTコンパイルを設定していないのですが、AOTを使用すると結局は理想的だと思います。これは何か変わるでしょうか?私がJITについていれば、これを取り除くことはできますか? –

+0

私はあなたの質問のすべての詳細を理解していないかもしれませんが、あなたは '* ngFor'と' * ngSwitch'構造指令を使ってあなたが望むものを達成できると思います。 を 'ngFor'と組み合わせて、必要なコンポーネントの総数をループします。 を 'ngSwitch'と組み合わせれば、いくつかの変数に応じて既知のコンポーネントセットを自由に選択できます。 –

答えて

0

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

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

を使用しています。

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

詳細については、Here is what you need to know about dynamic components in Angularを参照してください。

+0

説明と役に立つ記事、@ Maximusありがとう。あなたが言っていることは理にかなっています。私は、あなたの解決策を答えとしてマークし、動的テンプレートを持つブートストラップされたコンポーネントのアイデアをクローズする前に、これを達成する別の方法があることを祈っています。 –

+1

もちろん、問題ありません。テンプレートは、とにかくコンパイラによってコンパイルされなければなりません。コンパイル済みのテンプレートを使用している場合は、別の目的に使用できます。 'ng-template'ディレクティブでコンパイルされたテンプレートを得ることができます。しかし、私はこのソリューションがあなたのケースで動作するかどうかはわかりません。 –

関連する問題