web-dev-qa-db-ja.com

Angular 4を使用して、単一のコンポーネント内に動的テンプレートをロードします

私の要件は、各htmlテンプレートが少なくとも20のコントロールを持ち、いくつかの条件に基づいて特定のテンプレートをロードする、2つ以上のhtmlテンプレートを持つコンポーネントを構築することです。

注:テンプレートの値の取得および保存を駆動するための入力およびロジックとしての単一のtsファイルと同じであるtemplateTypeに基づいてコントロールが異なるため、3つの異なるテンプレートを選択しました。したがって、3つのテンプレートと1つのtsファイルを単一のコンポーネントとして使用することにしました。

//sub.component.ts
@Component({
     selector: 'sub-component',
     template: `
               <div [ngSwitch]="templateType">
                    <ng-template *ngSwitchCase="'1'"> ${require('./sub1.component.html')} </template>
                    <ng-template *ngSwitchCase="'2'"> ${require('./sub2.component.html')} </template>
                    <ng-template *ngSwitchCase="'3'"> ${require('./sub3.component.html')} </template>
                    <ng-template ngSwitchDefault> ${require('./sub1.component.html')} </template>
</div>
    `
})

動作を達成するための簡単な解決策として表示されますが、コンパイルが失敗して必要を見つけることができないため、上記の代替案を試しました。 AngularJSには、テンプレートを取り込むng-Includeがありますが、ng-templateは外部htmlコンテンツの読み込みをサポートしていないようです。

これに似た多くのクエリが表示されるため、これを重複としてマークしないでください。ただし、ほとんどのソリューションは非推奨またはAngular 4.に適用されません。

7
BVS

私はこの質問が古いことを知っていますが、うまくいけば、これは同様のことをしようとしている人々を助けるでしょう。

あなたが望むことについての残念なことは、それを行う最も簡単な方法は、各テンプレートを独自のコンポーネントにすることです。それ以外の場合は、HTMLを注入してサニタイズする必要があります。非サニタイズされたHTMLを挿入するセキュリティリスクのため、ng-includeおよび同様の機能を削除しました。モジュール内のすべての追加コンポーネントを具体的にインポートして宣言する必要がなければ、P.I.T.Aほどではありませんが、悲しいかな...

TemplateRefを取得する単純なディレクティブを作成し、それらのディレクティブを含むページ上の要素をクエリし、そこからテンプレートrefを取得して、他の場所に挿入できます。これにより、少なくともすべてのテンプレートを別のファイルに保存できます。通常、3つまたは4つのテンプレートを個別のコンポーネントに配置し、それらをレンダリングするコンポーネントに含めます。その方法を説明します。

テンプレート参照を取得するためのディレクティブ

import { Directive, TemplateRef, Input } from '@angular/core';

@Directive({
 selector: 'get-template',
})
export class GetTemplateDirective {
  @Input() name: string;
  constructor(public template: TemplateRef<any>) {  }
}

次に、テンプレートについて、それらすべてを備えた超シンプルなコンポーネントを作成します

@Component({
  selector: 'sub-component-templates',
  template: `

<ng-template get-template [name]="tpl1">
  Put Whatever here, including other components if you please
</ng-template> 

<ng-template get-template [name]="tpl2">
  Different template here
</ng-template> 

 ... and so on and so on...
`
})
export class Templates { }

関連するすべての新しいコンポーネントをモジュールにインポートし、テンプレートをレンダリングするメインコンポーネント内にそれらを含めます

私は通常ng-contentでそれを行うので、親コンポーネントでは、このコンポーネントがテンプレート用に別のコンポーネントを参照していることが明確になります。

たとえば、親で..

<sub-component>
    <sub-component-templates></sub-component-templates>
</sub-component>

次に、サブコンポーネントで

 import { Component, ViewChild, ContentChildren, QueryList } from '@angular/core';
import { GetTemplateDirective } from 'wherever';

@Component({
selector: 'sub-component',
template: `

<ng-content></ng-content>

 <div #templateRenderer></div>
`
})
export class SubComponent {

@ViewChild('templateRenderer',{read:ViewContainerRef}) anchor: ViewContainerRef;
@ContentChildren(GetTemplateDirective) templates: QueryList<GetTemplateDirective>;

ngAfterContentInit()  {

  ... at this stage, you will have access to all the included templates with that directive on them. You can perform your logic to choose which one you want. Once you have selected the proper one, you can embed it like so ... 
 let desiredTemplateName = 'whatever';

     for (let t of this.templates.toArray()) {
       if(t.name === desiredTemplateName) {
          this.anchor.createEmbeddedView(t.template);
          break;        
       } 
     }  
   }

}

これは、あなたがやろうとしていることにとってとてつもなく複雑であることがわかります。それらを個別のコンポーネントとして作成し、ngSwitchCaseを使用して適切なコンポーネントを選択する方が簡単です。上記の方法の利点は、本当に必要な場所にテンプレートを保持できることです。また、同じ外部コンポーネントに100を含めることができます(実際には、テンプレートで装飾された最低限のコンポーネントにすぎません)。あなたが望んでいた、またはサービス、または何でもそれらを移動します。

コンパイラの使用方法の実例については、こちらを参照してください- https://plnkr.co/edit/fdP9Oc?p=info

まだかなり複雑です...

テンプレートをクラスのプロパティとして保存する場合、必要に応じて後で変更できます。テンプレート参照インポートを追加するだけです...

 import { Component, ViewChild, ContentChildren, QueryList, TemplateRef } from '@angular/core';

そして、プロパティを作成します

 template: TemplateRef<any>;

その後、クエリリストのいずれかで切り替えて、ビューコンテナのメソッドを使用して、embeddedviewを再度作成できます。

Angular 2/4は特定のものをより簡単にしました...そして特定のものをより簡単にしました。しかし、この場合、セキュリティの名の下にあると思います。

11
diopside

私は実際に私たちが話しているときにこれを理解しようとしていますが、上記の答えに出会ったとき、私はしようとしているというアイデアを与えました。うまくいけば、私はそれでいくらか成功を収め、この答えをより具体的なもので更新できるようになります。

私は常にアンケートに取り組んでおり、言葉による回答を含む多肢選択問題、「1〜10のスケール」タイプのメカニズムを使用した多肢選択質問、テキスト回答が必要な質問があります。

componentを作成し、データが渡されるクラスの変数に接続するngIf条件で各テンプレートをラップすると、テンプレートがトリガーされます。

したがって、データは次のようになります

Questions:[{
    question:'blahblahblah',
    answers: [..array of answers..],
    template: 'a'
    },
    {
    question: 'yaddayaddayadda',
    answers: [],
    template: 'b'
    },
    {
    etc.
    }
    ]

次に、コンポーネントクラスでは、このようなものを持つことができます

@Component ({
    selector: 'question-component',
    templateUrl: './template.html'
})

export class QuestionComponent {

    @input() data: yourDataType;

    constructor() {} 

}

このコンポーネントのテンプレートには次のようなものがあります

<div *ngIf="data.template === a">
    <!-- code for template with binding and everything -->
</div>

<div *ngIf="data.template === b">
    <!-- code -->
</div>

<!-- etc. etc. etc. -->

次に、メインコンポーネントのテンプレートで次のようなことができます

<div *ngFor = "question of Questions">
    <question-component [data]="question"></question-component>
</div>

これはすべて頭のてっぺんから外れているので、いくつかのことを見逃しているかもしれませんが、その間に突進を始めるものとしてここにいることは価値があると感じています。ニーズに合わせて機能するかどうかを確認します。

0
Optiq