[Angular2] TwitterBootstrapのnavbarをAngular2で実装してみる【試行錯誤中】

``Angular2``のルーティングの勉強をかねて。
（ルーティング処理とは関係ない部分の処理はすこしサボってます。あらかじめご了承。）

## 環境

### package.json
```json:package.json
{
  "name": "angular",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "angular2": "^2.0.0-beta.1",
    "bootstrap": "^3.3.6",
    "es6-promise": "^3.0.2",
    "es6-shim": "^0.33.13",
    "jquery": "^2.2.0",
    "reflect-metadata": "^0.1.2",
    "rxjs": "^5.0.0-beta.0",
    "systemjs": "^0.19.17",
    "zone.js": "^0.5.10"
  }
}
```

### tsconfig.json
```json:tsconfig.json
{
    "compilerOptions": {
        "emitDecoratorMetadata": true,
        "experimentalDecorators": true,
        "module": "commonjs",
        "moduleResolution": "node",
        "target": "es5",
        "noImplicitAny": true,
        "outDir": "assets/scripts",
        "sourceMap": false
    },
    "exclude": [
        "node_modules"
    ],
    "files": [
      "typescript/bootstrap"
    ]
}
```

## directory

* /angular
    * /assets
        * /scripts 
            * about.component.js
            * app.component.js
            * bootstrap.js
            * contact.component.js
            * home.component.js
            * index.js
            * navbar.component.js
        * /styles
            * navbar.css
        * /templates
            * my-about.tmpl
            * my-contact.tmpl
            * my-home.tmpl
            * my-navbar.tmpl
    * /coffee
        * index.coffee
    * /jade
        * index.jade
    * /typescript
        * about.component.ts
        * app.component.ts
        * bootstrap.ts
        * contact.component.ts
        * home.component.ts
        * navbar.component.ts
* index.html
* package.json
* tsconfig.json


## index.html

### script
```jade:index.jade
doctype html
html(lang="ja")
  head
    base(href="/angular/index.html")
    meta(charaset="utf-8")
    meta(name="viewport" content="width=device-width,initial-scale=1")
    link(rel="stylesheet" href="node_modules/bootstrap/dist/css/bootstrap.min.css")
    link(rel="stylesheet" href="assets/styles/navbar.css")
    title Angular Routing
  body
    my-app Loading ...
    // for twitter-bootstrap
    script(src="node_modules/jquery/dist/jquery.min.js")
    script(src="node_modules/bootstrap/dist/js/bootstrap.min.js")
    // for Angular2
    script(src="node_modules/systemjs/dist/system.js")
    script(src="node_modules/rxjs/bundles/Rx.min.js")
    script(src="node_modules/angular2/bundles/angular2-polyfills.min.js")
    script(src="node_modules/angular2/bundles/angular2.min.js")
    script(src="node_modules/angular2/bundles/router.dev.js")
    script(src="assets/scripts/index.js")
```

### transpile
```shell-session
$ jade -P jade/index.jade -o .
```

## index.js
### script
```coffee:index.coffee
appDir   = "assets/scripts"
bootFile = "bootstrap"

System
  .config
    packages :
      "#{appDir}" :
        format           : "cjs"
        defaultExtension : "js"

System
  .import "#{appDir}/#{bootFile}"
```

### transpile
```shell-session
$ coffee -o assets/scripts -c cafe
```

## TypeScript files

### bootstrap.js
```ts:bootstrap.ts
import {bootstrap} from "angular2/platform/browser";
import {AppComponent} from "./app.component";
bootstrap(AppComponent);
```

### app.component.ts
```ts:app.component.ts
import {Component, provide} from "angular2/core";
import {RouteConfig, ROUTER_DIRECTIVES, ROUTER_PROVIDERS} from "angular2/router";
import {LocationStrategy, HashLocationStrategy} from "angular2/router";
import {NavbarComponent} from "./navbar.component";
import {HomeComponent} from "./home.component";
import {AboutComponent} from "./about.component";
import {ContactComponent} from "./contact.component";

const TMPL_ROOT    = "/angular/assets/templates";
const COMPONENT_ID = "my-app";

@Component({
  selector   : COMPONENT_ID,
  template   : `
    <div class="container">
      <my-navbar></my-navbar>
      <router-outlet></router-outlet>
    </div>
  `,
  directives : [NavbarComponent, ROUTER_DIRECTIVES],
  providers  : [
    ROUTER_PROVIDERS,
    provide(LocationStrategy, {useClass : HashLocationStrategy}),
  ]
})

@RouteConfig([
  {
    path         : "/home",
    name         : "Home",
    component    : HomeComponent,
    useAsDefault : true,
  },
  {
    path         : "/about",
    name         : "About",
    component    : AboutComponent,
  },
  {
    path         : "/contact",
    name         : "Contact",
    component    : ContactComponent,
  },
])

export class AppComponent { }
```

### navbar.component.js
```ts:navbar.component.ts
import {Component, OnInit} from "angular2/core";
import {ROUTER_DIRECTIVES} from "angular2/router";
import {HomeComponent} from "./home.component";
import {AboutComponent} from "./about.component";
import {ContactComponent} from "./contact.component";

const TMPL_ROOT    = "/angular/assets/templates";
const COMPONENT_ID = "my-navbar";

@Component({
  selector    : COMPONENT_ID,
  templateUrl : TMPL_ROOT + "/" + COMPONENT_ID + ".tmpl",
  directives  : [ROUTER_DIRECTIVES],
})

export class NavbarComponent implements OnInit
{
  private _selectedId: string;


  private isSelected(id: string)
  {
    return this._selectedId === id;
  }


  private onSelect(id: string)
  {
    return this._selectedId = id;
  }


  public ngOnInit()
  {
    this._selectedId = "home";
  }
}
```


### home.component.js
```ts:home.component.ts
import {Component, OnInit} from "angular2/core";
import {Router} from "angular2/router";

const TMPL_ROOT    = "/angular/assets/templates";
const COMPONENT_ID = "my-home";

@Component({
  selector    : COMPONENT_ID,
  templateUrl : TMPL_ROOT + "/" + COMPONENT_ID + ".tmpl",
})

export class HomeComponent implements OnInit
{
  public constructor(private _router: Router)
  {
    //no-op
  }


  public ngOnInit()
  {
    this._router.navigate(["Home"]);
  }
}
```

### about.component.js
```ts:about.component.ts
import {Component, OnInit} from "angular2/core";
import {Router} from "angular2/router";

const TMPL_ROOT    = "/angular/assets/templates";
const COMPONENT_ID = "my-about";

@Component({
  selector    : COMPONENT_ID,
  templateUrl : TMPL_ROOT + "/" + COMPONENT_ID + ".tmpl",
})

export class AboutComponent implements OnInit
{
  public constructor(private _router: Router)
  {
    //no-op
  }


  public ngOnInit()
  {
    this._router.navigate(["About"]);
  }
}
```

### contact.component.ts
```ts:contact.component.ts
import {Component, OnInit} from "angular2/core";
import {Router} from "angular2/router";

const TMPL_ROOT    = "/angular/assets/templates";
const COMPONENT_ID = "my-contact";

@Component({
  selector    : COMPONENT_ID,
  templateUrl : TMPL_ROOT + "/" + COMPONENT_ID + ".tmpl",
})

export class ContactComponent implements OnInit
{
  public constructor(private _router: Router)
  {
    //no-op
  }


  public ngOnInit()
  {
    this._router.navigate(["Contact"]);
  }
}
```

### transpile
```shell-session
$ tsc
```

## Template files
### my-navbar.tmpl
```html:my-navbar.tmpl
<!-- Static navbar -->
<nav class="navbar navbar-default">
  <div class="container-fluid">
    <div class="navbar-header">
      <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
        <span class="sr-only">Toggle navigation</span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
      </button>
      <a class="navbar-brand" href="index.html">Project name</a>
    </div>
    <div id="navbar" class="navbar-collapse collapse">
      <ul class="nav navbar-nav">
        <!-- *ngFor 使って書き直す -->
        <li [class.active]="isSelected('home')" (click)="onSelect('home')"><a [routerLink]="['Home']">Home</a></li>
        <li [class.active]="isSelected('about')" (click)="onSelect('about')"><a [routerLink]="['About']">About</a></li>
        <li [class.active]="isSelected('contact')" (click)="onSelect('contact')"><a [routerLink]="['Contact']">Contact</a></li>
        <li class="dropdown">
          <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Dropdown <span class="caret"></span></a>
          <ul class="dropdown-menu">
            <li><a href="#">Action</a></li>
            <li><a href="#">Another action</a></li>
            <li><a href="#">Something else here</a></li>
            <li role="separator" class="divider"></li>
            <li class="dropdown-header">Nav header</li>
            <li><a href="#">Separated link</a></li>
            <li><a href="#">One more separated link</a></li>
          </ul>
        </li>
      </ul>
      <ul class="nav navbar-nav navbar-right">
        <li><a href="./">Default <span class="sr-only">(current)</span></a></li>
        <li><a href="../navbar-static-top/">Static top</a></li>
        <li><a href="../navbar-fixed-top/">Fixed top</a></li>
      </ul>
    </div><!--/.nav-collapse -->
  </div><!--/.container-fluid -->
</nav>
```

### my-home.tmpl
```html:my-home.tmpl
<!-- Main component for a primary marketing message or call to action -->
<div class="jumbotron">
  <h1>Navbar Home</h1>
  <p>This example is a quick exercise to illustrate how the default, static navbar and fixed to top navbar work. It includes the responsive CSS and HTML, so it also adapts to your viewport and device.</p>
  <p>
    <a class="btn btn-lg btn-primary" href="../../components/#navbar" role="button">View navbar docs &raquo;</a>
  </p>
</div>
```

### my-about.tmpl
```html:my-about.tmpl
<!-- Main component for a primary marketing message or call to action -->
<div class="jumbotron">
  <h1>Navbar About</h1>
  <p>This example is a quick exercise to illustrate how the default, static navbar and fixed to top navbar work. It includes the responsive CSS and HTML, so it also adapts to your viewport and device.</p>
  <p>
    <a class="btn btn-lg btn-primary" href="../../components/#navbar" role="button">View navbar docs &raquo;</a>
  </p>
</div>
```

### my-contact.tmpl
```html:my-contact.tmpl
<!-- Main component for a primary marketing message or call to action -->
<div class="jumbotron">
  <h1>Navbar Contact</h1>
  <p>This example is a quick exercise to illustrate how the default, static navbar and fixed to top navbar work. It includes the responsive CSS and HTML, so it also adapts to your viewport and device.</p>
  <p>
    <a class="btn btn-lg btn-primary" href="../../components/#navbar" role="button">View navbar docs &raquo;</a>
  </p>
</div>
```



## CSS
### navbar.css
```shell-session
$ cd assets/styles
$ wget http://getbootstrap.com/examples/navbar/navbar.css
```

### アクセス
``http://hogehoge.com/angular/index.html``


## 課題

* 1) 【実装完了】 ``[routerLink]``を定義したのち、リンクをクリックしたあと``<li class="active">``を指定するにはどうするか
    * **``(click)``と``[class.active]``を利用して実装しました。**
* 2) 【実装完了】 ``[routerLink]``を``/home``等で定義すると、リロード時に、404 not found に飛ばされてすごくメンドウな感じ。これはハッシュを使えば回避できそうなので、そちらの実装に変更したいなぁ。[browser-url-styles](https://angular.io/docs/ts/latest/guide/router.html#!#browser-url-styles)
    * **``angular2/ts/src/router/hash_location_strategy.ts``に書いてありました。**
* 3) ``navbar.component``以外にルーティングを設定したい場合はどう書くか。


## 関連
[[Angular2] Routerに使用するHTMLのBASE要素について](http://qiita.com/pb_tmz08/items/ca697e79365820b0ea84)