【Angular.io】 Architectureまとめ

Angular.ioにある[Architecture](https://angular.io/guide/architecture)について簡単にまとめました。

# モジュール

## ルートモジュール
アプリケーションのrootととなるモジュール。アプリケーションをbootstrapする際に必要なモジュールたちをここで一括で読み込む。

## フィーチャーモジュール
Root Moduleに読み込まれるモジュールたち。

## NgModule
ディレクティブやサービスなどをひとまとまりにしたモジュールを宣言するためのAPI。

```
import { NgModule }      from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
@NgModule({
  imports:      [ BrowserModule ],
  providers:    [ Logger ],
  declarations: [ AppComponent ],
  exports:      [ AppComponent ],
  bootstrap:    [ AppComponent ]
})
export class AppModule { }
```

- `declarations`
モジュール内で宣言されているコンポーネント、ディレクティブ、パイプを登録する。一度登録されればそのモジュール内ならどこでも使えるようになる。

- `providers`
アプリケーション / モジュール全体で使用するサービスを登録する。ルートモジュールに`provider`を登録する場合は、 同じ`provider`のインスタンスをアプリケーション全体で共有することが可能だが、コンポーネントの`provider`として登録した場合は、 コンポーネントが作成される度に新しい`provider`のインスタンスが作成される。

- `imports`
自分のモジュールに別のモジュールを読み込むことができる。importsから読み込まれたモジュールからはexportsで指定されたものと、providersに登録されたものが読み込まれる。

- `exports`
exportsプロパティにはコンポーネント、ディレクティブとパイプを指定することができる。

- `bootstrap`
アプリケーションのエントリポイントとなるコンポーネントを指定する。

# コンポーネント
ビューをコントロールするためのクラスやHTML、CSS、タグを定義する。

```
@Component({ // メタデータ
  selector: 'my-app’, // ビューで使用するタグ名
  template: '<h1>My First Angular 2 App</h1>' // HTMLテンプレート,
  styleUrls: ['style.css’] // CSSファイル
})
export class AppComponent { } // コンポーネントクラス
```
# テンプレート
コンポーネントで使用するビューファイル

```
<h2>Hero List</h2>

<p><i>Pick a hero from the list</i></p>
<ul>
  <li *ngFor="let hero of heroes" (click)="selectHero(hero)">
    {{hero.name}}
  </li>
</ul>

<hero-detail *ngIf="selectedHero" [hero]="selectedHero"></hero-detail>
```

# メタデータ
コンポーネント内で使用するメタデータを定義する。以下が主なメタデータ。

- `selector`
HTMLでコンポーネントのインスタンスを埋め込むためのタグ名。

- `templateUrl`
HTMLファイルの指定。

- `providers`
コンポーネント内で使用するサービスを定義。

# データバインティング
AngularはDOMとモデル間のデータバインティングを自動的に行ってくれる。

```
<li>{{hero.name}}</li>
<hero-detail [hero]="selectedHero"></hero-detail>
<li (click)="selectHero(hero)"></li>
```

- `[hero]="selectedHero"`
親コンポーネントの `selectedHero` プロパティを 子供コンポーネント(`HeroDetailComponent`) に `hero` をプロパティとしてバインディングさせている。

- `(click)="selectHero(hero)”`
クリックされた時に `selectedHero` を呼び出す。

- `双方向データバインティング (モデルからビューへ、ビューからモデルへ)`
`[…]` がインプットプロパティ、`(…)`がアウトプットプロパティを意味している。双方向データバインディングをするには `ngModel` を使うと簡単にできる。

```
<input [(ngModel)]=“hero.name”>
```

# Directives
ディレクティブを使用することによって動的にDOMを変更することができる。コンポーネントもディレクティブの一種で、違いはテンプレートを含んでいるかいないか。

- `Structural Directive (構造化ディレクティブ)`
DOMを削除したり、追加したりしてDOMのレイアウトを変更するもの。`NgFor` や `NgIf` など。

- `Attribute Directive (要素ディレクティブ)`
HTML要素に変更を加えるディレクティブ。`NgClass`、`NgStyle`、`NgModel`など。

```
<li *ngFor="let hero of heroes"></li>
<hero-detail *ngIf="selectedHero"></hero-detail>
```

# サービス
シングルトンでコンポーネントやデータの状態を管理するために使われるクラス。複数のコンポーネントから呼び出されたりする。XHRのデータ取得や、バリデーションなどの複雑な処理はコンポーネントではなくサービスで行うのが一般的。コンポーネントの責務はビューとのバインディングなどのインタラクションのみにして `lean(無駄がない)` にするのがよさげ。

```
export class HeroService {
  private heroes: Hero[] = [];

  constructor(
    private backend: BackendService,
    private logger: Logger) { }

  getHeroes() {
    this.backend.getAll(Hero).then( (heroes: Hero[]) => {
      this.logger.log(`Fetched ${heroes.length} heroes.`);
      this.heroes.push(...heroes); // fill cache
    });
    return this.heroes;
  }
}
```

サービスはコンポーネントに一度加えられると、そのコンポーネントに付随する子供コンポーネントでも参照することができる。そのためルートコンポーネントで読み込ませたサービスのインスタンスは全てのコンポーネントで使用可能になる。

もし、複数のサービスのインスタンスを生成したい場合は以下のようにキャッシュさせる仕組みを整えてあげれば可能。

複数のHeroサービスのインスタンスを管理するHeroCheServiceを定義。

```
@Injectable()
export class HeroCacheService {
  hero: Hero;
  constructor(private heroService: HeroService) {}

  fetchCachedHero(id: number) {
    if (!this.hero) {
      this.hero = this.heroService.getHeroById(id);
    }
    return this.hero;
  }
}
```
# 依存型注入 (DI)
AngularDI機能を提供しており、主にサービスを使用するときにつかう。

コンポーネントの `providers` プロパティに使用したいサービスを定義する

```
import { LoggerService }      from './logger.service';
import { UserContextService } from './user-context.service';
import { UserService }        from './user.service';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  providers: [ LoggerService, UserContextService, UserService ]
})
export class AppComponent {
/* . . . */
}
```
クラスのコンストラクタでインジェクトする

```
constructor(logger: LoggerService) {
  logger.logInfo('Creating HeroBiosComponent');
}
```

参考:
https://angular.io/guide/architecture