← コース一覧
Angular
Googleが開発するフルスタックなフロントエンドフレームワークを学びます。スタンドアロンコンポーネントとシグナルを中心に、モダンなAngularの書き方を身につけます。
公式ドキュメント: Angular 日本語ドキュメント ↗コンポーネント基礎
- 1コンポーネント — UIの基本単位Angularの画面は、コンポーネントという部品を組み合わせて作ります。コンポーネントはTypeScriptのクラスに @Component デコレータを付けたもので、selector(HTMLタグ名)と template(表示するHTML)を指定します。selectorに app-hello と書けば、ほかの場所から <app-hello /> というタグで呼び出せます。
- 2テンプレート補間 — {{ }} で値を表示するクラスが持つ値をテンプレートに表示するには、{{ userName }} のような二重波カッコを使います。これをテンプレート補間と呼び、カッコの中にはプロパティ名のほか、{{ price * 1.1 }} のような簡単な式も書けます。式の結果は文字列に変換されてHTMLに埋め込まれます。
- 3プロパティバインディング — [ ] で値を流し込むHTML要素の属性にクラスの値を渡すには、属性名を角カッコで囲んで [src]="imageUrl" のように書きます。これをプロパティバインディングと呼び、右辺の式が評価されて、その結果が要素のプロパティに設定されます。クラス側の値が変われば、要素の状態も自動で更新されます。
- 4イベントバインディング — ( ) で操作を受け取るクリックや入力などのユーザー操作をクラスのメソッドにつなぐには、イベント名を丸カッコで囲んで (click)="increment()" のように書きます。これをイベントバインディングと呼び、イベントが発生するとカッコ内の式が実行されます。$event と書けば、イベントの詳細情報をメソッドに渡すこともできます。
- 5クラスとスタイルのバインディングCSSクラスの付け外しを条件で切り替えるには [class.クラス名]="条件" と書きます。条件が true のときだけそのクラスが付与されます。同じように [style.スタイル名]="値" で、個別のスタイルに値を直接バインドすることもできます。
制御フロー
- 6@if — 条件で表示を切り替えるテンプレート内で条件分岐をするには @if を使います。@if (条件) { ... } と書くと、条件が true のときだけ中身が描画されます。@else { ... } や @else if (条件) { ... } を続けて、条件ごとの出し分けもできます。
- 7@for — 配列を繰り返し表示する配列の要素を順に描画するには @for を使います。@for (item of items; track item.id) { ... } と書くと、配列の要素ごとに中身が繰り返し描画されます。track には各要素を一意に識別できる値(IDなど)を必ず指定します。@empty { ... } を続ければ、配列が空のときの表示も書けます。
- 8@switch — 値ごとに表示を分ける1つの値が取りうる複数のパターンで表示を分けるには @switch を使います。@switch (値) { @case (候補) { ... } } と書くと、値に一致した @case の中身だけが描画されます。どの @case にも一致しなかったときの表示は @default { ... } に書きます。
シグナルと状態
- 9実行可signal — リアクティブな状態の入れ物シグナルは「値が変わったことを周りに知らせる入れ物」です。count = signal(0) のように作り、count() と関数のように呼んで値を読み、count.set(5) で更新します。現在値をもとに更新するなら count.update((v) => v + 1) と書きます。
- 10実行可computed — シグナルから作る派生値computed は、ほかのシグナルから自動で計算される読み取り専用のシグナルです。total = computed(() => price() * quantity()) と書くと、price か quantity が変わるたびに total も新しい値になります。読み方は普通のシグナルと同じで total() です。
- 11effect — シグナルの変更に反応するeffect は、シグナルが変わるたびに実行したい処理を登録する仕組みです。effect(() => { ... }) と書くと、その関数の中で読んでいるシグナルが自動で追跡され、どれかが変わるたびに関数が再実行されます。コンポーネントのコンストラクタの中で登録するのが基本です。
- 12input() — 親から値を受け取る親コンポーネントから子へデータを渡すには、子側で input() を宣言します。task = input.required<string>() と書くと、親はテンプレートで [task]="値" の形で値を渡せます。受け取った値はシグナルなので、子のテンプレートでは task() と関数として読みます。
- 13output() — 親へイベントを通知する子コンポーネントから親へ「ボタンが押された」などの出来事を伝えるには、子側で output() を宣言します。deleted = output<number>() と書いて deleted.emit(42) を呼ぶと、親はテンプレートの (deleted)="onDeleted($event)" でそれを受け取れます。$event にはemitした値が入ります。
- 14model() — 親と子で値を双方向に同期する親から受け取った値を子側からも書き換えたいときは、model() を使います。value = model(0) と宣言すると、子は value() で読み、value.set() や value.update() で書き換えられます。親はテンプレートで [(value)]="score" と書くだけで、どちらの変更ももう一方へ自動で反映されます。
サービスと通信
- 15サービスとDI — ロジックの置き場所画面の表示に直接関係しないロジック(データの管理、計算、ログ出力など)は、サービスというクラスに切り出します。@Injectable({ providedIn: 'root' }) を付けて定義すると、Angularがインスタンスを1つだけ作り、必要とするコンポーネントに渡してくれます。この「必要な部品をフレームワークが渡してくれる」仕組みを依存性の注入(DI)と呼びます。
- 16inject() — サービスを受け取るコンポーネントからサービスを使うには、inject() 関数でインスタンスを受け取ります。private cart = inject(CartService) とフィールドの初期化として書くだけで、DIコンテナが管理しているインスタンスが手に入ります。あとは this.cart.add() のように普通のメソッド呼び出しで使えます。
- 17HttpClient — APIとの通信サーバーのAPIからデータを取得するには HttpClient を使います。アプリ起動時の providers に provideHttpClient() を追加したうえで、コンポーネントやサービスで inject(HttpClient) して this.http.get<User[]>('/api/users') のように呼び出します。レスポンスは subscribe で受け取り、届いたデータを状態に反映します。
- 18ルーティング — URLで画面を切り替えるルーティングは、URLに応じて表示するコンポーネントを切り替える仕組みです。Routes型の配列に { path: 'about', component: AboutComponent } のようにURLとコンポーネントの対応を定義し、アプリ起動時に provideRouter(routes) で登録します。コンポーネントが表示される場所は <router-outlet /> で指定します。
- 19ルートパラメータ — URLから値を受け取るURLの一部を可変にして値を受け取るには、ルート定義のpathに 'users/:id' のようにコロン付きの名前を書きます。表示されたコンポーネント側では inject(ActivatedRoute) でルート情報を受け取り、route.snapshot.paramMap.get('id') で実際の値を取り出します。/users/7 にアクセスすれば '7' が得られます。