Angular基礎 #2 コンポーネントとテンプレート構文

読了 9分

前回は Angular とは何か、どんな強みを持っているかを見てきました。今回からは本格的にコードを触っていきます。Angular の学習は結局 コンポーネント (Component) から始まってコンポーネントで終わると言っても過言ではないほど、コンポーネントがすべての画面の基本単位です。

今回の記事でやることは大きく 4 つです。

  1. Node.js と Angular CLI のインストール
  2. ng new で最初のプロジェクトを作成
  3. コンポーネント 1 つの構造を把握 (@Component デコレータ)
  4. 新しいコンポーネントを作って親コンポーネントに差し込む

Node.js と Angular CLI のインストール #

Angular で開発するためには、まず Node.js が必要です。Angular CLI 自体が Node.js 上で動作し、ビルド・テストツールもすべて Node 環境を使うためです。

nodejs.org にアクセスして LTS (Long Term Support) バージョンをダウンロードしてインストールします。この記事を書いている時点での LTS は Node 22 ラインです。Mac では Homebrew でインストールしても構いません。

Node.js インストール (Homebrew)
brew install node

インストールが終わったらターミナルを新しく開き、バージョンを確認します。

バージョン確認
node -v
npm -v

Node と npm のバージョンが出力されれば正常です。これで Angular の標準ツールである Angular CLI をグローバルにインストールします。

Angular CLI インストール
npm install -g @angular/cli

-g は “global” の略で、このパッケージをシステム全体にインストールしてどのフォルダからでも ng コマンドを使えるようにする、という意味です。インストールが終わったら次のコマンドで確認します。

Angular CLI バージョン確認
ng version

Angular CLI のバージョンとともに ASCII アートで描かれた Angular ロゴが出力されれば成功です。この講座は Angular v17 以上 (Standalone Components が標準となった時点) を基準にしています。

注記
Mac で ng version 実行時に権限エラーが出る方は npm のグローバルパス設定に問題がある可能性があります。このような場合には nvm や Homebrew で Node をインストールするとほとんど解決します。

最初のプロジェクトを作る #

希望する場所 (例: ~/projects または Desktop) に移動した後、次のコマンドを実行します。

新しいプロジェクトの作成
ng new my-app

my-app はプロジェクトフォルダ名なので、好きな名前に変えても構いません。コマンドを実行するといくつかの質問を受けます。

  1. Which stylesheet format would you like to use? — スタイル形式を聞かれます。CSS を選択します (入門者にはもっとも無難です。SCSS・Sass・Less に慣れている方ならそちらを選んでも構いません)。
  2. Do you want to enable Server-Side Rendering (SSR) and Static Site Generation (SSG/Prerendering)? — SSR/SSG を有効にするか聞かれます。基礎学習段階では No で答えておいてください。後で必要になったらオプションで追加できます。

質問が終わると Angular CLI がフォルダを作り、依存関係まで自動的にインストールしてくれます。時間が少しかかることがあるので、お茶でも一杯飲んできても構いません。

インストールが終わったら作られたフォルダ構造を見てみます。

my-app/
my-app/
├── node_modules/        ← インストールされたライブラリ
├── public/              ← 静的ファイル (favicon など)
├── src/                 ← 私たちが書くコード
│   ├── app/
│   │   ├── app.component.ts    ← ルートコンポーネント (TS)
│   │   ├── app.component.html  ← ルートコンポーネント (テンプレート)
│   │   ├── app.component.css   ← ルートコンポーネント (スタイル)
│   │   ├── app.config.ts       ← アプリ設定 (ルーティング、provider など)
│   │   └── app.routes.ts       ← ルーティング定義
│   ├── index.html       ← アプリが注入される HTML
│   ├── main.ts          ← アプリのエントリポイント (bootstrap)
│   └── styles.css       ← グローバルスタイル
├── angular.json         ← Angular CLI 設定
├── package.json         ← プロジェクト情報と依存関係リスト
└── tsconfig.json        ← TypeScript 設定

今の段階でもっとも重要なフォルダは src/app/ です。私たちが作るコンポーネントはすべてこの中に入ります。

開発サーバーの起動 #

これでプロジェクトフォルダに入って開発サーバーを立ち上げてみます。

開発サーバー起動
cd my-app
ng serve

次のような出力が見えれば成功です。

実行結果
  ➜  Local:   http://localhost:4200/
  ➜  press h + enter to show help

ブラウザを開いて http://localhost:4200 にアクセスしてみます。Angular ロゴと一緒にウェルカム画面が見えればすべて正常です。

この状態で src/app/app.component.html のテキストを少し変えて保存してみてください。リロードしなくてもブラウザの画面が即座に更新されます。これがまさに HMR (Hot Module Replacement) — 変更された部分だけリアルタイムに描き直してくれる開発機能です。

ヒント
開発サーバーを終了するにはターミナルで Ctrl + C を押します。再起動するときは同じフォルダで ng serve を実行すれば構いません。ポートを変えたければ ng serve --port 4300 のようにオプションを与えれば構いません。

コンポーネント 1 つの形 #

これで本題です。Angular のコンポーネントは通常 3 つのファイルが 1 セット で動きます。

  • app.component.ts — コンポーネントのクラス (TypeScript)
  • app.component.html — 画面に描くテンプレート
  • app.component.css — このコンポーネントだけに適用されるスタイル

src/app/app.component.ts ファイルを開いてみると、次のようなコードが見えるはずです。

src/app/app.component.ts
import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [RouterOutlet],
  templateUrl: './app.component.html',
  styleUrl: './app.component.css',
})
export class AppComponent {
  title = 'my-app';
}

最初に見ると馴染みがないかもしれませんが、1 行ずつ分解してみると意外に単純です。

  • @Component({...}) — このクラスを「Angular コンポーネントにする」と宣言する デコレータ (decorator) です。その下の AppComponent クラスにメタデータを付ける役割をします。
  • selector: 'app-root' — このコンポーネントを HTML から呼ぶときに使う タグ名 です。<app-root></app-root> として使うことになります。
  • standalone: true — このコンポーネントが Standalone Component であるという意味です。以前はコンポーネントを NgModule で束ねる必要がありましたが、モダン Angular ではモジュールなしでもコンポーネントが独立して動作します。
  • imports: [...] — このコンポーネントのテンプレートで使う他のコンポーネントやディレクティブを予め登録しておくところです。上の例ではルーティングに使う RouterOutlet を登録してあります。
  • templateUrl / styleUrl — テンプレートとスタイルファイルのパスです。短いコンポーネントなら別ファイルなしで template: '<h1>...</h1>' のようにインラインで書くこともできます。
  • export class AppComponent — 実際のコンポーネントの本体。データ (クラスフィールド) と動作 (メソッド) が入るところです。

簡単に例えると @Component「このクラスがどんな画面の断片かを説明するラベル」、その下のクラスは 「その断片の頭脳」 です。

補間 (Interpolation) #

クラスに定義したデータをテンプレートに表示するには 補間 (interpolation) を使います。上のコードで title = 'my-app' というフィールドを作ってあるのが見えるはずです。この値を画面に表示してみます。

src/app/app.component.html ファイルを開いて内容をすべて消した後、次のように書きます。

src/app/app.component.html
<h1>こんにちは、{{ title }}!</h1>
<p>私の最初の Angular アプリです。</p>

保存するとブラウザに「こんにちは、my-app!」が表示されます。二重中括弧 ({{ }}) の中にコンポーネントクラスのプロパティを書くとその値が画面に出力されます。これが補間です。

中括弧の中には単純なプロパティだけでなく、簡単な式も入れられます。

src/app/app.component.html
<h1>こんにちは、{{ title.toUpperCase() }}!</h1>
<p>1 + 2 = {{ 1 + 2 }}</p>

ただしテンプレートの式の中にあまり複雑なロジックを入れないほうが良いです。複雑な計算はクラスのメソッドやゲッター (getter) に切り出しておき、テンプレートではその結果だけを呼び出すスタイルで書くのが保守に良いです。

新しいコンポーネントを作る #

ルートコンポーネント (AppComponent) 1 つだけでアプリ全体を作ることはできません。画面を小さな断片に分割して、各断片を別々のコンポーネントとして作って組み立てるのが Angular (そしてすべてのコンポーネントベースフレームワーク) の基本的な考え方です。

新しいコンポーネントは Angular CLI で作ります。

新しいコンポーネントの作成
ng generate component user-card

長く書くのが面倒なら短縮形もあります。

新しいコンポーネントの作成 (短縮形)
ng g c user-card

コマンドを実行すると src/app/user-card/ フォルダの中に次のファイルが自動的に作られます。

user-card/
src/app/user-card/
├── user-card.component.ts
├── user-card.component.html
├── user-card.component.css
└── user-card.component.spec.ts   ← テストファイル

user-card.component.ts を開いてみると、先ほど見た AppComponent とほぼ同じ形のコードが入っているのが分かります。

src/app/user-card/user-card.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-user-card',
  standalone: true,
  imports: [],
  templateUrl: './user-card.component.html',
  styleUrl: './user-card.component.css',
})
export class UserCardComponent {
  name = 'カーティス';
  role = 'フロントエンド開発者';
}

namerole フィールドを直接追加してみました。これでテンプレートを書きます。

src/app/user-card/user-card.component.html
<div class="card">
  <h2>{{ name }}</h2>
  <p>{{ role }}</p>
</div>

スタイルも少し当ててみます。

src/app/user-card/user-card.component.css
.card {
  border: 1px solid #ddd;
  border-radius: 8px;
  padding: 16px;
  width: 240px;
}

このコンポーネントの selector は app-user-card です。つまり、HTML のどこかに <app-user-card></app-user-card> タグを入れるとこのコンポーネントがそこに描画されます。

コンポーネントの組み立て #

これで作っておいた UserCardComponent をルートコンポーネントである AppComponent に差し込んでみましょう。2 つのステップが必要です。

まず親コンポーネントの imports 配列に子コンポーネントを登録します。Standalone コンポーネントは NgModule がない代わりに、使うコンポーネントを明示的に import しなければなりません

src/app/app.component.ts
import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { UserCardComponent } from './user-card/user-card.component';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [RouterOutlet, UserCardComponent],
  templateUrl: './app.component.html',
  styleUrl: './app.component.css',
})
export class AppComponent {
  title = 'my-app';
}

次に親テンプレートで子の selector を使います。

src/app/app.component.html
<h1>こんにちは、{{ title }}!</h1>

<app-user-card></app-user-card>
<app-user-card></app-user-card>

保存すると UserCard カードが 2 つ画面に描画されるのが見えます。このようにコンポーネントはまるでレゴブロックのように他のコンポーネントのテンプレートの中に差し込むことができ、自分自身を他のところで何度も再利用できます。

ヒント
「なぜ毎回 imports に登録しないといけないの?」という疑問が湧くかもしれません。Standalone コンポーネントは NgModule のような巨大な登録簿がないので、各コンポーネントが 自分が必要なものだけを明示的に持ってくる 構造です。最初は煩わしく見えますが、コンポーネント単位で依存関係が明確になるためツリーシェイキングとバンドル最適化に大きな利点があります。

もちろん今は 2 つのカードが同じデータを表示しているという限界があります。カードごとに異なる人の情報を表示するためには親から子へデータを 渡せる ようにする必要がありますが、この部分は次回扱います。

まとめ #

今回の記事では Node.js と Angular CLI をインストールし、ng new で最初のプロジェクトを作り、@Component デコレータの構造を見てきました。そして補間 ({{ }}) でクラスデータを画面に表示し、ng generate component で新しいコンポーネントを作って親テンプレートに差し込むところまでやってみました。

ここまでの内容だけでも Angular アプリがどのようにコンポーネント単位で組み立てられるかの大きな絵が掴めたはずです。次回の「Angular基礎 #3 データバインディングとイベント」では、親から子へデータを渡す プロパティバインディング ([name]="...") と、ユーザーのクリックのようなイベントを処理する イベントバインディング ((click)="...") を本格的に扱っていきます。

X