Angular 2.3.1およびng-bootstrap 1.0.0-alpha.18を使用します。テンプレート内からではなく、コンポーネントからIDに基づいてプログラムでタブを選択しようとしています。目標はURLからパラメーターを取得し、それを使用してngOnInitのタブを選択します
テンプレート
<section id="policy-terms">
<ngb-tabset>
<ngb-tab title="Terms and Privacy" id="terms">
<template ngbTabContent>
<div class="container page-content">
</div>
</template>
</ngb-tab>
<ngb-tab title="Company Policy" id="policy">
<template ngbTabContent>
<div class="container page-content">
</div>
</template>
</ngb-tab>
</ngb-tabset>
</section>
そしてコンポーネントコード:
import { Component, OnInit } from '@angular/core';
import { NgbTabset } from '@ng-bootstrap/ng-bootstrap';
@Component({
selector: 'app-policy-terms',
templateUrl: './policy-terms.component.html',
styleUrls: ['./policy-terms.component.scss'],
providers: [
NgbTabset
]
})
export class PolicyTermsComponent implements OnInit {
constructor(
public tabset: NgbTabset
) { }
ngOnInit() {
this.tabset.select('policy');
}
}
これは単にエラーを生成します:
この方法にアクセスするにはどうすればよいですか?
AngularJs 1.xでは、ui-routerを使用して名前を設定するのは簡単でした。 Angular 2とNg-Bootstrapではそれほど明白ではありません。逆に、必要なものはネイティブAngular 2ライブラリで利用可能です。
export const appRoutes: Routes =
[
{ path: 'prospect/:prospectid/details', component: ProspectTabsView, data:{name:'details'} },
{ path: 'prospect/:prospectid/appointments', component: ProspectTabsView, data:{name:'appointments'} },
{ path: 'prospect/:prospectid/followups', component: ProspectTabsView, data:{name:'followups'} },
{ path: 'prospect/:prospectid/contacts', component: ProspectTabsView, data:{name:'contacts'} },
{ path: '', component: DashboardView },
{ path: '**', redirectTo: '', pathMatch: 'full'}
];
[data]属性という1つの例外を除いて、構成は簡単です。 name
というキーがあります。これはルートの名前です。データバッグとしてのデータ属性と考えてください。ルート名だけでなく、追加することもできます。
<ngb-tabset #tabs>
<ngb-tab id="details">
<ng-template ngbTabTitle>
<a [routerLink]="['/prospect', prospectId, 'details']">Details</a>
</ng-template>
<ng-template ngbTabContent>
</ng-template>
</ngb-tab>
<ngb-tab id="contacts">
<ng-template ngbTabTitle>
<a [routerLink]="['/prospect',prospectId,'contacts']">Contacts</a>
</ng-template>
<ng-template ngbTabContent>
</ng-template>
</ngb-tab>
<ngb-tab id="appointments">
<ng-template ngbTabTitle>
<a [routerLink]="['/prospect', prospectId, 'appointments']">Appointments</a>
</ng-template>
<ng-template ngbTabContent>
</ng-template>
</ngb-tab>
<ngb-tab id="followups">
<ng-template ngbTabTitle>
<a [routerLink]="['/prospect', prospectId, 'followups']">Follow Ups</a>
</ng-template>
<ng-template ngbTabContent>
</ng-template>
</ngb-tab>
</ngb-tabset>
上記のタブマークアップには魔法のようなものはありません。注意したいことがいくつかあります。最初はngb-tabset
要素にあり、変数#tab
を宣言しました。コンポーネントの後半で#tab
を使用します。次に、各nbg-tab
には、ルート構成で定義した名前(つまり、data:{name:'followups'}
)と一致するid
セットがあります。
import {
AfterViewChecked, Component, OnInit,
ViewChild
} from '@angular/core';
import '../../assets/css/styles.css';
import {ActivatedRoute} from "@angular/router";
import {NgbTabset} from "@ng-bootstrap/ng-bootstrap";
@Component({
templateUrl: './tabs.view.html'
})
export class ProspectTabsView implements OnInit, AfterViewChecked{
prospectId: number;
selectedTab:string;
@ViewChild('tabs')
private tabs:NgbTabset;
constructor(private route: ActivatedRoute) {
this.route.data.subscribe(d=>{
this.selectedTab = d.name;
});
}
ngOnInit(): void {
this.route.params.subscribe(
params => {
this.prospectId = +params['prospectid'];
}
);
}
ngAfterViewChecked(): void {
if(this.tabs) {
this.tabs.select(this.selectedTab);
}
}
}
この演習の最も難しい部分は、実行順序を正しくすることでした。正しくない場合、コレクションまたはプロパティは、操作する前に初期化されません。クラスの先頭から始めて、下に進みます。
まず、変数があります。 prospectId
はデータの主キー、selectedTab
は現在選択されているタブの名前、そして最後にtabs
変数があります。 tabs
は、#tab
要素に追加した属性(ngb-tabset
)への参照です。
次はconstructor
です。ドキュメントでは明らかではありませんが、data
はObservable<data>
です。値をキャプチャするために、ルートからdata
プロパティにサブスクライブしています。
constuctor
に続くのはngOnInit
です。これはタブにとって重要ではありませんが、タブのルーティングで使用するprospectIdをキャプチャします。ルートに動的データがない場合、これは必要ありません。
最後に、ngAfterViewChecked
があります。 tabs
をルーティングするには、これが最も重要です。ここでは、マークアップからキャプチャしたtabs
変数を使用し、選択したタブを変更するために、選択したタブ名をtabs
に渡します。
これを適切に機能させるには、ngb-tabset
のtabChange
イベントにフックするために追加する必要がありました。
<ngb-tabset [activeId]="selectedTab" #tabs (tabChange)="onTabChange($event)">
また、onTabChange関数でルートをハードコーディングする必要がありました。
onTabChange($event: NgbTabChangeEvent) {
let routes = {
details: `/prospect/${this.prospectId}/details`,
appointments: `/prospect/${this.prospectId}/appointments`,
followups: `/prospect/${this.prospectId}/followups`,
notes: `/prospect/${this.prospectId}/notes`,
dials: `/prospect/${this.prospectId}/dials`,
};
this.router.navigateByUrl(routes[$event.nextId]);
}
これは、タブが初期化される前にタブでselectを呼び出しているために発生しています。 NgTabsetは、ビューが初期化された後に初期化されます。ブール値を使用して、selectを呼び出す前に初期化されているかどうかを確認しました。
tabsInitialized: boolean = false;
@ViewChild('tabs') public tabs:NgbTabset;
ngAfterViewInit() {
this.tabsInitialized = true;
}
ngOnChanges(){
if(this.tabsInitialized){
this.tabs.select('dashboard');
}
}
...
誰かがテンプレートからそれをしたい場合、最良のアプローチは次のとおりです。
<ngb-tabset #tabRef="ngbTabset">
<ngb-tab title="Tab-1" id="tab1">
<ng-template ngbTabContent>
<p> Tab 1 Content</p>
</ng-template>
</ngb-tab>
<ngb-tab title="Tab-2" id="tab2">
<ng-template ngbTabContent>
<p> Tab 2 Content</p>
</ng-template>
</ngb-tab>
</ngb-tabset>
<div>
<button class="btn" (click)="tabRef.select('tab2')">Select tab with id tab2</button>
</div>
要素に参照を置きます
<ngb-tabset #tabs>
ViewChildを使用してタブを制御する
export class PolicyTermsComponent implements OnInit {
private tabs:NgbTabset;
@ViewChild('tabs') public set _tabs(tabs: NgbTabset)
{
if(!tabs) return;
this.tabs = _tabs;
this.tabs.select('policy');
}
}
ページがタブコンポーネントを適切に作成し、参照および使用できるように、selectの実行をセットに移動しました。
あなたが持っている問題は、イベントループの間違った部分でコードを実行しているためです。 await/async
を使用して、アクティブなタブの設定を他のマイクロタスクのイベントループの後半にプッシュできます。
// ... other stuff
{ path: ":id/:tabName", component: ViewTabsComponent },
// ... other stuff
<ngb-tabset #myTabs>
<ngb-tab title="Terms and Privacy" id="terms">
<template ngbTabContent>
<p>content</p>
</template>
</ngb-tab>
<ngb-tab title="Company Policy" id="policy">
<template ngbTabContent>
<p>other content<\p>
</template>
</ngb-tab>
</ngb-tabset>
@ViewChild("myTabs", { static: true, read: NgbTabset }) myTabs: NgbTabset;
async ngOnInit() {
const params = await this.route.paramMap
.pipe(
map((params: ParamMap) => ({ tabName: params.get("tabName") })),
take(1) // <-- force to complete
).toPromise();
this.myTabs.select(`${params.tabName}`);
}
これはで働いています