はじめに
- Angular のチュートリアルをやったりドキュメントを読んだりしたので、復習のために自分でアプリケーションを作りながら入門的な内容をまとめていく。
 
ドキュメント
- 
公式のチュートリアル
- これやっておけばなんとなくわかったような気になる
 
 - 
公式のアーキテクチャ解説
- コンポーネントとは?モジュールとは?サービスとは?というのがわかる
 
 
インストール
- Angular プロジェクトのスケルトンを生成してくれる Angular CLI をインストールする
 
npm install -g @angular/cli
プロジェクトの作成
ng new myapp
cd myapp
npm install
アプリケーションの起動
- コマンド実行後 
http://localhost:4200/にブラウザでアクセスすることで起動を確認できる 
npm start
コンポーネントの作成
- コンポーネントは Angular の管理する UI 要素の単位
 - コンポーネントは TypeScript のクラスで内部変数やメソッドを持ち、テンプレートの HTML や CSS を持つことができる
 - コンポーネントは入れ子にすることができ、ページとしても UI の要素としても振る舞うことができる
 - 今回は ng コマンドでヘッダーパーツのコンポーネントを作成する
 
コマンドの実行
- 
ng generateコマンドでコンポーネントを作成する - コンポーネントの本体の ts ファイルとテストの spec.ts ファイル、html, css が作成される
 - app.module.ts の変更箇所については後述
 
$ ng generate component header
installing component
  create src/app/header/header.component.css
  create src/app/header/header.component.html
  create src/app/header/header.component.spec.ts
  create src/app/header/header.component.ts
  update src/app/app.module.ts
コンポーネントの登録
- コンポーネント作成の際に app.module.ts に変更が入ったが、これはアプリケーションのメインモジュールにヘッダーコンポーネントが登録されたということ
 - モジュールとは現時点では Angular のフレームワークとしての機能を提供するレイヤーと理解しておけば良い
 - 今回はアプリケーション内で利用しているコンポーネントのリストの設定にヘッダーコンポーネントが追加された
 
diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index f657163..55587c2 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -2,10 +2,12 @@ import { BrowserModule } from '@angular/platform-browser';
 import { NgModule } from '@angular/core';
 import { AppComponent } from './app.component';
+import { HeaderComponent } from './header/header.component';
 @NgModule({
   declarations: [
-    AppComponent
+    AppComponent,
+    HeaderComponent
   ],
   imports: [
     BrowserModule
@NgModule とは
- 
@NgModule の箇所は「デコレータ」と呼ばれる TypeScript の機能でクラスやメソッドにメタデータを定義できる
- Java のアノテーションや C# の属性のようなもの
 
 - @NgModule デコレータを付けたクラスは Angular のモジュールとして振る舞う
 - @NgModule デコレータのカッコの中には Angular のモジュールの設定を定義する
 - declarations にはアプリケーションで使用されるコンポーネントがリストで定義される
 
作成されたコンポーネントの確認
- 初期化処理として constructor と ngOnInit が定義されている
 - constructor は TypeScript の標準のコンストラクタで ngOnInit は Angular のコンポーネントの初期化処理
 - constructor には後述の DI のための処理だけを定義して、コンポーネントの初期化処理は ngOnInit に定義する慣習になっている
 
header.component.ts
import { Component, OnInit } from '@angular/core';
// @Component デコレータがついたクラスがコンポーネントとして振る舞う
@Component({
  selector: 'app-header', // HTML上では <app-header> として扱うことができる
  templateUrl: './header.component.html', // このコンポーネントに関連するテンプレートの定義
  styleUrls: ['./header.component.css'] // このコンポーネントに関連するスタイルシートの定義
})
export class HeaderComponent implements OnInit {
  // 初期化処理
  constructor() { }
  // OnInit インターフェイスを実装すると ngOnInit が初期化時に実行される
  ngOnInit() {
  }
}
コンポーネントの表示
- app.component.html の行頭にヘッダーのセレクタを記述することでヘッダーコンポーネントを表示することができる
 
diff --git a/src/app/app.component.html b/src/app/app.component.html
index 230f4ed..5b233f3 100644
--- a/src/app/app.component.html
+++ b/src/app/app.component.html
@@ -1,4 +1,5 @@
 <!--The content below is only a placeholder and can be replaced.-->
+<app-header></app-header>
 <div style="text-align:center">
   <h1>
     Welcome to {{title}}!
コンポーネントの値をテンプレートに表示する
変数をテンプレートに表示する
- コンポーネントのインスタンス変数はテンプレート上で 
{{VAR}}という記法で表示できる 
diff --git a/src/app/header/header.component.html b/src/app/header/header.component.html
index 51bfb8c..80a0af3 100644
--- a/src/app/header/header.component.html
+++ b/src/app/header/header.component.html
@@ -1,3 +1,4 @@
 <p>
   header works!
+  header title is {{title}}
 </p>
diff --git a/src/app/header/header.component.ts b/src/app/header/header.component.ts
index ac77fc6..f430c29 100644
--- a/src/app/header/header.component.ts
+++ b/src/app/header/header.component.ts
@@ -7,6 +7,8 @@ import {Component, OnInit} from '@angular/core';
 })
 export class HeaderComponent implements OnInit {
+  title = 'タイトル';
+
   constructor() {
   }
テンプレートでリストを表示する
- テンプレートで 
*ngForを使うとリストをループで展開することができる - ng-container 要素はコンパイル後のソースには表示されないので今回のように *ngFor などとセットで利用される
 
diff --git a/src/app/header/header.component.html b/src/app/header/header.component.html
index 80a0af3..348d0c7 100644
--- a/src/app/header/header.component.html
+++ b/src/app/header/header.component.html
@@ -2,3 +2,7 @@
   header works!
   header title is {{title}}
 </p>
+
+<ng-container *ngFor="let b of buttons">
+  <button>{{b}}</button>
+</ng-container>
diff --git a/src/app/header/header.component.ts b/src/app/header/header.component.ts
index f430c29..cbe156a 100644
--- a/src/app/header/header.component.ts
+++ b/src/app/header/header.component.ts
@@ -9,6 +9,12 @@ export class HeaderComponent implements OnInit {
   title = 'タイトル';
+  buttons: string[] = [
+    'button1',
+    'button2',
+    'button3'
+  ];
+
   constructor() {
   }
変数で表示非表示を切り替える
- 
*ngIfを使うとコンポーネントの変数の値によってテンプレート上の表示非表示を切り替えることができる 
diff --git a/src/app/header/header.component.html b/src/app/header/header.component.html
index 348d0c7..e09e2ad 100644
--- a/src/app/header/header.component.html
+++ b/src/app/header/header.component.html
@@ -3,6 +3,9 @@
   header title is {{title}}
 </p>
-<ng-container *ngFor="let b of buttons">
-  <button>{{b}}</button>
+<ng-container *ngIf="showButton">
+  <ng-container *ngFor="let b of buttons">
+    <button>{{b}}</button>
+  </ng-container>
 </ng-container>
+
diff --git a/src/app/header/header.component.ts b/src/app/header/header.component.ts
index cbe156a..5f5301f 100644
--- a/src/app/header/header.component.ts
+++ b/src/app/header/header.component.ts
@@ -15,6 +15,8 @@ export class HeaderComponent implements OnInit {
     'button3'
   ];
+  showButton = false;
+
   constructor() {
   }
ルーティング機能を使って表示するコンポーネントを切り替える
- RouterModule を使うことでテンプレート中の 
<router-outlet>内に任意のコンポーネントを表示することができる - 今回は About ページを追加してページ全体の表示を切り替えられるようにする
- ページ全体を切り替えるような実装にするため既存のトップページの内容は IndexComponent に避難して AppComponent では の表示だけを行う
 
 
Index ページ用のコンポーネントの追加
ng g component index
- app.component.html を index.component.html にコピーしておく
 
About ページ用のコンポーネントの追加
ng g component about
ルーターモジュールの作成
- ルーティング設定を AppModule に直接記載してもいいが、今回はルーティング設定を切り出したいのと自分でモジュールを作ってみたいのでこのアプリケーション用のルーターモジュールをつくってみる
 
$ ng generate module app-router
installing module
  create src/app/app-router/app-router.module.ts
  WARNING Module is generated but not provided, it must be provided to be used
ルーターモジュールの設定
- RouterModule が標準のルーターモジュール
 - アプリケーション用のルーターモジュールの定数でルーティング設定を用意しておき、RouterModule の import と設定を行う
 - RouterModule を export することでこのモジュールを import したモジュール側で RouterModule を改めて import する必要がなくなるので(これだけだとそんなに意味はないが)見通しが良くなり責任が適切に分割できる
 
import {NgModule} from '@angular/core';
import {RouterModule, Routes} from '@angular/router';
import {AppComponent} from '../app.component';
import {AboutComponent} from '../about/about.component';
const routes: Routes = [
  {path: '', component: IndexComponent},
  {path: 'about', component: AboutComponent},
];
@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRouterModule {
}
ルーターモジュールをメインモジュールから読み込む
diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index 374a2c6..f306a55 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -4,15 +4,19 @@ import { NgModule } from '@angular/core';
 import { AppComponent } from './app.component';
 import { HeaderComponent } from './header/header.component';
 import { AboutComponent } from './about/about.component';
+import {AppRouterModule} from './app-router/app-router.module';
+import { IndexComponent } from './index/index.component';
 @NgModule({
   declarations: [
     AppComponent,
     HeaderComponent,
     AboutComponent,
     IndexComponent
   ],
   imports: [
-    BrowserModule
+    BrowserModule,
+    AppRouterModule
   ],
   providers: [],
   bootstrap: [AppComponent]
ルートパラメータを使用する
ルート定義でパラメータを受け取るように設定
- FooComponent で 
barパラメータを受け取る設定を追加 
AppRouterModule.ts
const routes: Routes = [
  {path: '', component: IndexComponent},
  {path: 'about', component: AboutComponent},
  {path: 'foo/:bar', component: FooComponent},
];
ルートパラメータを受け取る
- FooComponent で 
barパラメータを受け取る 
FooComponent.ts
import {ActivatedRoute} from '@angular/router';
@Component({...})
export class FooComponent implements OnInit {
  bar: string;
  constructor(private route: ActivatedRoute) {
    route.params.subscribe(params => {
      this.bar = params['bar'];
    });
  }
  ngOnInit() {
  }
}
サービスを作成する
- Angular で言うサービスとは何らかのデータを返したり何らかの処理をするレイヤー
 - 公式ドキュメントの例だと logging service, data service, tax calculator, application configuration などとあるので、フレームワークの拡張でもドメインロジックでもなんでもサービスとして扱う様子
 - 今回はランダムで運勢を教えてくれるおみくじサービスを作ってみる
 
$ ng g service omikuji
installing service
  create src/app/omikuji.service.spec.ts
  create src/app/omikuji.service.ts
  WARNING Service is generated but not provided, it must be provided to be used
omikuji.service.ts
import {Injectable} from '@angular/core';
@Injectable()
export class OmikujiService {
  box: string[] = [
    '大吉',
    '中吉',
    '吉',
    '小吉'
  ];
  constructor() {
  }
  draw(): string {
    return this.box[Math.floor(Math.random() * this.box.length)];
  }
}
サービスをコンポーネントから使用する
- Dependency Injection を使ってコンポーネントにサービスを割り当てて使用する
 - Dependency Injection とは依存性の注入と訳され、Angular ではサービスや任意のクラスを DI の対象として設定しておくと、初期化と割り当てをフレームワークが自動で行ってくれる
 
サービスを DI の対象にする
- AppModule の @NgModule デコレータの設定の providers に OmikujiService を登録するとアプリケーション全体で OmikujiService が DI の対象になる
 
diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index f306a55..37fdd84 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -6,6 +6,7 @@ import { HeaderComponent } from './header/header.component';
 import { AboutComponent } from './about/about.component';
 import {AppRouterModule} from './app-router/app-router.module';
 import { IndexComponent } from './index/index.component';
+import {OmikujiService} from './omikuji.service';
 @NgModule({
   declarations: [
@@ -18,7 +19,7 @@ import { IndexComponent } from './index/index.component';
     BrowserModule,
     AppRouterModule
   ],
-  providers: [],
+  providers: [OmikujiService],
   bootstrap: [AppComponent]
 })
 export class AppModule { }
サービスをコンポーネントに割り当てて使用する
- コンポーネントのコンストラクタの引数に DI 対象のクラスを指定しておくと初期化時に自動で割り当てられ、コンポーネントから使用できるようになる
 
diff --git a/src/app/header/header.component.html b/src/app/header/header.component.html
index e09e2ad..e868060 100644
--- a/src/app/header/header.component.html
+++ b/src/app/header/header.component.html
@@ -9,3 +9,6 @@
   </ng-container>
 </ng-container>
+<p>
+  {{omikujiResult}}
+</p>
diff --git a/src/app/header/header.component.ts b/src/app/header/header.component.ts
index 5f5301f..be4283b 100644
--- a/src/app/header/header.component.ts
+++ b/src/app/header/header.component.ts
@@ -1,4 +1,5 @@
 import {Component, OnInit} from '@angular/core';
+import {OmikujiService} from '../omikuji.service';
 @Component({
   selector: 'app-header',
@@ -17,10 +18,13 @@ export class HeaderComponent implements OnInit {
   showButton = false;
-  constructor() {
+  omikujiResult = '';
+
+  constructor(public omikuji: OmikujiService) {
   }
   ngOnInit() {
+    this.omikujiResult = this.omikuji.draw();
   }
 }
クリックイベントを処理する
- テンプレートで 
(click)="something()"とするとその要素のクリックイベントで something メソッドを実行する - 今回はクリックでおみくじを引くように修正する
 
diff --git a/src/app/header/header.component.html b/src/app/header/header.component.html
index e868060..51bf2a2 100644
--- a/src/app/header/header.component.html
+++ b/src/app/header/header.component.html
@@ -9,6 +9,6 @@
   </ng-container>
 </ng-container>
-<p>
-  {{omikujiResult}}
-</p>
+<div>
+  <button (click)="draw()">おみくじを引く</button> {{omikujiResult}}
+</div>
diff --git a/src/app/header/header.component.ts b/src/app/header/header.component.ts
index be4283b..d5c56e2 100644
--- a/src/app/header/header.component.ts
+++ b/src/app/header/header.component.ts
@@ -18,13 +18,15 @@ export class HeaderComponent implements OnInit {
   showButton = false;
-  omikujiResult = '';
+  omikujiResult;
   constructor(public omikuji: OmikujiService) {
   }
   ngOnInit() {
-    this.omikujiResult = this.omikuji.draw();
   }
+  draw() {
+    this.omikujiResult = this.omikuji.draw();
+  }
 }