73
71

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

はじめに

大規模なSPAでは必要不可欠なルーティングの機能をAngular2で試してみます。
Angular2の2.0.0-beta.0を使います。

Router

まずは最小限の例を示しましょう。
beta.0で更新された5 MIN QUICKSTARTを参考にディレクトリ構成は以下のようにしています。

my-app
├ node_modules
├ app
│ ├ app.component.ts
│ ├ page1.component.ts
│ ├ page2.component.ts
│ └ boot.ts
├ index.html
├ package.json
└ tsconfig.json

index.htmlの中身は以下のとおりです。

index.html
<html>
  <head>
    <title>Angular 2 QuickStart</title>
    <script src="node_modules/angular2/bundles/angular2-polyfills.js"></script>
    <script src="node_modules/systemjs/dist/system.src.js"></script>
    <script src="node_modules/rxjs/bundles/Rx.js"></script>
    <script src="node_modules/angular2/bundles/angular2.dev.js"></script>
    <script src="node_modules/angular2/bundles/router.dev.js"></script>
    <script>
      System.config({
        packages: {
          app: {
            format: 'register',
            defaultExtension: 'js'
          }
        }
      });
      System.import('app/boot')
        .then(null, console.error.bind(console));
    </script>
    <base href="/">
  </head>
  <body>
    <my-app>Loading...</my-app>
  </body>
</html>

5 MIN QUICKSTARTのindex.htmlに、router.dev.jsを読み込むscript要素とbase要素を追加しています。

4つのTypeScriptファイルの中身は以下のようになっています。

app/page1.component.ts
import {Component} from 'angular2/core'

const template = `
<h2>page 1</h2>
`;

@Component({
  template: template
})
export class Page1 {
}
app/page2.component.ts
import {Component} from 'angular2/core'

const template = `
<h2>page 2</h2>
`;

@Component({
  template: template
})
export class Page2 {
}

Page1とPage2はtemplateから直接参照しないので、selectorは省略してもよさそうでした。

app/app.component.ts
import {Component} from 'angular2/core'
import {RouteConfig, ROUTER_DIRECTIVES} from 'angular2/router'
import {Page1} from './page1.component'
import {Page2} from './page2.component'

const template = `
<router-outlet></router-outlet>
`;

@Component({
  selector: 'my-app',
  template: template,
  directives: [ROUTER_DIRECTIVES]
})
@RouteConfig([
  {
    useAsDefault: true,
    path: '/page1',
    component: Page1
  },
  {
    path: '/page2',
    component: Page2
  }
])
export class AppComponent {
}
app/boot.ts
import {bootstrap} from 'angular2/platform/browser'
import {ROUTER_PROVIDERS} from 'angular2/router'
import {AppComponent} from './app.component'

bootstrap(AppComponent, [
  ROUTER_PROVIDERS
]);

ブラウザで開くとhttp://localhost:3000/page1に遷移し「page 1」と表示されているはずです。
URLを入力しhttp://localhost:3000/page2に遷移すると表示内容が「page 2」に変わるかと思います。

とりあえず大事なのは、app.component.tsの@RouteConfigです。
引数にはRouteの配列を与えます。

Routeの引数に必須なのはpathcomponentで、pathはURLに反映されるpathの名前、componentはこのRouteに対応するComponentです。
Page1へのRouteにuseAsDefault: trueを与えることで、http://localhost:3000/にアクセスしたときにhttp://localhost:3000/page1に遷移するようになっています。

Page1、Page2の内容は、templateの<router-outlet></router-outlet>の箇所に表示されます。
<router-outlet></router-outlet>を使うには、angular/routerからimportするROUTER_DIRECTIVESが必要です。

routerLink

さて、上のままではURLを直接打ち込まないとページ遷移ができないので不便です。
routerLinkを使ってRouteへのリンクを作ってみます。

app/app.component.ts
import {Component} from 'angular2/core'
import {RouteConfig, ROUTER_DIRECTIVES} from 'angular2/router'
import {Page1} from './page1.component'
import {Page2} from './page2.component'

const template = `
<a [routerLink]="['Spam']">page1</a>
<a [routerLink]="['Ham']">page2</a>
<router-outlet></router-outlet>
`;

@Component({
  selector: 'my-app',
  template: template,
  directives: [ROUTER_DIRECTIVES]
})
@RouteConfig([
  {
    useAsDefault: true,
    path: '/page1',
    component: Page1,
    name: 'Spam'
  },
  {
    path: '/page2',
    component: Page2,
    name: 'Ham'
  }
])
export class AppComponent {
}

変更点は2箇所です。
まずRouteのパラメータにnameを与えます。
次にtemplateにa要素を追加し、属性に[routerLink]="['Spam']"のように書きます。
ここでの「Spam」が、Routeのnameの「Spam」に対応します。

また、alpha版の資料だとrouter-linkと書かれていたりしますが、routerLinkに変更になっているので気をつけてください。

router.navigate

formをsubmitされたときなど、Component内で処理を行ってからページ遷移を行いたい場合があると思います。
実装例は以下のとおりです。

app/page2.component.ts
import {Component} from 'angular2/core'
import {Router} from 'angular2/router'

const template = `
<h2>page 2</h2>
<button (click)="goPage1()">go to page1</button>
`;

@Component({
  template: template
})
export class Page2 {
  constructor(public router: Router) {
  }

  goPage1() {
    console.log('go to page1');
    this.router.navigate(['Spam']);
  }
}

router.navigateの引数はtemplateでのrouterLinkと同じなようです。

LocationStrategy

Angular2ではPathをURLにするときに、実際にhttps://example.com/page1https://example.com/#/page1のどちらにするかをLocationStrategyを使って設定できます。
Angular1の$locationProvider.html5Modeと同じような感じです。
前者はPathLocationStrategy、後者はHashLocationStrategyと呼びます。

デフォルトではPathLocationStrategyなので、HashLocationStrategyに変更する例は以下のようになります。

app/app.component.ts
import {provide} from 'angular2/core'
import {bootstrap} from 'angular2/platform/browser'
import {ROUTER_PROVIDERS, LocationStrategy, HashLocationStrategy} from 'angular2/router'
import {AppComponent} from './app.component'

bootstrap(AppComponent, [
  ROUTER_PROVIDERS,
  provide(LocationStrategy, {useClass: HashLocationStrategy})
]);

Lifecycle Hooks

Angular2ではLifecycle HooksによってComponentの状態変更のタイミングで処理をはさむことができます。
RouterのLifecycle HookはOnActivateOnReuseOnDeactivateCanReuseCanDeactivateの5種類があります。

各HookはInterfaceとして提供されており、ComponentでInterfaceのメソッドを実装することになります。
以下は簡単な例です。

import {Component} from 'angular2/core'
import {OnActivate, OnReuse, OnDeactivate, CanReuse, CanDeactivate} from 'angular2/router'

const template = `
<h2>page 1</h2>
`;

@Component({
  template: template
})
export class Page1 implements OnActivate, OnReuse, OnDeactivate, CanReuse, CanDeactivate {
  routerOnActivate() {
    console.log('onActivate');
  }

  routerOnReuse() {
    console.log('onReuse');
  }

  routerOnDeactivate() {
    console.log('onDeactivate');
  }

  routerCanReuse() {
    return confirm('can reuse?');
  }

  routerCanDeactivate() {
    return confirm('can deactivate?');
  }
}

OnActivateのInterfaceにrouterOnActivateメソッドが対応するという感じになっています。
routerCanReuserouterCanDeactivateは真偽値またはPromiseを返すようになっています。
今回は試していませんが、Promiseを返すことで非同期的な処理も行うことができます。

おわりに

本稿では、Angular2のRouterでよく使いそうな機能などを試してみました。
今年の春頃にAngular1向けのComponent Routerを触ってみましたが、そこから更に洗練された印象を受けます。

本稿を書くにあたって、@ovrmrw さんがRouterを使うサンプルを既に書いてくれていたのでとても助かりました。

Routerの詳細は公式のドキュメントも目を通してみてください。

73
71
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
73
71

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?