2017-08-25 4 views
3

角度2を使用してカスタムタブコンポーネントを開発しました。 これはその使用方法です。角2は、ヘッダーをクリックしたときにタブを動的に読み込みます。

<us-tab-verticle> 
    <vtab-content [tabTitle]="'Basic Information'"><basic-info> </basic-info></vtab-content> 
    <vtab-content [tabTitle]="'VAT Settings'"><vat-settings> </vat-settings></vtab-content> 
    <vtab-content [tabTitle]= "'Economy Settings'"><economy-settings> </economy-settings></vtab-content> 
    <vtab-content [tabTitle]="'Access Profiles'"><access-profiles> </access-profiles></vtab-content> 
</us-tab-verticle> 

問題は、ビューの読み込み時にすべてのタブコンポーネントが読み込まれることです。

マイタブの実装は次のとおりです。

たち-タブverticle.component.html

<div class="v-tabs"> 
    <div class="v-tabs-col v-tabs-left"> 
    <ul class="nav nav-v-tabs flex-column" role="tablist"> 
     <li class="nav-v-item" *ngFor="let tab of tabs" (click)="selectTab(tab)"> 
     <a [class.active]="tab.active" class="nav-v-link" data-toggle="tab" href="#" role="tab">{{tab.title}}</a> 
     </li> 
    </ul> 
    </div> 

    <div class="v-tabs-col v-tabs-fill"> 
    <div class="v-tabs-content"> 
     <div> 
     <ng-content></ng-content> 
     </div> 
    </div> 
    </div> 

たち-タブverticle.component.ts

import { Component, ContentChildren, QueryList, AfterContentInit } from '@angular/core'; 
import { VtabContentComponent } from './vtab-content/vtab-content.component'; 

@Component({ 
    selector: 'us-tab-verticle', 
    templateUrl: './us-tab-verticle.component.html', 
    styleUrls: ['./us-tab-verticle.component.scss'] 
}) 
export class UsTabVerticleComponent implements AfterContentInit { 

    @ContentChildren(VtabContentComponent) tabs: QueryList<VtabContentComponent>; 

    // contentChildren are set 
    ngAfterContentInit() { 
    // get all active tabs 
    const activeTabs = this.tabs.filter((tab) => tab.active); 

    // if there is no active tab set, activate the first 
    if (activeTabs.length === 0) { 
     this.selectTab(this.tabs.first); 
    } 
    } 

    selectTab(tab: VtabContentComponent) { 
    // deactivate all tabs 
    this.tabs.toArray().forEach(tab => tab.active = false); 

    // activate the tab the user has clicked on. 
    tab.active = true; 
    } 

} 

vtab-content.component.html

<div class="tab-content v-tab-content align-content-stretch"> 
    <div [hidden]="!active" class="tab-pane active" role="tabpanel"> 
    <ng-content></ng-content> 
    </div> 
</div> 

vtab-content.component.ts

import { Component, Input } from '@angular/core'; 
import { NgComponentOutlet } from '@angular/common'; 

@Component({ 
    selector: 'vtab-content', 
    templateUrl: './vtab-content.component.html', 
    styleUrls: ['./vtab-content.component.scss'] 
}) 

export class VtabContentComponent { 
    @Input('tabTitle') title: string; 
    @Input() active = false; 
} 

は、私は、各タブのヘッダをクリックすると、各コンポーネントをロードする必要があります。 私はこのような状況にNgComponentOutletを使うことができます。しかし、どのように実装するか考えられなかった。

+0

エンティティの「動的コンポーネント」または「遅延読み込み」を使用 –

+0

この問題については、解決する方法がたくさんあります。[material2 tabs](https://github.com/angular/material2/tree/master/src/lib/tabs)にはソリューションが実装されています。 –

+0

あなたは* ngIf = "active"をtrueのときにコンポーネントを挿入するように[hidden]の代わりに使うことができます – fastAsTortoise

答えて

1

ngComponentOutlet指示文を使用して構造を再現しようとしています。

​​

これは、独自のタブ名、アクティブ状態と誰かがタブを選択したときにロードされるべき身体のコンポーネント参照を知っている非常に単純なコンポーネントは次のとおりです。ここでは、タブコンテナです。

ここ
@Component({ 
    selector: 'tab-content', 
    template: `<p>Hey</p>` 
}) 
export class TabContentComponent {} 

@Component({ 
    selector: 'tab-content-alternative', 
    template: `<p>Hey, this is an alternative content</p>` 
}) 
export class TabContentAlternativeComponent {} 

レンダリングタブとタブコンテナ成分と動的ボディコンポーネントの空のプレースホルダである:

はその後、我々は、動的にロードされるいくつかのボディコンポーネントを作成

@Component({ 
    selector: 'tab-container', 
    template: ` 
    <div class="tab-header"> 
     <div class="tab" *ngFor="let tab of tabs" (click)="selectTab(tab)" [class.active]="tab.active">{{tab.title}}</div> 
    </div> 

    <div class="tab-content"> 
     <ng-container *ngComponentOutlet="content | async"></ng-container> 
    </div> 
    `, 
}) 
export class TabContainerComponent implements AfterContentInit { 
    @ContentChildren(TabComponent) tabs: QueryList<TabComponent>; 

    private contentSbj = new BehaviorSubject<BasicContent>(null); 
    content = this.contentSbj.asObservable(); 

    ngAfterContentInit() { 
    const activeTabs = this.tabs.filter((tab) => tab.active); 
    if (activeTabs.length === 0) { 
     this.selectTab(this.tabs.first); 
    } 
    } 

    selectTab(tab: TabComponent) { 
    this.tabs.toArray().forEach(tab => tab.active = false); 
    tab.active = true; 
    this.contentSbj.next(tab.contentRef); 
    } 
} 

そしてこれは、親コンポーネントで使用できる方法です。

import {TabContentComponent} from './tab/tab-content.component' 
import {TabContentAlternativeComponent} from './tab/tab-content-alternative.component' 
... 

@Component({ 
    selector: 'my-app', 
    template: ` 
    <tab-container> 
     <tab title="Tab 1" [contentRef]="normalContent"></tab> 
     <tab title="Tab 2" [contentRef]="alternativeContent"></tab> 
    </tab-container> 
    `, 
}) 
export class App { 
    normalContent = TabContentComponent; 
    alternativeContent = TabContentAlternativeComponent; 
} 

ここで働いていますPlunkr

+0

あなたのソリューションによれば、 'title-content-mapping'はTabContainerComponentの依存関係です。したがって、これは共通コンポーネントとして使用することはできません。現在の実装では、プロジェクトのどこからでも使用でき、任意の数のタブを作成できます。 –

+0

アイデアは、タブ名とその内容の間にあるマッピングを持つことでした。私はそれを取り除き、コンテンツ・コンポーネントを直接入力パラメーターとしてタブに渡すことができます。 [plunkr](https://embed.plnkr.co/OUYzd445JXETcmZdP4Q9/)を少し更新しました。 – hiper2d

+0

この[plunkr](https://embed.plnkr.co/OvtQQnlF9NtcODjRrDQm/)で私の最終的な解決策を確認してください。これで、タブコンテナコンポーネントには、必要な数のタブ(app.ts参照)を外部依存関係なしに持つことができ、すべてのロジックは内部に隠されます。答えも更新されました。 – hiper2d

2

あなたのソリューションを改善したい場合は、私は*ngIfの使用を提案する多くのソリューションがあります。ただし、*ngIfの状態が変更されるたびに新しいコンポーネントを破棄して作成することに注意してください。

RouterModuleをご覧になることをお勧めします。childrenの属性を使用してください。

少しサンプル:代わりに

// Router.ts 
import { NgModule } from '@angular/core'; 
import { Routes, RouterModule } from '@angular/router'; 

const routes: Routes = [ 
    { 
     path: '', 
     children: [ 
      { path: 'tab1', component: Tab1Component }, 
      { path: 'tab2', component: Tab2Component }, 
     ] 
    }, 
    { path: '**', redirectTo: '' } // modify for default tab? 
]; 


@NgModule({ 
    imports: [RouterModule.forRoot(routes)], 
    exports: [RouterModule] 
}) 
export class AppRoutingModule { } 

export const routedComponents = [Tab1Component, Tab2Component]; 

// AppModule.ts 
imports: [AppRoutingModule] 
declarations: [ 
    routedComponents 
], 

// main.html 
<app-header> 
<us-tab-verticle> 
<div class="tab" [routerLink]="['/tab1']"><a> 
<div class="tab" [routerLink]="['/tab2']"><a> 
<router-outlet></router-outlet> // the content of your tab components will be displayed below 
<app-footer> 

は私の意見では、この方法は、(宣言型ルーティング)を読むためのアプリを作るより簡単に(わからないあなたはそれがすぐに動作させることができますが、私は私のアプリに似たものを使用します)あなたのタブの状態を管理するためのコンポーネントと外部サービスを持っている。

+0

* ngIfは私の実装では動作しません。私はルータの変更オプションで試してみます。 –

関連する問題