2017-08-25 67 views
3

我已經開發了一個使用Angular 2的自定義標籤組件,它工作正常。 這是它的用法。Angular 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選項卡](https://github.com/angular/material2/tree/master/src/lib/tabs),該解決方案已實施。 –

+0

你可以使用* ngIf =「active」而不是[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/)。現在,tab-container組件可以具有所需的多個選項卡(請參閱app.ts),而不需要任何外部依賴關係,並且所有邏輯都隱藏在內部。也更新了答案。 – hiper2d

2

有很多的解決方案,如果你想改善你的解決方案,我建議使用*ngIf。但請注意,每當*ngIf狀態更改時,您都會銷燬並創建一個新組件。

我建議你看看RouterModule與使用children attribue。

一個小例子:(不知道你可以把它馬上工作,但我在我的應用程序中使用類似的東西)

// 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不適用於我的實施。我會嘗試使用路由器更改選項。 –