Angular MaterialでRouterと連携するTabを実装
Angular Materialで次のようなTabsを使ったUIを実装する方法です。
今回実現したのは👇こんな感じの動きです。
動きを見て分かるように、URLの変化に合わせてアクティブなtabと内容が変更されます。
以下のStackOverflowにあるサンプルコードを参考に、routerとmd-tab-nav-barの連携を行いましたが、これだけでは、URLが直接変更された場合に対応できていなかったため、別途修正を加えました。
環境
$ ng --version @angular/cli: 1.3.0 node: 8.1.3 os: darwin x64
"@angular/material": "^2.0.0-beta.10", "@angular/router": "^4.2.4",
構成
今回作成したプロジェクトの構成は👇
./app ├── ./app/app-routing.module.ts ├── ./app/app.component.css ├── ./app/app.component.html ├── ./app/app.component.ts ├── ./app/app.module.ts └── ./app/container ├── ./app/container/newest │ ├── ./app/container/newest/newest.component.css │ ├── ./app/container/newest/newest.component.html │ └── ./app/container/newest/newest.component.ts ├── ./app/container/random │ ├── ./app/container/random/random.component.css │ ├── ./app/container/random/random.component.html │ └── ./app/container/random/random.component.ts └── ./app/container/search ├── ./app/container/search/search.component.css ├── ./app/container/search/search.component.html └── ./app/container/search/search.component.ts
app.componentに<router-outlet>を配置して、Tabの内容はそれぞれsearch、newest、randomを切り替えます。
サンプル
まずは、routingの設定 (app-routing.module.ts)
import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; import { SearchComponent } from './container/search/search.component'; import { NewestComponent } from './container/newest/newest.component'; import { RandomComponent } from './container/random/random.component'; const routes: Routes = [ { path: '', redirectTo: 'search', pathMatch: 'full' }, { path: 'search', component: SearchComponent }, { path: 'newest', component: NewestComponent }, { path: 'random', component: RandomComponent } ]; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule] }) export class AppRoutingModule { }
メインのcomponent (app.component.html, app.component.ts)
<app-header></app-header> <div class="main-area-container"> <nav md-tab-nav-bar> <a md-tab-link *ngFor="let routeLink of routeLinks; let i = index" [routerLink]="routeLink.link" [active]="activeLinkIndex === i" (click)="activeLinkIndex = i"> {{routeLink.label}} </a> </nav> <router-outlet></router-outlet> </div> <app-footer></app-footer>
import { Component } from '@angular/core'; import { Router, ActivatedRoute, NavigationEnd } from '@angular/router'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { title = 'app'; private routeLinks: any[]; private activeLinkIndex = 0; private currentRoute = ''; constructor( private router: Router, private activatedRoute: ActivatedRoute ) { this.routeLinks = [ { label: 'Search', link: 'search' }, { label: 'Newest', link: 'newest' }, { label: 'Random', link: 'random' } ]; router.events.subscribe(event => { if (event instanceof NavigationEnd) { this.currentRoute = event.url.slice(1); console.log(this.currentRoute); this.routeLinks.forEach((elm, index) => { if (elm.link === this.currentRoute) { this.activeLinkIndex = index; } }); } }); } }
ActivatedRouteを使って、コンストラクタ内で現在のパスをsubscribeしています。 routingが変更されるたびに、activeLinkIndexも更新されviewに反映されるようになっています。
その他のrouterで読み込んでいるsearch、newest、randomに関しては省略します。
参考
angular - Angular2 material design mdtabs with router - Stack Overflow