Angular 2
ルーティング(3.0.0+)
サーチ…
備考
ルータでできること(アクセスの制限など)がいくつかありますが、これらは個別のチュートリアルで扱うことができます。
新しいルートが必要な場合は、 app.routes.ts
を変更して次の手順に従います。
- コンポーネントのインポート
-
routes
配列に追加します。新しいpath
とcomponent
が含まれていることを確認してください。
ブートストラップ
ルートが定義されたので、アプリケーションにルートを知らせる必要があります。これを行うには、前の例でエクスポートしたプロバイダをブートストラップします。
あなたのブートストラップ設定を見つけてください( main.ts
にあるはずですが、 あなたの走行距離は異なるかもしれません )。
//main.ts
import {bootstrap} from '@angular/platform-browser-dynamic';
//Import the App component (root component)
import { App } from './app/app';
//Also import the app routes
import { APP_ROUTES_PROVIDER } from './app/app.routes';
bootstrap(App, [
APP_ROUTES_PROVIDER,
])
.catch(err => console.error(err));
ルータコンセントの設定
ルータが設定され、アプリケーションがルートを処理する方法を知ったので、設定した実際のコンポーネントを表示する必要があります。
これを行うには、 トップレベル(app)コンポーネントのHTMLテンプレート/ファイルを次のように設定します。
//app.ts
import {Component} from '@angular/core';
import {Router, ROUTER_DIRECTIVES} from '@angular/router';
@Component({
selector: 'app',
templateUrl: 'app.html',
styleUrls: ['app.css'],
directives: [
ROUTER_DIRECTIVES,
]
})
export class App {
constructor() {
}
}
<!-- app.html -->
<!-- All of your 'views' will go here -->
<router-outlet></router-outlet>
<router-outlet></router-outlet>
要素は、指定されたルートの内容を切り替えます。この要素に関するもう1つの優れた点は、HTMLの唯一の要素である必要はないということです。
たとえば、Stack Overflowの外観と同様に、ルート間で一定のままであるすべてのページにツールバーが必要になるとします。要素の下に<router-outlet>
をネストすると、ページの特定の部分だけが変更されます。
ルートの変更(テンプレートとディレクティブを使用)
ルートが設定されたので、実際にルートを変更するには何らかの方法が必要です。
この例では、テンプレートを使用してルートを変更する方法を示しますが、TypeScriptでルートを変更することは可能です。
ここに1つの例があります(束縛なし):
<a routerLink="/home">Home</a>
ユーザーがそのリンクをクリックすると、 /home
ルーティングされます。ルータは/home
を処理する方法を知っているため、 Home
コンポーネントが表示されます。
データバインディングの例を次に示します。
<a *ngFor="let link of links" [routerLink]="link">{{link}}</a>
links
と呼ばれる配列が必要なので、これをapp.ts
追加してapp.ts
:
public links[] = [
'home',
'login'
]
これは、配列をループし、 <a>
要素をrouterLink
ディレクティブ=配列内の現在の要素の値と一緒に追加します。
<a routerLink="home">home</a>
<a routerLink="login">login</a>
これは、リンクがたくさんある場合や、リンクを絶えず変更する必要がある場合に特に役立ちます。 Angularは、必要な情報をフィードするだけでリンクを追加するという忙しい作業を処理します。
現在、 links[]
は静的ですが、別のソースからデータをフィードすることは可能です。
ルートの設定
注:この例は、@ angle / routerの3.0.0.-beta2リリースに基づいています。執筆時点では、これはルータの最新バージョンです。
ルータを使用するには、そのような新しいTypeScriptファイルでルートを定義します
//app.routes.ts
import {provideRouter} from '@angular/router';
import {Home} from './routes/home/home';
import {Profile} from './routes/profile/profile';
export const routes = [
{path: '', redirectTo: 'home'},
{path: 'home', component: Home},
{path: 'login', component: Login},
];
export const APP_ROUTES_PROVIDER = provideRouter(routes);
最初の行では、 provideRouter
をインポートして、ブートストラップフェーズ中にルートが何であるかをアプリケーションに知らせることができます。
Home
とProfile
は、一例として2つのコンポーネントにすぎません。必要な各Component
をルートとしてインポートする必要があります。
次に、ルートの配列をエクスポートします。
path
:コンポーネントへのパス。 あなたは '/ ........'を使用する必要はありません。Angularはこれを自動的に行います
component
:ルートへのアクセス時にロードするコンポーネント
redirectTo
: オプション 。ユーザが特定のルートにアクセスするときに自動的にリダイレクトする必要がある場合は、これを指定します。
最後に、設定したルータをエクスポートします。 provideRouter
は、私たちのアプリケーションが各ルートを扱う方法を知っているように、私たちがprovideRouter
できるプロバイダを返します。
ルートへのアクセスまたはルートからのアクセスの制御
デフォルトの角度ルータでは、任意のルートとの間で無条件にナビゲーションを行うことができます。これは常に望ましい動作ではありません。
ユーザが条件付きで経路をナビゲートすることを許可されるシナリオでは、 ルートガードを使用してこの動作を制限することができる。
シナリオが次のいずれかに当てはまる場合は、ルートガードの使用を検討してください。
- ターゲットコンポーネントにナビゲートするには、ユーザーを認証する必要があります。
- ユーザーは、ターゲットコンポーネントにナビゲートする権限が必要です。
- コンポーネントは初期化の前に非同期要求を必要とします。
- コンポーネントは、離れて移動する前にユーザー入力が必要です。
ルートガードのしくみ
ルートガードは、ブール値を返すことによって動作し、ルーターナビゲーションの動作を制御します。 trueが返された場合、ルータはターゲットコンポーネントへのナビゲーションを続行します。 falseが返された場合、ルータはターゲットコンポーネントへのナビゲーションを拒否します。
ルートガードインターフェイス
ルータは複数のガードインターフェイスをサポートしています。
- CanActivate :ルートナビゲーションの間に発生します。
- CanActivateChild :ルートナビゲーションと子ルートの間で発生します。
- CanDeactivate :現在のルートからナビゲートするときに発生します。
- CanLoad :非同期にロードされたフィーチャモジュールへのルートナビゲーションの間に発生します。
- Resolve :経路を有効にする前にデータを取得するために使用されます。
これらのインタフェースは、ガード内で実装して、ナビゲーションの特定のプロセスへのアクセスを許可または削除することができます。
同期対非同期ルートガード
Route Guardsでは、同期操作と非同期操作で条件付きでナビゲーションを制御できます。
同期ルートガード
同期ルートガードは、条件付きでナビゲーションを制御するために、即時結果を計算するなど、ブール値を返します。
import { Injectable } from '@angular/core';
import { CanActivate } from '@angular/router';
@Injectable()
export class SynchronousGuard implements CanActivate {
canActivate() {
console.log('SynchronousGuard#canActivate called');
return true;
}
}
非同期ルートガード
より複雑な動作の場合、ルートガードは非同期的にナビゲーションをブロックできます。非同期ルートガードは、ObservableまたはPromiseを返すことができます。
これは、ユーザーの入力が質問に答えるのを待ったり、サーバーに変更を保存するのを待ったり、リモートサーバーから取得したデータを受け取るのを待ったりするような状況に役立ちます。
import { Injectable } from '@angular/core';
import { CanActivate, Router, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Observable } from 'rxjs/Rx';
import { MockAuthenticationService } from './authentication/authentication.service';
@Injectable()
export class AsynchronousGuard implements CanActivate {
constructor(private router: Router, private auth: MockAuthenticationService) {}
canActivate(route:ActivatedRouteSnapshot, state:RouterStateSnapshot):Observable<boolean>|boolean {
this.auth.subscribe((authenticated) => {
if (authenticated) {
return true;
}
this.router.navigateByUrl('/login');
return false;
});
}
}
経路設定にガードを追加する
ファイルapp.routes
保護されたルートはcanActivate
がGuard
canActivate
されてcanActivate
ます
import { provideRouter, Router, RouterConfig, CanActivate } from '@angular/router';
//components
import { LoginComponent } from './login/login.component';
import { DashboardComponent } from './dashboard/dashboard.component';
export const routes: RouterConfig = [
{ path: 'login', component: LoginComponent },
{ path: 'dashboard', component: DashboardComponent, canActivate: [AuthGuard] }
}
アプリのブートストラップで使用するAPP_ROUTER_PROVIDERSをエクスポートする
export const APP_ROUTER_PROVIDERS = [
AuthGuard,
provideRouter(routes)
];
アプリのブートストラップでGuardを使用する
ファイルmain.ts (またはboot.ts )
上記の例を考えてみましょう。
- ガードを作成します (ガードが作成される場所)。
- 経路設定にガードを追加します (Guardに経路が設定され、次にAPP_ROUTER_PROVIDERSがエクスポートされます)。
次のようにブートストラップをGuardに結合することができます
import { bootstrap } from '@angular/platform-browser-dynamic';
import { provide } from '@angular/core';
import { APP_ROUTER_PROVIDERS } from './app.routes';
import { AppComponent } from './app.component';
bootstrap(AppComponent, [
APP_ROUTER_PROVIDERS
])
.then(success => console.log(`Bootstrap success`))
.catch(error => console.log(error));
レゾルバーとガードの使用
最初のページの読み込み時に現在のユーザーを捕まえるためにroute configにトップレベルのガードを使用し、バックエンドから認証されたユーザーであるcurrentUser
の値を格納するリゾルバを使用しています。
実装の簡略化されたバージョンは次のようになります。
ここに私達の最上位ルートがあります:
export const routes = [
{
path: 'Dash',
pathMatch : 'prefix',
component: DashCmp,
canActivate: [AuthGuard],
resolve: {
currentUser: CurrentUserResolver
},
children: [...[
path: '',
component: ProfileCmp,
resolve: {
currentUser: currentUser
}
]]
}
];
ここにAuthService
があります
import { Injectable } from '@angular/core';
import { Http, Headers, RequestOptions } from '@angular/http';
import { Observable } from 'rxjs/Rx';
import 'rxjs/add/operator/do';
@Injectable()
export class AuthService {
constructor(http: Http) {
this.http = http;
let headers = new Headers({ 'Content-Type': 'application/json' });
this.options = new RequestOptions({ headers: headers });
}
fetchCurrentUser() {
return this.http.get('/api/users/me')
.map(res => res.json())
.do(val => this.currentUser = val);
}
}
ここにAuthGuard
があります:
import { Injectable } from '@angular/core';
import { CanActivate } from "@angular/router";
import { Observable } from 'rxjs/Rx';
import { AuthService } from '../services/AuthService';
@Injectable()
export class AuthGuard implements CanActivate {
constructor(auth: AuthService) {
this.auth = auth;
}
canActivate(route, state) {
return Observable
.merge(this.auth.fetchCurrentUser(), Observable.of(true))
.filter(x => x == true);
}
}
ここに私たちのCurrentUserResolver
があります:
import { Injectable } from '@angular/core';
import { Resolve } from "@angular/router";
import { Observable } from 'rxjs/Rx';
import { AuthService } from '../services/AuthService';
@Injectable()
export class CurrentUserResolver implements Resolve {
constructor(auth: AuthService) {
this.auth = auth;
}
resolve(route, state) {
return this.auth.currentUser;
}
}