2017-09-08 30 views
0

更新:角度4でラッパーコンポーネントを実装する正しい方法は?

正しい質問はおそらくです:「どのように私はng-containerの私の独自のバージョンを実装しないので、私は使用することができ、」<ng-container my-directive ...>...</ng-container>「の代わりに」<my-component ...>...</my-component>」を

私は角4で新しいアプリを開発しています私はラッパーコンポーネントを使ってアプリケーション全体を構築したいので、実際のコンポーネントを必要に応じて交換することができます。これは簡単なコントロールでは簡単に動作しますが、複雑なコントロールでは個別のコンポーネントに分割したくありません。要件はかなり安定しています:表示/非表示のラベルとコンテンツパネルのタブのリスト 私たちは、このようないくつかの他のコンポーネントがあり

<ngb-tabset> 
    <ngb-tab title="Tab 1"> 
    <ng-template ngbTabContent>...</ng-template> 
    </ngb-tab> 
    ... 
<ngb-tabset> 

:NG-ブートストラップは、このようなものを使用することができ

<div class="my-tab-group"> 
    <ul> 
    <li>Tab 1</li> 
    ... 
    </ul> 
    <div class="my-tab" title="Tab 1">...</div> 
    ... 
</div> 

代わりのこの時点では、特定の実装に私のアプリを抱き合わせを私は自分を定義したいです

<my-tabs-control> 
    <my-tab-control title="Tab 1">...</my-tab-control> 
    ... 
<my-tabs-control> 

次に、タブが動作する方法を変更する必要がある場合は、1か所で発生します。しかし、ラッパーコンポーネントを使用すると、HTMLは汚染され、ホスト要素タグは所望のタグとインターレースされます。

<my-tabs-control> 
    <div class="my-tab-group"> 
    <ul> 
     <li>Tab 1</li> 
     ... 
    </ul> 
    <my-tab-control title="Tab 1"> 
     <div class="my-tab" title="Tab 1">...</div> 
    </my-tab-control>   
    ... 
    </div> 
<my-tabs-control> 

私の推測では、これは多くの人々が、角度成分で、ホスト要素削除/アンラップする方法を尋ねる理由である - を行うには、これは本当に簡単になるだろう。

いつもの答えは例えば、代わりに属性セレクタを使用することです:

Remove the angular2 component's selector tag

How to remove/replace the angular2 component's selector tag from HTML

しかし、これは我々が明らかに破壊し、使用部位、でタグ構造を知っておく必要があることを意味素敵な名前のラッパータグを使用することの全体的なポイント。

最後に、私はこれをどのように行うべきですか?パフォーマンス上の理由によりおそらく可能ではありませんか?私はRenderer2を見て始めましたが、私が望むことを実行する明白な方法を見つけていないので、非角形のDOMハックを避けたいと思います。

+0

あなたはNG-コンテンツを使用して「トランスクルー」を使用するようになっています https://scotch.io/tutorials/angular-2-transclusion-using- ng-content公式の角書類ではこれが欠けているようです: https://github.com/angular/angular.io/issues/3099 – marvini

+0

私はすでにコンテンツを投影するためにたくさんのコンテンツを使用していますが、これは問題を解決していませんコンポーネント自体によって作成されたラッパー/コンテナタグの私たちは、コンポーネントの代わりにディレクティブを使ってng-containerを使いたいものを並べ替えることができますが、それは面倒です。おそらく、デフォルトの属性セレクタの代わりに要素セレクタを使用してディレクティブを使用して、おそらくRenderer2 /コードを使用してコンテンツをレンダリングすることができます。私が本当に望むのは、単に「このコンポーネントの内容をラッパー/コンテナ/ホスト要素なしでレンダリングする」というスイッチです。悲しいことに、それは不可能だと思います。 – Etherman

答えて

1

私は、私が気に入っていたほどエレガントではありませんが、機能するソリューションを持っています。私は、「ホスト要素を取り除く」というオプションを好むでしょう。

ng-bootstrapプロジェクトでタブがどのように実装されているかを確認するだけで、この解決策を導き出しました:https://github.com/ng-bootstrap/ng-bootstrap

解決策は、@ Containerをメインコンテナとして使用し、すべての内部子コンポーネントに@Directivesを使用することです。通常は、他の要素へのアドオンとしてディレクティブを使用しますが、ここではディレクティブを実際の要素として使用します。これは、自身のコンテンツをレンダリングしたり、独自のホストコンテナを作成したりしないコンポーネントのように機能するようです。その代わりに、ホストコンポーネントはディレクティブの内容をどのように処理するかを決定することができます。特別な条件はng-templatesを使用することです - ng-templatesを使用せずにディレクティブコンテンツを直接投影する方法はわかりません。ここで

は、私は私のラッパーコンポーネントを使用して、タブコンテナをマークアップする方法である:ここでは

<my-tab-container> 
    <my-tab title="Tab 1"> 
    <ng-template myTabContent> 
     This is panel 1! 
    </ng-template> 
    </my-tab> 
    <my-tab title="Tab 2"> 
    <ng-template myTabContent> 
     This is panel 2! 
    </ng-template> 
    </my-tab> 
    <my-tab title="Tab 3"> 
    <ng-template myTabContent> 
     This is panel 3! 
    </ng-template> 
    </my-tab> 
</my-tab-container> 

は、個々のタブやタブのコンテンツのための2つのディレクティブが含まれて私のタブのラッパーコンポーネントの最小限の実装です。

import { Component, OnInit, Directive, ContentChildren, QueryList, Input, TemplateRef, ContentChild } from '@angular/core'; 

@Directive({ selector: 'ng-template[myTabContent]' }) 
export class TabContentDirective { 
    constructor(public templateRef: TemplateRef<any>) { } 
} 

@Directive({ selector: 'my-tab' }) 
export class TabDirective { 
    @Input() 
    title: string; 
    @ContentChild(TabContentDirective) 
    content: TabContentDirective; 
    public getTemplateRef() { 
    return this.content.templateRef; 
    } 
} 

@Component({ 
    selector: 'my-tab-container', 
    templateUrl: './tab-container.component.html', 
    styleUrls: ['./tab-container.component.scss'] 
}) 
export class TabContainerComponent implements OnInit { 
    @ContentChildren(TabDirective) 
    tabs: QueryList<TabDirective>; 
    constructor() { } 
    ngOnInit() { 
    } 
} 

タブコンテナコンポーネントのHTMLテンプレートを切り替えることで、さまざまな種類のタブをレンダリングできます。

ブートストラップ用:

<ngb-tabset> 
    <ngb-tab *ngFor="let tab of tabs"> 
    <ng-template ngbTabTitle>{{tab.title}}</ng-template> 
    <ng-template ngbTabContent> 
     <ng-template [ngTemplateOutlet]="tab.content.templateRef"></ng-template> 
    </ng-template> 
    </ngb-tab> 
</ngb-tabset> 

<md-tab-group> 
    <md-tab *ngFor="let tab of tabs" label="{{tab.title}}"> 
    <ng-template [ngTemplateOutlet]="tab.content.templateRef"></ng-template> 
    </md-tab> 
</md-tab-group> 

またはいくつかの他のカスタムの事(jQueryUIスタイル):アンギュラMaterial2ため

<ul> 
    <li *ngFor="let tab of tabs">{{tab.title}}</li> 
</ul> 
<div *ngFor="let tab of tabs"> 
    <ng-template [ngTemplateOutlet]="tab.content.templateRef"></ng-template> 
</div> 

それは私たちが今、すべての上のUIにタブ(およびコントロールの他のすべてのタイプ)を追加することを続けていくことができることを意味します私たちのプロジェクトに最適なコンポーネントを選んだら心配する必要はありません。必要に応じて後で簡単に切り替えることができます。

(うまくいけば、これはパフォーマンスの問題を紹介しません!)

関連する問題