【初心者必見】Angular入門:開発環境構築から基本操作まで完全ガイド
はじめに
Web開発の世界は日々進化しており、数多くのフレームワークやライブラリが登場しています。その中でも、Googleによって開発・メンテナンスされている「Angular」は、大規模なエンタープライズアプリケーション開発から、高機能なシングルページアプリケーション(SPA)まで、幅広い用途で利用されている強力なフレームワークです。
しかし、「Angular」と聞くと、「学習コストが高い」「TypeScriptが難しそう」といったイメージを持つ方もいるかもしれません。確かに、他のフレームワークと比較すると、最初に学ぶべき概念が多いのは事実です。ですが、一度その基本を理解してしまえば、Angularが提供する堅牢な構造と豊富な機能が、あなたの開発を強力にサポートしてくれることを実感できるでしょう。
このガイドは、Angularをゼロから学びたいと考えている初心者の方を対象としています。開発環境の構築から、Angularアプリケーションの基本的な構成要素、そして実際のアプリケーション開発に役立つ操作までを、ステップバイステップで丁寧に解説していきます。この記事を読み終える頃には、あなたは自信を持ってAngularアプリケーションを開発できるようになっているはずです。
Angularとは何か?
Angularは、TypeScriptベースのオープンソースなフロントエンドWebアプリケーションフレームワークです。動的でインタラクティブなシングルページアプリケーション(SPA)を構築するために設計されています。
- SPA(Single Page Application): 従来のWebサイトのようにページ遷移ごとに全ページを読み込むのではなく、最初に一度だけ必要なリソースを読み込み、その後の操作はJavaScriptによって動的にコンテンツを書き換えることで、高速かつシームレスなユーザー体験を提供します。
- TypeScriptベース: JavaScriptに静的型付けの概念を導入したTypeScriptを採用しているため、大規模なアプリケーション開発においてコードの可読性や保守性を高め、エラーを早期に発見するのに役立ちます。
- コンポーネント指向: アプリケーションを再利用可能な小さな部品(コンポーネント)の集合として構築します。これにより、開発効率が向上し、コードの管理が容易になります。
- Googleによるサポート: Googleが開発・メンテナンスしており、安定性と長期的なサポートが保証されています。
なぜAngularを学ぶのか?
- 大規模開発への適応性: 強固なアーキテクチャと厳格な型システムにより、複数の開発者が関わる大規模プロジェクトでも高い保守性とスケーラビリティを維持できます。
- 豊富な機能とエコシステム: ルーティング、HTTP通信、フォーム管理、テストツールなど、アプリケーション開発に必要な機能の多くがフレームワーク内に標準で組み込まれています。また、Angular Materialのような公式UIライブラリも充実しています。
- パフォーマンス: Angularは、変更検知の最適化やレンダリングの効率化など、高パフォーマンスなアプリケーションを実現するための多くの内部的な最適化が施されています。
- コミュニティと情報: 世界中に多くの開発者がおり、公式ドキュメントも非常に充実しています。困ったときには、Stack Overflowや各種フォーラムで多くの情報を得ることができます。
この記事で学ぶこと
- Angular開発に必要な事前知識(TypeScript、Node.js、CLIなど)
- Angular開発環境の構築手順
- Angular CLIを使ったプロジェクトの作成と実行
- Angularアプリケーションの主要な構成要素(コンポーネント、モジュール、サービス、ディレクティブなど)
- データバインディング、ルーティング、フォーム操作、HTTP通信といった基本的な開発手法
- アプリケーションのビルドとテストの基礎
さあ、Angularの世界へ飛び込みましょう!
第1章:Angular開発の準備:概念とツールの理解
Angularアプリケーションを開発する前に、いくつか知っておくべき基本的な概念と、使用するツールについて理解を深めておきましょう。これは、単にコマンドを打ち込むだけでなく、なぜその操作を行うのか、何が起きているのかを理解するための重要なステップです。
1.1 Web開発の基礎知識
Angularはフロントエンドフレームワークであり、Webブラウザ上で動作します。そのため、基本的なWeb技術の知識は不可欠です。
- HTML (HyperText Markup Language): Webページの構造(見出し、段落、画像、リンクなど)を定義するためのマークアップ言語です。Angularでは、コンポーネントの「テンプレート」としてHTMLを使用します。
- CSS (Cascading Style Sheets): Webページの見た目(色、フォント、レイアウトなど)を装飾するためのスタイルシート言語です。Angularでは、コンポーネントごとに独立したCSS(またはSCSS, Lessなど)を適用できます。
- JavaScript: Webページに動的な動き(インタラクティブな要素、データの操作など)を付与するためのプログラミング言語です。Angularの基盤となる言語であり、TypeScriptにコンパイルされた後、ブラウザで実行されます。
- DOM (Document Object Model): HTMLやXMLドキュメントのプログラミングインターフェースです。JavaScriptはDOMを介して、HTML要素の構造、スタイル、内容を変更できます。Angularは直接DOMを操作するのではなく、データバインディングによって効率的にDOMを更新します。
これらの技術はAngular開発の前提知識となりますが、深く知らなくてもこの記事を進めることは可能です。開発を進める中で必要に応じて学習を深めていくと良いでしょう。
1.2 TypeScriptとは?
AngularはJavaScriptではなく、TypeScriptで記述されます。TypeScriptはMicrosoftが開発・提供しているオープンソースのプログラミング言語で、JavaScriptのスーパーセット(上位互換)です。
JavaScriptとの関係
TypeScriptで書かれたコードは、最終的に標準のJavaScriptに「トランスパイル」(変換)されてから、WebブラウザやNode.js環境で実行されます。つまり、有効なJavaScriptコードはすべて有効なTypeScriptコードでもあります。
TypeScriptを使うメリット
-
静的型付け: JavaScriptは動的型付け言語ですが、TypeScriptは変数、関数の引数、戻り値などに型を明示的に指定できます。これにより、開発中に型に関するエラーを検出できるため、実行時エラーを減らし、コードの堅牢性を高めます。特に大規模なアプリケーション開発では、型情報はコードの可読性を向上させ、チーム開発を円滑にします。
“`typescript
// JavaScript (型がないため、実行時にエラーになる可能性がある)
function greet(name) {
return “Hello, ” + name;
}
console.log(greet(123)); // 実行時に “Hello, 123” となるが、意図しない挙動// TypeScript (型指定により、コンパイル時にエラーを検出)
function greetTs(name: string): string {
return “Hello, ” + name;
}
// console.log(greetTs(123)); // エラー: Argument of type ‘number’ is not assignable to parameter of type ‘string’.
console.log(greetTs(“Angular User”)); // “Hello, Angular User”
“`
2. ESNext(最新のJavaScript機能)の早期利用: TypeScriptは、JavaScriptの最新仕様(ECMAScript, 通称ESNext)で提案されている機能(async/await, class, arrow functionsなど)を、それらが広くサポートされる前に利用できるようにします。トランスパイルによって、古いブラウザ環境でも動作するJavaScriptに変換されます。
3. 優れた開発者体験: 型情報があることで、IDE(統合開発環境)のコード補完、リファクタリング、エラーチェックが格段に向上します。VS CodeなどのエディタはTypeScriptとの相性が抜群です。
TypeScriptの基本的な型
number
: 数値 (整数、浮動小数点数)
typescript
let age: number = 30;string
: 文字列
typescript
let name: string = "Alice";boolean
: 真偽値 (true/false)
typescript
let isActive: boolean = true;Array<Type>
またはType[]
: 配列
typescript
let numbers: number[] = [1, 2, 3];
let names: Array<string> = ["Alice", "Bob"];any
: 任意の型。型の安全性を無視したい場合に使用しますが、できるだけ避けるべきです。
typescript
let data: any = "hello";
data = 123;void
: 関数が値を返さない場合
typescript
function logMessage(): void {
console.log("メッセージ");
}null
,undefined
: JavaScriptと同じく、それぞれ「値がないこと」と「未定義」を表します。object
: プリミティブ型ではない任意の型。tuple
: 要素の型と数が固定された配列。
typescript
let x: [string, number];
x = ["hello", 10];enum
: 列挙型。数値のセットにフレンドリーな名前を付けられます。
typescript
enum Color {Red, Green, Blue}
let c: Color = Color.Green; // c は 1
インターフェースとクラス
- インターフェース (Interface): オブジェクトの形状を定義します。型チェックのために使用され、JavaScriptにトランスパイルされる際には消滅します。
typescript
interface User {
id: number;
name: string;
email?: string; // ? はオプションプロパティ
}
let user1: User = { id: 1, name: "Taro" }; - クラス (Class): オブジェクト指向プログラミングの概念で、データ(プロパティ)とそれを操作する関数(メソッド)をカプセル化します。Angularのコンポーネントやサービスはクラスとして定義されます。
typescript
class Person {
name: string;
constructor(name: string) {
this.name = name;
}
greet() {
console.log(`Hello, my name is ${this.name}`);
}
}
let person1 = new Person("Hanako");
person1.greet(); // Hello, my name is Hanako
TypeScriptはAngular開発の根幹をなすため、これらの基本的な概念を抑えておくことが重要です。
1.3 Node.jsとは?
Node.jsは、Google ChromeのJavaScriptエンジン「V8」をベースに構築された、JavaScriptの実行環境です。通常、JavaScriptはWebブラウザ上で動作しますが、Node.jsを使えばサーバーサイドやコマンドラインツールなど、ブラウザ以外の環境でもJavaScriptを実行できるようになります。
npm (Node Package Manager) の役割
Node.jsをインストールすると、自動的に「npm」(Node Package Manager)もインストールされます。npmは、Node.jsプロジェクトで必要なライブラリやツールを管理するためのパッケージマネージャーです。
- パッケージのインストール: 開発に必要な外部ライブラリ(例: Angular CLI、各種ユーティリティライブラリ)を簡単にインストールできます。
- 依存関係の管理: プロジェクトが依存するパッケージとそのバージョンを管理し、複数の開発者間で一貫した開発環境を構築できます。
- スクリプトの実行:
package.json
ファイルに定義されたカスタムスクリプト(例: ビルド、テスト、開発サーバー起動など)を実行できます。
Angular CLIを含む多くの開発ツールがNode.jsとnpmに依存しているため、Angular開発にはNode.jsのインストールが必須です。
1.4 CLI (Command Line Interface) の重要性
CLI(コマンドラインインターフェース)は、テキストベースのコマンドを入力してコンピュータを操作するインターフェースです。GUI(グラフィカルユーザーインターフェース)に慣れていると抵抗があるかもしれませんが、Web開発、特にフレームワークを使った開発ではCLIの利用が非常に多いです。
Angular開発においては、「Angular CLI」という専用のCLIツールが提供されており、プロジェクトの作成、コンポーネントやサービスの生成、アプリケーションのビルド、テストの実行など、開発の様々なタスクを効率的に行うことができます。
基本的なCLI操作
Windowsでは「コマンドプロンプト」または「PowerShell」、macOS/Linuxでは「ターミナル」を使用します。
cd [ディレクトリ名]
: カレントディレクトリを変更します。cd ..
: 一つ上のディレクトリへ移動cd ~
(macOS/Linux): ホームディレクトリへ移動
ls
(macOS/Linux) /dir
(Windows): カレントディレクトリの内容(ファイルやフォルダ)を一覧表示します。mkdir [ディレクトリ名]
: 新しいディレクトリを作成します。rm [ファイル名]
(macOS/Linux) /del [ファイル名]
(Windows): ファイルを削除します。rm -rf [ディレクトリ名]
(macOS/Linux) /rmdir /s /q [ディレクトリ名]
(Windows): ディレクトリとその内容を再帰的に削除します。注意: このコマンドは元に戻せないため、慎重に使用してください。code .
: VS Codeがインストールされていれば、カレントディレクトリをVS Codeで開きます。
Angular CLIのコマンドは、ng
から始まります。例えば、ng new my-app
のように使います。
1.5 VS Codeの準備
Visual Studio Code (VS Code) は、Microsoftが開発した無料のオープンソースなコードエディタです。軽量でありながら強力な機能を持ち、TypeScriptやJavaScript開発に最適化されています。多くの拡張機能があり、Angular開発を非常に快適にしてくれます。
VS Codeのインストール
VS Codeの公式サイトから、ご自身のOSに合ったインストーラをダウンロードしてインストールしてください。
https://code.visualstudio.com/
VS Codeの基本的な使い方
- ファイル/フォルダを開く: 「ファイル」>「フォルダーを開く」または
code .
コマンドでプロジェクトフォルダを開きます。 - 統合ターミナル: VS Code内で直接コマンドを実行できるターミナル機能があります。「表示」>「ターミナル」または
Ctrl+@
(Windows/Linux) /Cmd+@
(macOS) で開きます。 - 拡張機能: 左側のサイドバーにある正方形のアイコン(Extensions)から、様々な拡張機能を検索・インストールできます。
推奨拡張機能
Angular開発をより効率的に進めるために、以下の拡張機能をインストールすることをお勧めします。
- Angular Language Service:
- Angularのテンプレート内でのコード補完、エラーチェック、ナビゲーションを提供します。Angular開発には必須と言える拡張機能です。
- インストール後、VS Codeを再起動すると有効になります。
- Prettier – Code formatter:
- コードを自動的に整形(フォーマット)してくれるツールです。統一されたコードスタイルを保ち、可読性を向上させます。
- 設定(
Ctrl+,
またはCmd+,
> “format on save” で検索)で、「保存時にフォーマットする」を有効にすると便利です。
- ESLint:
- JavaScript/TypeScriptのコード品質をチェックし、潜在的な問題やスタイルガイド違反を検出します。
- AngularプロジェクトにはデフォルトでESLintが設定されていますが、VS Code拡張機能を入れることでエディタ上でリアルタイムにフィードバックが得られます。
これらの概念とツールの準備が整えば、いよいよAngularの開発環境を構築する準備が完了です。
第2章:Angular開発環境の構築
それでは、実際にAngularアプリケーションを開発するための環境を構築していきましょう。主なステップは「Node.jsとnpmのインストール」と「Angular CLIのインストール」の2つです。
2.1 Node.jsとnpmのインストール
Angular CLIはNode.js上で動作するため、まずNode.jsとそのパッケージマネージャーであるnpmをインストールする必要があります。
Node.jsの推奨バージョン
Node.jsにはLTS(Long Term Support)版とCurrent版があります。開発用途では安定しているLTS版を選択するのが一般的です。Angular CLIのバージョンによってサポートするNode.jsのバージョンが異なりますが、最新のLTS版をインストールしておけば、通常は問題ありません。
現在のAngularの最新バージョン(例: v17)では、Node.jsのv18.13.0以上またはv20.9.0以上が推奨されています。
インストール方法
Node.jsの公式サイトからインストーラをダウンロードして実行するのが最も簡単です。
- Node.js 公式サイトにアクセス:
https://nodejs.org/ja/ - LTS版をダウンロード:
通常、左側に表示されている「LTS (推奨版)」のインストーラ(Windows Installer.msi
、macOS Installer.pkg
など)をダウンロードします。 - インストーラを実行:
ダウンロードしたファイルをダブルクリックしてインストーラを実行します。基本的にデフォルト設定のままで「Next」をクリックしていけば問題ありません。「Node.js runtime」「npm package manager」「Online documentation shortcuts」「Add to PATH」が選択されていることを確認してください。
途中で「Tools for Native Modules」というオプションが表示されることがありますが、これは必須ではないためチェックを外しても構いません。必要になった際に別途インストールすることも可能です。
インストール後のバージョン確認
インストールが完了したら、正しくインストールされたかを確認するために、ターミナル(コマンドプロンプト、PowerShell、またはターミナル)を開き、以下のコマンドを実行します。
bash
node -v
npm -v
それぞれのコマンドを実行すると、インストールされたNode.jsとnpmのバージョンが表示されます。例えば、以下のような出力が得られれば成功です。
v20.11.0 // Node.jsのバージョン
10.2.4 // npmのバージョン
【補足:NVM(Node Version Manager)の利用(上級者向け)】
もし複数のNode.jsプロジェクトを扱う予定がある場合や、異なるバージョンのNode.jsを切り替えて使いたい場合は、NVM(Node Version Manager)の導入を検討すると良いでしょう。NVMを使えば、複数のNode.jsバージョンを簡単にインストール・管理・切り替えることができます。ただし、最初は通常のインストーラで十分です。
- nvm (macOS/Linux): https://github.com/nvm-sh/nvm
- nvm-windows: https://github.com/coreybutler/nvm-windows
2.2 Angular CLIのインストール
Node.jsとnpmが利用できるようになったら、次にAngular CLIをグローバルにインストールします。これにより、どのプロジェクトフォルダからでもAngular CLIのコマンドを実行できるようになります。
ターミナルを開き、以下のコマンドを実行してください。
bash
npm install -g @angular/cli
npm install
: パッケージをインストールするコマンドです。-g
: グローバルインストールを意味します。これにより、システム全体でこのパッケージが利用可能になります。@angular/cli
: インストールするAngular CLIパッケージの名前です。
このコマンドは、インターネットからAngular CLIパッケージをダウンロードし、インストールするため、しばらく時間がかかる場合があります。
インストール後のバージョン確認
インストールが完了したら、Angular CLIが正しくインストールされたかを確認します。
bash
ng version
このコマンドを実行すると、Angular CLIのバージョン、Node.jsのバージョン、npmのバージョン、OSの情報などがまとめて表示されます。
“`
Angular CLI: 17.2.1
Node: 20.11.0
Package Manager: npm 10.2.4
OS: win32 x64
Angular: …
…
“`
このような情報が表示されれば、Angular CLIのインストールは成功です。
2.3 開発環境の確認とトラブルシューティング
ここまでの手順で、基本的な開発環境は整っているはずです。しかし、時には予期せぬ問題が発生することもあります。
よくあるエラーとその対処法
'node' is not recognized as an internal or external command...
または'ng' is not recognized...
:- 原因: Node.jsまたはAngular CLIの実行パスが環境変数
PATH
に正しく追加されていない可能性があります。 - 対処法:
- Node.jsインストーラを再実行し、「Add to PATH」オプションが選択されていることを確認します。
- 手動で環境変数
PATH
にNode.jsとnpmの実行ファイルがあるディレクトリ(例:C:\Program Files\nodejs\
やC:\Users\YourUser\AppData\Roaming\npm
)を追加します。 - ターミナルを一度閉じてから再度開いてみてください。
- 原因: Node.jsまたはAngular CLIの実行パスが環境変数
npm ERR! code EPERM
またはnpm ERR! A complete log of this run can be found in...
:- 原因: npmがファイルやディレクトリへの書き込み権限がないために発生します。特にWindowsで多いです。
- 対処法:
- ターミナル(コマンドプロンプトやPowerShell)を「管理者として実行」して、再度
npm install -g @angular/cli
コマンドを実行してみてください。 - アンチウイルスソフトがインストールを妨げている可能性もあります。一時的に無効にして試すか、例外設定を追加します。
- ターミナル(コマンドプロンプトやPowerShell)を「管理者として実行」して、再度
- ネットワークエラー (
npm ERR! network
):- 原因: インターネット接続の問題、プロキシ設定、またはnpmレジストリへのアクセス問題。
- 対処法:
- インターネット接続を確認します。
- 企業ネットワークなどでプロキシを使用している場合は、npmのプロキシ設定を行います。
bash
npm config set proxy http://your.proxy.com:8080
npm config set https-proxy http://your.proxy.com:8080 - npmのキャッシュをクリアしてみます。
bash
npm cache clean --force
- バージョンミスマッチ警告:
- Angular CLIのバージョンとNode.jsのバージョンに互換性がない場合、
ng version
コマンドなどで警告が表示されることがあります。 - 対処法: Angularの公式ドキュメントで、お使いのAngular CLIのバージョンがサポートするNode.jsのバージョンを確認し、必要であればNode.jsをアップデートまたはダウングレードします(NVMが便利です)。
- Angular CLIのバージョンとNode.jsのバージョンに互換性がない場合、
これらの対処法を試しても解決しない場合は、エラーメッセージを正確にコピーしてGoogle検索するのが最も効果的です。多くの場合は同じ問題に直面した開発者がすでに解決策を公開しています。
これで、Angular開発の環境構築は完了です!次の章では、実際にAngularアプリケーションを作成し、動かしてみましょう。
第3章:初めてのAngularアプリケーション作成
開発環境が整ったところで、いよいよAngular CLIを使って初めてのAngularアプリケーションを作成し、起動してみましょう。この章では、Angularプロジェクトの生成から、アプリケーションの実行、そして生成されたファイル構造の概要までを学びます。
3.1 新規プロジェクトの作成
Angular CLIの ng new
コマンドを使って、新しいAngularプロジェクトを作成します。このコマンドは、必要なファイルと設定を自動的に生成し、開発をすぐに始められる状態にしてくれます。
プロジェクト作成コマンド
ターミナルを開き、プロジェクトを作成したいディレクトリに移動してから、以下のコマンドを実行します。
bash
ng new my-first-angular-app
ng new
: 新しいAngularワークスペースとアプリケーションを作成するコマンドです。my-first-angular-app
: 作成するプロジェクトの名前です。任意の名前を付けることができます。
このコマンドを実行すると、Angular CLIがいくつか質問をしてきます。
? Would you like to add Angular routing? (Y/n)
: Angularアプリケーションにルーティング機能を追加するかどうかを尋ねられます。Webアプリケーションでは複数のページを持つのが一般的であり、ルーティングは必須の機能なので、Y
(Yes) を入力してEnterを押しましょう。? Which stylesheet format would you like to use? (Use arrow keys)
: 使用したいスタイルシートの形式を選択します。CSS
: 標準のCSSSCSS
(Sass): CSSのプリプロセッサ。機能拡張や記述効率の向上が図れます。Sass
: SCSSと似ていますが、異なる記法です。Less
: SCSS/Sassと同様のCSSプリプロセッサ。Stylus
: SCSS/Sass/Lessと同様のCSSプリプロセッサ。
特にこだわりがなければ、まずは最も基本的なCSS
を選択してEnterを押しましょう。SCSSは多くのプロジェクトで利用されていますが、後から変更することも可能です。
これらの質問に答えると、Angular CLIがプロジェクトのファイルを生成し、必要なnpmパッケージをインストールし始めます。このプロセスには数分かかる場合があります。
完了すると、以下のようなメッセージが表示されるはずです。
CREATE my-first-angular-app/angular.json (3256 bytes)
CREATE my-first-angular-app/package.json (1088 bytes)
...
✔ Packages installed successfully.
Successfully initialized git.
これで、my-first-angular-app
という新しいディレクトリが作成され、その中にAngularプロジェクトのファイルがすべて格納されています。
生成されるファイルとフォルダの概要
生成された my-first-angular-app
ディレクトリの中身を簡単に見てみましょう。
my-first-angular-app/
├── .angular/ # Angular CLIのキャッシュなど
├── .vscode/ # VS Codeの設定ファイル
├── node_modules/ # npmパッケージがインストールされるディレクトリ
├── src/ # アプリケーションのソースコード
│ ├── app/ # アプリケーションの主要なロジックとコンポーネント
│ │ ├── app.component.css
│ │ ├── app.component.html
│ │ ├── app.component.spec.ts
│ │ ├── app.component.ts
│ │ └── app.module.ts
│ │ └── app-routing.module.ts # ルーティングを選択した場合
│ ├── assets/ # 画像やフォントなどの静的ファイル
│ ├── environments/ # 環境変数設定(開発用、本番用など)
│ ├── favicon.ico
│ ├── index.html # アプリケーションのエントリポイントとなるHTMLファイル
│ ├── main.ts # アプリケーションの起動スクリプト
│ ├── polyfills.ts # ブラウザ互換性維持のためのポリフィル
│ └── styles.css # グローバルスタイルシート
├── .browserslistrc # サポートするブラウザのリスト
├── .editorconfig # エディタのコードスタイル設定
├── .gitignore # Gitで管理しないファイル・ディレクトリ
├── angular.json # Angularワークスペースの設定ファイル
├── karma.conf.js # ユニットテストの設定ファイル
├── package.json # プロジェクトのメタデータと依存関係を定義
├── tsconfig.app.json # アプリケーションのTypeScript設定
├── tsconfig.json # ワークスペース全体のTypeScript設定
├── tsconfig.spec.json # テストのTypeScript設定
└── tsconfig.lib.json # ライブラリのTypeScript設定 (新しいプロジェクトにはない場合も)
└── README.md # プロジェクトのREADMEファイル
src/
: 実際に開発を行うほとんどのファイルはこの中にあります。特にsrc/app/
ディレクトリは、アプリケーションの主要なコンポーネント、モジュール、サービスが配置される場所です。node_modules/
: プロジェクトが依存するすべてのnpmパッケージが格納されます。このディレクトリは非常に大きくなるため、Gitで管理する際には.gitignore
に含まれます。angular.json
: Angularワークスペース全体の重要な設定ファイルです。ビルド設定、テスト設定、スタイルシートの設定などが記述されています。package.json
: プロジェクトの名前、バージョン、スクリプト、そして開発依存関係(devDependencies
)や実行時依存関係(dependencies
)など、npmパッケージに関する情報が記述されています。
3.2 アプリケーションの実行
プロジェクトが作成されたら、いよいよ開発サーバーを起動して、ブラウザでアプリケーションを確認してみましょう。
プロジェクトディレクトリへの移動
まず、作成したプロジェクトのルートディレクトリに移動します。
bash
cd my-first-angular-app
開発サーバーの起動
次に、Angular CLIの ng serve
コマンドを実行します。
bash
ng serve
このコマンドを実行すると、Angular CLIはアプリケーションをコンパイルし、開発サーバーを起動します。コンパイルが成功すると、以下のようなメッセージが表示されます。
“`
✔ Compiled successfully.
** Angular Live Development Server is listening on localhost:4200, open your browser on http://localhost:4200/ **
√ Compiled successfully.
“`
このメッセージは、アプリケーションが http://localhost:4200/
で利用可能であることを示しています。
ブラウザでの確認
Webブラウザを開き、アドレスバーに http://localhost:4200/
と入力してアクセスしてください。
Angularのロゴと「my-first-angular-app app is running!」のようなメッセージが表示されたページが見えるはずです。
このページは、Angularによって自動生成された初期のアプリケーションです。
ng serve
は、ファイルの変更を監視(watch)し、コードを保存するたびに自動的にアプリケーションを再コンパイルし、ブラウザをリロードする「ライブリロード」機能も提供しています。これにより、変更を即座に確認しながら開発を進めることができます。
VS Codeの統合ターミナルで ng serve
を実行している間は、そのターミナルは占有されます。新しいコマンドを実行したい場合は、別のターミナルタブを開くか、Ctrl+C
(Windows/Linux) / Cmd+C
(macOS) でサーバーを停止します。
3.3 開発サーバーのオプション
ng serve
コマンドには、便利なオプションがいくつかあります。
--open
または-o
: 開発サーバーの起動後、自動的にWebブラウザを開きます。
bash
ng serve --open--port [ポート番号]
: 開発サーバーが使用するポート番号を指定します。デフォルトは4200
です。
bash
ng serve --port 8080--host [ホスト名]
: サーバーがリッスンするホスト名を指定します。デフォルトはlocalhost
です。0.0.0.0
を指定すると、ネットワーク内の他のデバイスからアクセスできるようになります。
bash
ng serve --host 0.0.0.0--configuration=[環境名]
または-c=[環境名]
: ビルド設定ファイルを指定します(例:--configuration=production
で本番用ビルド)。
bash
ng serve --configuration=production
これらのオプションを組み合わせて、開発のニーズに合わせてサーバーを起動できます。
これで、最初のAngularアプリケーションが作成され、起動できました。次の章では、Angularアプリケーションを構成する主要な要素について詳しく見ていき、実際にコードを書いてアプリケーションを変更していきます。
第4章:Angularアプリケーションの基本構造と構成要素
Angularアプリケーションは、特定の構造とルールに基づいて構築されています。主要な構成要素である「コンポーネント」「モジュール」「テンプレート」「ディレクティブ」「サービス」を理解することは、Angular開発の根幹をなします。この章では、それぞれの役割と関係性について詳しく解説します。
4.1 コンポーネントとは?
Angularアプリケーションは、UI(ユーザーインターフェース)を構成する小さな自己完結型のブロックである「コンポーネント」の集合体です。コンポーネントは、アプリケーションの最小単位であり、以下の3つの要素から構成されます。
- テンプレート (Template): コンポーネントのUIを定義するHTMLコードです。
- クラス (Class): コンポーネントのロジック(データ、メソッド、ライフサイクル)を定義するTypeScriptコードです。
- スタイル (Style): コンポーネントの見た目を定義するCSSコードです。
これら3つの要素は、@Component
デコレータによって関連付けられます。
@Component
デコレータ
@Component
デコレータは、TypeScriptのクラスをAngularコンポーネントとして認識させるためのメタデータを提供します。
src/app/app.component.ts
ファイルを見てみましょう。
“`typescript
// app.component.ts
import { Component } from ‘@angular/core’; // Componentデコレータをインポート
@Component({
selector: ‘app-root’, // (1) HTML要素として使うセレクタ名
templateUrl: ‘./app.component.html’, // (2) テンプレートHTMLファイルのパス
styleUrls: [‘./app.component.css’] // (3) スタイルシートファイルのパスの配列
})
export class AppComponent { // (4) コンポーネントのロジックを記述するクラス
title = ‘my-first-angular-app’; // (5) プロパティ
}
“`
selector
: このコンポーネントをHTMLテンプレート内で参照する際に使用するカスタムタグ名です。例えば、app-root
コンポーネントはindex.html
の<app-root></app-root>
というタグで利用されています。templateUrl
: コンポーネントのHTMLテンプレートファイルへの相対パスを指定します。インラインでHTMLを書く場合はtemplate: \
Hello
`
のように
template` プロパティを使用します。styleUrls
: コンポーネントに適用するCSS(またはSCSSなど)ファイルへの相対パスの配列を指定します。複数のスタイルシートを適用できます。インラインでCSSを書く場合はstyles: [\
h1 { color: blue; }`]のように
styles` プロパティを使用します。export class AppComponent
: コンポーネントのロジックを記述するTypeScriptクラスです。このクラス内のプロパティやメソッドが、テンプレートから利用できます。title = 'my-first-angular-app';
: クラスのプロパティです。このプロパティの値は、テンプレート内でデータバインディングによって表示されます。
コンポーネントのライフサイクル
Angularコンポーネントは、生成、初期化、データ変更、破棄といった一連のライフサイクルを持っています。これらの特定のタイミングで実行されるフックメソッドが提供されています。
例えば、OnInit
はコンポーネントが初期化された直後に実行されるフックです。
“`typescript
// app.component.ts
import { Component, OnInit } from ‘@angular/core’;
@Component({
selector: ‘app-root’,
templateUrl: ‘./app.component.html’,
styleUrls: [‘./app.component.css’]
})
export class AppComponent implements OnInit { // OnInitインターフェースを実装
title = ‘my-first-angular-app’;
constructor() {
console.log(‘AppComponent constructor’); // コンポーネントインスタンス生成時
}
ngOnInit() { // 初期化フック
console.log(‘AppComponent initialized’);
// ここで初期データのロードなどを行う
}
}
“`
OnInit
の他にも OnDestroy
(コンポーネントが破棄される前)、DoCheck
(変更検知が実行されるたび)など、様々なライフサイクルフックがあります。
4.2 モジュールとは?
Angularアプリケーションは、コンポーネントだけでなく、「モジュール」という単位でも構成されます。モジュールは、関連するコンポーネント、サービス、ディレクティブ、パイプなどをグループ化し、アプリケーションを構造化するための仕組みです。
@NgModule
デコレータ
@NgModule
デコレータは、TypeScriptのクラスをAngularモジュールとして認識させるためのメタデータを提供します。
src/app/app.module.ts
ファイルを見てみましょう。これはアプリケーションの「ルートモジュール」です。
“`typescript
// app.module.ts
import { NgModule } from ‘@angular/core’;
import { BrowserModule } from ‘@angular/platform-browser’; // ブラウザアプリケーションで必須
import { AppRoutingModule } from ‘./app-routing.module’; // ルーティングモジュール
import { AppComponent } from ‘./app.component’; // ルートコンポーネント
@NgModule({
declarations: [ // (1) このモジュールに属するコンポーネント、ディレクティブ、パイプ
AppComponent
],
imports: [ // (2) このモジュールが依存する他のAngularモジュール
BrowserModule,
AppRoutingModule
],
providers: [], // (3) このモジュールで提供されるサービス
bootstrap: [AppComponent] // (4) アプリケーション起動時にロードされるルートコンポーネント
})
export class AppModule { } // モジュールを定義するクラス
“`
declarations
: このモジュールが所有するコンポーネント、ディレクティブ、パイプを宣言します。新しいコンポーネントを作成すると、ここに自動的に追加されます。imports
: このモジュールが依存する他のAngularモジュール(例:BrowserModule
、FormsModule
、HttpClientModule
など)をインポートします。これにより、インポートしたモジュールが提供する機能をこのモジュール内で利用できるようになります。providers
: サービス(後述)を登録し、アプリケーション全体で利用可能にします。ここで登録されたサービスは、依存性の注入(DI)メカニズムを通じて、必要なコンポーネントやサービスに提供されます。bootstrap
: アプリケーション起動時に、最初にロードされるルートコンポーネントを指定します。これはルートモジュール(AppModule
)のみで設定します。
ルートモジュールとフィーチャーモジュール
- ルートモジュール (
AppModule
): アプリケーション全体のエントリポイントとなるモジュールです。通常、アプリケーションにつき一つだけ存在します。 - フィーチャーモジュール: アプリケーションの特定の機能(例: ユーザー管理、商品一覧、認証など)をまとめたモジュールです。アプリケーションが大規模になるにつれて、フィーチャーモジュールに分割することで、コードの整理、遅延ロードによるパフォーマンス向上などが図れます。
4.3 テンプレート(HTML)とデータバインディング
Angularのテンプレートは、標準のHTMLを拡張したもので、コンポーネントのクラスとUIを連携させるための強力な機能「データバインディング」を提供します。
データバインディングとは?
データバインディングは、コンポーネントのTypeScriptクラス内のデータと、そのコンポーネントのHTMLテンプレート内のUI要素を同期させる仕組みです。これにより、DOMを直接操作することなく、動的なUIを簡単に構築できます。
種類
Angularには主に4つのデータバインディング方式があります。
-
インターポレーション (Interpolation)
{{ }}
:- コンポーネントのプロパティ値をHTMLに表示します。
- One-way Data Binding (データはコンポーネントからテンプレートへ)。
html
<!-- app.component.html -->
<h1>{{ title }}</h1>
<p>現在の値: {{ counter }}</p>
typescript
// app.component.ts
title = 'Welcome to Angular';
counter = 0;
ブラウザには「Welcome to Angular」と「現在の値: 0」が表示されます。
-
プロパティバインディング (Property Binding)
[ ]
:- HTML要素のプロパティ(属性)にコンポーネントのプロパティ値をバインドします。
- One-way Data Binding (データはコンポーネントからテンプレートへ)。
html
<!-- app.component.html -->
<img [src]="imageUrl" [alt]="imageAlt" [disabled]="isButtonDisabled">
<button [disabled]="isButtonDisabled">クリック</button>
typescript
// app.component.ts
imageUrl = 'assets/logo.png';
imageAlt = 'Angular Logo';
isButtonDisabled = true;
isButtonDisabled
がtrue
の場合、ボタンは無効化されます。
-
イベントバインディング (Event Binding)
( )
:- HTML要素で発生したイベント(クリック、入力など)を検知し、コンポーネントのメソッドを実行します。
- One-way Data Binding (データはテンプレートからコンポーネントへ)。
html
<!-- app.component.html -->
<button (click)="incrementCounter()">カウントアップ</button>
typescript
// app.component.ts
counter = 0;
incrementCounter() {
this.counter++;
console.log('Counter:', this.counter);
}
ボタンをクリックするたびにincrementCounter
メソッドが実行され、counter
の値が増加します。
-
双方向データバインディング (Two-way Data Binding)
[(ngModel)]
:- プロパティバインディングとイベントバインディングを組み合わせたもので、フォーム要素でよく使われます。
- データの変更がコンポーネントからテンプレートへ、テンプレートからコンポーネントへ双方向に同期されます。
- 注意:
[(ngModel)]
を使うには、AppModule
にFormsModule
をインポートする必要があります。
typescript
// src/app/app.module.ts
import { FormsModule } from '@angular/forms'; // 追加
// ...
@NgModule({
// ...
imports: [
BrowserModule,
AppRoutingModule,
FormsModule // ここに追加
],
// ...
})
export class AppModule { }
html
<!-- app.component.html -->
<input type="text" [(ngModel)]="userName">
<p>入力された名前: {{ userName }}</p>
typescript
// app.component.ts
userName: string = '';
入力フィールドに何か入力すると、即座に下のp
タグの表示が更新されます。
4.4 ディレクティブとは?
ディレクティブは、DOM要素に特定の振る舞いや構造を追加するものです。コンポーネントも一種のディレクティブ(コンポーネントディレクティブ)ですが、Angularには大きく分けて2種類のディレクティブがあります。
-
構造ディレクティブ (Structural Directives):
- DOMの構造(要素の追加、削除、置き換え)を変更します。
-
通常、アスタリスク
*
をプレフィックスとして使用します。 -
*ngIf
: 条件に基づいて要素をDOMに追加したり削除したりします。
html
<p *ngIf="showContent">このコンテンツは表示されます。</p>
<p *ngIf="!showContent">このコンテンツは表示されません。</p>
typescript
showContent = true; -
*ngFor
: 配列を反復処理し、各アイテムに対して要素を繰り返し描画します。
html
<ul>
<li *ngFor="let item of items; let i = index;">
{{ i + 1 }}: {{ item }}
</li>
</ul>
typescript
items = ['Apple', 'Banana', 'Cherry']; -
[ngSwitch]
(と*ngSwitchCase
,*ngSwitchDefault
): 複数の条件に基づいて表示する要素を切り替えます。
html
<div [ngSwitch]="selectedValue">
<p *ngSwitchCase="'optionA'">Option Aが選択されました。</p>
<p *ngSwitchCase="'optionB'">Option Bが選択されました。</p>
<p *ngSwitchDefault>何も選択されていません。</p>
</div>
typescript
selectedValue = 'optionA';
-
属性ディレクティブ (Attribute Directives):
- 既存のDOM要素の見た目や振る舞いを変更します(属性を追加・変更するイメージ)。
-
アスタリスクは付けません。
-
[ngClass]
: オブジェクトまたは配列に基づいてCSSクラスを動的に追加・削除します。
html
<p [ngClass]="{ 'highlight': isHighlighted, 'bold-text': true }">
このテキストのスタイルは動的に変わります。
</p>
typescript
isHighlighted = true; -
[ngStyle]
: オブジェクトに基づいてCSSスタイルを動的に適用します。
html
<p [ngStyle]="{'color': textColor, 'font-size.px': fontSize}">
このテキストのスタイルも動的に変わります。
</p>
typescript
textColor = 'blue';
fontSize = 20;
カスタムディレクティブの概要
自分でディレクティブを作成することも可能です。例えば、特定の要素にホバーしたときに背景色を変えるようなディレクティブを独自に定義できます。カスタムディレクティブは ng generate directive MyHighlight
のようにCLIで生成します。
4.5 サービスと依存性の注入(DI)
アプリケーションが複雑になると、コンポーネント間でデータを共有したり、ビジネスロジック(データの取得、計算、状態管理など)を再利用したりする必要が出てきます。このような場合、「サービス」を使用します。
サービスとは?
- 特定のビジネスロジックやデータ操作(例: ユーザー管理、HTTP通信、ログ記録)をカプセル化したクラスです。
- コンポーネントから独立しており、複数のコンポーネントから共通の機能を利用するために設計されています。
- Angularでは、
@Injectable()
デコレータを付けてサービスとして定義します。
src/app/app.service.ts
のようなファイルでサービスを作成します。
“`typescript
// app.service.ts
import { Injectable } from ‘@angular/core’;
@Injectable({
providedIn: ‘root’ // (1) アプリケーションのどこからでも利用可能にする
})
export class DataService {
private data: string[] = [‘Item 1’, ‘Item 2’];
getData(): string[] {
return this.data;
}
addData(item: string): void {
this.data.push(item);
}
}
“`
@Injectable({ providedIn: 'root' })
: これは、このサービスが「シングルトン」(アプリケーション全体でインスタンスが一つだけ)として提供され、どのモジュールからでも注入できることを示します。Angular 6以降の推奨される方法です。
依存性の注入 (Dependency Injection: DI)
依存性の注入は、サービスやその他の依存オブジェクトを、それらを必要とするコンポーネントやサービスに自動的に提供するデザインパターンです。これにより、コードの再利用性、テストの容易性、保守性が向上します。
AngularのDIシステムは非常に強力で、以下のように使います。
“`typescript
// app.component.ts
import { Component, OnInit } from ‘@angular/core’;
import { DataService } from ‘./data.service’; // (1) サービスをインポート
@Component({
selector: ‘app-root’,
templateUrl: ‘./app.component.html’,
styleUrls: [‘./app.component.css’]
})
export class AppComponent implements OnInit {
items: string[] = [];
constructor(private dataService: DataService) { // (2) コンストラクタでサービスを注入
// コンストラクタでプロパティとして宣言すると、自動的にプライベートプロパティとして割り当てられる
}
ngOnInit() {
this.items = this.dataService.getData(); // (3) 注入されたサービスを使用
}
addNewItem(item: string) {
this.dataService.addData(item);
this.items = this.dataService.getData(); // データを更新
}
}
“`
- サービスのインポート: サービスを使用するコンポーネントで、そのサービスをインポートします。
- コンストラクタインジェクション: コンポーネントのコンストラクタの引数として、必要なサービスの型を宣言します。AngularのDIシステムが、その型のインスタンスを自動的に提供(注入)してくれます。
- 注入されたサービスの使用: コンストラクタで注入されたサービスは、そのコンポーネントのインスタンス変数として利用できます。
DIにより、コンポーネントは特定のサービスの実装に依存せず、必要な機能だけを要求できます。これにより、コンポーネントとサービスの結合度が低くなり、モジュール性が高まります。
この章で学んだコンポーネント、モジュール、テンプレート、ディレクティブ、サービスは、Angularアプリケーションを構築する上での最も基本的なビルディングブロックです。これらを理解し組み合わせることで、複雑なアプリケーションも整理された形で開発できるようになります。
第5章:Angularのルーティング
シングルページアプリケーション(SPA)では、URLの変更に応じて表示されるコンテンツを切り替える「ルーティング」の仕組みが不可欠です。Angularは強力なルーティングモジュールを提供しており、宣言的な方法でアプリケーションのナビゲーションを管理できます。
5.1 ルーティングの基本
Angularのルーティングは、ユーザーがアプリケーション内の特定のURLにアクセスしたときに、どのコンポーネントを表示するかを定義します。
主要な要素
RouterModule
とRoutes
: ルーティング設定の基盤となるモジュールと、ルート定義の配列です。routerLink
ディレクティブ: HTMLテンプレート内でナビゲーションリンクを作成するためのディレクティブです。従来の<a href="...">
の代わりに使います。router-outlet
コンポーネント: ルートによって表示されるコンポーネントが描画されるプレースホルダーです。
プロジェクト作成時にルーティングを追加するオプションを選択した場合、src/app/app-routing.module.ts
というファイルが自動的に生成されます。
“`typescript
// src/app/app-routing.module.ts
import { NgModule } from ‘@angular/core’;
import { RouterModule, Routes } from ‘@angular/router’;
const routes: Routes = []; // (1) ルート定義の配列
@NgModule({
imports: [RouterModule.forRoot(routes)], // (2) ルートモジュールにRouterModuleをインポート
exports: [RouterModule] // (3) RouterModuleを他のモジュールで利用可能にする
})
export class AppRoutingModule { }
“`
const routes: Routes = [];
: ここにアプリケーションのルーティングルールを定義していきます。Routes
型の配列です。RouterModule.forRoot(routes)
: ルートモジュール(AppModule
)で使用するルーティングを設定します。forRoot()
メソッドは、アプリケーションのルートレベルのルーティングを設定するために一度だけ呼び出されます。exports: [RouterModule]
:AppRoutingModule
をインポートする他のモジュール(例えばAppModule
)が、routerLink
などのルーティングディレクティブを利用できるように、RouterModule
をエクスポートします。
そして、src/app/app.module.ts
で AppRoutingModule
がインポートされています。
“`typescript
// src/app/app.module.ts
// …
import { AppRoutingModule } from ‘./app-routing.module’;
@NgModule({
declarations: [
// …
],
imports: [
BrowserModule,
AppRoutingModule // ここでインポートされている
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
“`
5.2 ルートの定義
新しいコンポーネントを作成し、そのコンポーネントに対応するルートを定義してみましょう。
まず、2つの新しいコンポーネントをCLIで生成します。
bash
ng generate component home
ng generate component about
これで src/app/home
と src/app/about
ディレクトリが生成され、それぞれのモジュールにコンポーネントが自動的に登録されます。
次に、src/app/app-routing.module.ts
を開いて、routes
配列にルート定義を追加します。
“`typescript
// src/app/app-routing.module.ts
import { NgModule } from ‘@angular/core’;
import { RouterModule, Routes } from ‘@angular/router’;
import { HomeComponent } from ‘./home/home.component’; // 追加
import { AboutComponent } from ‘./about/about.component’; // 追加
const routes: Routes = [
{ path: ”, component: HomeComponent }, // (1) パスが空の場合は HomeComponent を表示
{ path: ‘home’, component: HomeComponent }, // (2) /home パスに HomeComponent をマッピング
{ path: ‘about’, component: AboutComponent }, // (3) /about パスに AboutComponent をマッピング
{ path: ‘**’, redirectTo: ” } // (4) ワイルドカードルート: マッチしないパスは ‘/’ にリダイレクト
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
“`
{ path: '', component: HomeComponent }
: パスが空(/
)の場合、HomeComponent
を表示します。これはアプリケーションのトップページになります。{ path: 'home', component: HomeComponent }
:/home
というパスにアクセスがあった場合、HomeComponent
を表示します。{ path: 'about', component: AboutComponent }
:/about
というパスにアクセスがあった場合、AboutComponent
を表示します。{ path: '**', redirectTo: '' }
: これは「ワイルドカードルート」と呼ばれ、定義されたどのパスにもマッチしない場合にこのルートが使用されます。ここでは、未知のURLにアクセスがあった場合、ルートパス(/
)にリダイレクトする設定です。ワイルドカードルートは常にルート定義の最後に配置してください。
router-outlet
の配置
最後に、ルートによってレンダリングされるコンポーネントを表示するための router-outlet
を配置します。通常はルートコンポーネントのテンプレート(src/app/app.component.html
)に配置します。
src/app/app.component.html
を開き、既存のAngularの初期コンテンツをすべて削除し、以下のように書き換えてみましょう。
“`html
“`
routerLink
: 指定されたパスにナビゲートします。routerLinkActive="active"
: 現在アクティブなルートに対応するリンクにactive
というCSSクラスを追加します。これにより、ナビゲーションメニューで現在のページをハイライト表示できます。(styles.css
にactive
クラスのスタイルを追加する必要がある)
src/styles.css
に以下を追加して、アクティブなリンクをハイライトしましょう。
“`css
/ src/styles.css /
nav ul {
list-style-type: none;
padding: 0;
}
nav li {
display: inline-block;
margin-right: 10px;
}
nav a {
text-decoration: none;
color: blue;
padding: 5px 10px;
border: 1px solid blue;
border-radius: 5px;
}
nav a.active {
background-color: blue;
color: white;
}
“`
これで、ng serve
でアプリケーションを起動し、ブラウザで /home
や /about
にアクセスしたり、ナビゲーションリンクをクリックしたりすると、対応するコンポーネントのコンテンツが表示されるはずです。
5.3 パラメータ付きルーティング
特定のアイテムの詳細ページなど、動的なデータに基づいてルーティングを行いたい場合があります。そのために、URLパラメータやクエリパラメータを使用します。
URLパラメータの取得
例えば、ユーザーIDに基づいてユーザーの詳細を表示するページを作成する場合を考えます。
まず、ユーザー詳細コンポーネントを作成します。
bash
ng generate component user-detail
次に、app-routing.module.ts
にパラメータを含むルートを定義します。
“`typescript
// src/app/app-routing.module.ts (抜粋)
import { UserDetailComponent } from ‘./user-detail/user-detail.component’; // 追加
const routes: Routes = [
// …既存のルート…
{ path: ‘user/:id’, component: UserDetailComponent }, // ‘:id’ でパラメータを定義
// …
];
“`
user/:id
の :id
がURLパラメータです。
UserDetailComponent
でこのパラメータを取得するには、ActivatedRoute
サービスを依存性の注入によって使用します。
“`typescript
// src/app/user-detail/user-detail.component.ts
import { Component, OnInit } from ‘@angular/core’;
import { ActivatedRoute } from ‘@angular/router’; // ActivatedRouteをインポート
@Component({
selector: ‘app-user-detail’,
templateUrl: ‘./user-detail.component.html’,
styleUrls: [‘./user-detail.component.css’]
})
export class UserDetailComponent implements OnInit {
userId: string | null = null;
constructor(private route: ActivatedRoute) { } // ActivatedRouteを注入
ngOnInit(): void {
// スナップショット方式 (初回ロード時のみ)
// this.userId = this.route.snapshot.paramMap.get(‘id’);
// console.log(‘Snapshot User ID:’, this.userId);
// Observable方式 (ルートパラメータの変更を監視)
this.route.paramMap.subscribe(params => {
this.userId = params.get('id'); // 'id' パラメータを取得
console.log('Observable User ID:', this.userId);
// ここでIDに基づいてユーザーデータをロードする処理などを記述
});
}
}
“`
ActivatedRoute
サービスは、現在のルートに関する情報を提供します。paramMap
はObservable
であり、ルートパラメータが変更されるたびに新しい値を発行します。これにより、同じコンポーネント内でルートパラメータだけが変わった場合(例:/user/1
から/user/2
へ遷移)でも、コンポーネントが再生成されずにデータが更新されるように対応できます。snapshot.paramMap.get('id')
は、ルートが最初にアクティブになったときのパラメータの静的なスナップショットを取得します。
src/app/user-detail/user-detail.component.html
に表示を追加:
“`html
ユーザー詳細ページ
ユーザーID: {{ userId }}
“`
これで、http://localhost:4200/user/123
にアクセスすると、「ユーザーID: 123」と表示されるようになります。
クエリパラメータとフラグメント
-
クエリパラメータ: URLの
?
の後に続くキーと値のペア(例:/search?query=angular&page=1
)。主にフィルタリングやページネーションに使われます。
typescript
// クエリパラメータの取得
this.route.queryParamMap.subscribe(params => {
const query = params.get('query');
const page = params.get('page');
console.log('Query:', query, 'Page:', page);
});
routerLink
でクエリパラメータを渡すにはqueryParams
プロパティを使います。
html
<a [routerLink]="['/search']" [queryParams]="{ query: 'Angular', page: 1 }">検索</a> -
フラグメント: URLの
#
の後に続く文字列(例:/about#section2
)。ページ内の特定の位置にスクロールするために使われます。
typescript
// フラグメントの取得
this.route.fragment.subscribe(fragment => {
console.log('Fragment:', fragment);
});
routerLink
でフラグメントを渡すにはfragment
プロパティを使います。
html
<a [routerLink]="['/about']" fragment="section2">セクション2へ</a>
5.4 ルーティングモジュールの分離
アプリケーションが大きくなると、すべてのルートを AppRoutingModule
に書くのは非効率的になります。関連するルートを「フィーチャーモジュール」として分離し、遅延ロード(Lazy Loading)することで、アプリケーションの初期ロード時間を短縮し、コードの管理を容易にすることができます。
例: AdminModule
を遅延ロードする場合
-
まず、Admin機能用のモジュールとコンポーネントを作成します。
bash
ng generate module admin --route admin --module app
このコマンドはAdminModule
を作成し、そのモジュール内にAdminComponent
を作成し、さらにAppRoutingModule
にadmin
パスでこのモジュールを遅延ロードする設定を追加します。 -
AppRoutingModule
は以下のように更新されます。
typescript
// src/app/app-routing.module.ts (抜粋)
const routes: Routes = [
// ...既存のルート...
{
path: 'admin',
loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule)
}, // 遅延ロードの設定
// ...
];
loadChildren
は、特定のパスにアクセスされたときにのみ、対応するモジュールを非同期でロードするようにAngularに指示します。
この機能は、アプリケーションのパフォーマンス最適化において非常に重要です。
これで、Angularのルーティングの基本的な使い方を習得しました。これにより、複雑なナビゲーションを持つアプリケーションも効率的に構築できるようになります。
第6章:フォームの操作
Webアプリケーションにおいて、ユーザーからの入力を受け付けるフォームは不可欠な要素です。Angularはフォームを扱うための強力な2つのアプローチを提供します。
- テンプレート駆動フォーム (Template-driven forms): HTMLテンプレート内でフォームのロジックとバリデーションを定義します。シンプルで簡単なフォームに適しています。
- リアクティブフォーム (Reactive forms): TypeScriptコードでフォームモデルを構築し、プログラム的にフォームの状態を管理します。より複雑なフォームや動的なフォーム、厳密なバリデーションが必要な場合に推奨されます。
どちらのアプローチも、使用する前にそれぞれ対応するモジュールを AppModule
にインポートする必要があります。
- テンプレート駆動フォーム:
FormsModule
- リアクティブフォーム:
ReactiveFormsModule
6.1 テンプレート駆動フォーム
テンプレート駆動フォームは、HTMLテンプレート内のディレクティブを通じてフォームのロジックを宣言的に記述します。
FormsModule
のインポート
まず、src/app/app.module.ts
に FormsModule
をインポートします。
“`typescript
// src/app/app.module.ts
import { NgModule } from ‘@angular/core’;
import { BrowserModule } from ‘@angular/platform-browser’;
import { FormsModule } from ‘@angular/forms’; // これを追加!
import { AppRoutingModule } from ‘./app-routing.module’;
import { AppComponent } from ‘./app.component’;
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
AppRoutingModule,
FormsModule // ここに追加
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
“`
フォームの作成とデータバインディング
新しいコンポーネントを作成してみましょう。
bash
ng generate component template-form
template-form.component.html
に以下のフォームを追加します。
“`html
テンプレート駆動フォーム
入力されたデータ: {{ model | json }}
“`
template-form.component.ts
に以下のロジックを追加します。
“`typescript
// src/app/template-form/template-form.component.ts
import { Component } from ‘@angular/core’;
import { NgForm } from ‘@angular/forms’; // NgFormをインポート
interface Hero {
name: string;
power: string;
}
@Component({
selector: ‘app-template-form’,
templateUrl: ‘./template-form.component.html’,
styleUrls: [‘./template-form.component.css’]
})
export class TemplateFormComponent {
powers = [‘Flight’, ‘Super Strength’, ‘Telekinesis’, ‘Invisibility’];
model: Hero = { name: ”, power: this.powers[0] }; // 初期値
onSubmit(form: NgForm): void {
console.log(‘フォームが送信されました!’);
console.log(form.value); // フォーム全体の値
console.log(this.model); // ngModelでバインドされたモデル
}
}
“`
#heroForm="ngForm"
: フォーム全体をheroForm
というテンプレート変数として参照できるようにします。ngForm
ディレクティブは、HTMLの<form>
要素に自動的に適用され、フォーム全体のコントロールを管理します。(ngSubmit)="onSubmit(heroForm)"
: フォームの送信イベントをキャッチし、onSubmit
メソッドを実行します。[(ngModel)]="model.name"
: 双方向データバインディングで、入力フィールドとコンポーネントのmodel.name
プロパティを同期します。name="name"
:ngModel
を使用する入力要素には、一意のname
属性が必要です。#name="ngModel"
: 特定の入力フィールド(ここでは名前)をname
というテンプレート変数として参照できるようにします。ngModel
ディレクティブは、個々のフォームコントロールを管理します。
バリデーションとフォームの状態
Angularのテンプレート駆動フォームは、HTML5のバリデーション属性(required
, minlength
, pattern
など)と連携して、フォームコントロールの状態を自動的に追跡します。
required
: HTML5の必須フィールドバリデーション。name.invalid
: コントロールが無効な状態(バリデーションエラーがある)かどうか。name.dirty
: ユーザーがコントロールの値を変更したことがあるか。name.touched
: ユーザーがコントロールを訪れてから離れたことがあるか。name.errors?.['required']
: 特定のバリデーションエラー(ここではrequired
)があるかどうか。heroForm.valid
: フォーム全体が有効な状態かどうか。heroForm.invalid
も利用できます。
これらのプロパティを使って、エラーメッセージの表示や、送信ボタンの有効/無効を制御できます。
最後に、app.component.html
にルーティングを追加して、このフォームを表示できるようにしましょう。
“`html
“`
app-routing.module.ts
にルートを追加します。
“`typescript
// src/app/app-routing.module.ts (抜粋)
import { TemplateFormComponent } from ‘./template-form/template-form.component’; // 追加
const routes: Routes = [
// …
{ path: ‘template-form’, component: TemplateFormComponent }, // 追加
// …
];
“`
6.2 リアクティブフォーム(推奨)
リアクティブフォームは、より強力で柔軟なフォーム管理を提供します。フォームの構造はTypeScriptコードで明示的に定義され、すべてのコントロールの状態はプログラム的にアクセス・操作されます。複雑なフォーム、動的なフォーム、またはカスタムバリデーションが必要な場合に特に推奨されます。
ReactiveFormsModule
のインポート
まず、src/app/app.module.ts
に ReactiveFormsModule
をインポートします。
“`typescript
// src/app/app.module.ts
import { NgModule } from ‘@angular/core’;
import { BrowserModule } from ‘@angular/platform-browser’;
import { ReactiveFormsModule } from ‘@angular/forms’; // これを追加!
import { AppRoutingModule } from ‘./app-routing.module’;
import { AppComponent } from ‘./app.component’;
import { FormsModule } from ‘@angular/forms’; // テンプレート駆動フォームも使うならこれも必要
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
AppRoutingModule,
ReactiveFormsModule, // ここに追加
FormsModule // 必要であれば
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
“`
フォームモデルの構築
新しいコンポーネントを作成します。
bash
ng generate component reactive-form
src/app/reactive-form/reactive-form.component.ts
で FormGroup
と FormControl
を使ってフォームモデルを定義します。
“`typescript
// src/app/reactive-form/reactive-form.component.ts
import { Component, OnInit } from ‘@angular/core’;
import { FormGroup, FormControl, Validators, FormBuilder, FormArray } from ‘@angular/forms’; // 必要なクラスをインポート
@Component({
selector: ‘app-reactive-form’,
templateUrl: ‘./reactive-form.component.html’,
styleUrls: [‘./reactive-form.component.css’]
})
export class ReactiveFormComponent implements OnInit {
userForm!: FormGroup; // FormGroupインスタンス
// FormBuilderを使ってフォームを簡単に構築することもできます
constructor(private fb: FormBuilder) { }
ngOnInit(): void {
// 方法1: FormControlとFormGroupを直接インスタンス化
// this.userForm = new FormGroup({
// ‘firstName’: new FormControl(”, Validators.required), // 初期値とバリデーター
// ‘lastName’: new FormControl(”, Validators.required),
// ‘email’: new FormControl(”, [Validators.required, Validators.email]),
// ‘hobbies’: new FormArray([
// new FormControl(”) // 趣味の初期入力フィールド
// ])
// });
// 方法2: FormBuilderサービスを使用 (より簡潔に記述できる)
this.userForm = this.fb.group({
firstName: ['', Validators.required],
lastName: ['', Validators.required],
email: ['', [Validators.required, Validators.email]],
hobbies: this.fb.array([
this.fb.control('') // FormArray内のFormControl
])
});
// フォームの値の変更を監視 (オプション)
this.userForm.valueChanges.subscribe(value => {
console.log('フォーム値が変更されました:', value);
});
// フォームの状態の変更を監視 (オプション)
this.userForm.statusChanges.subscribe(status => {
console.log('フォームステータスが変更されました:', status); // VALID, INVALID, PENDING
});
}
// hobbies FormArrayへのゲッター
get hobbies() {
return this.userForm.get(‘hobbies’) as FormArray;
}
addHobby() {
this.hobbies.push(this.fb.control(”));
}
removeHobby(index: number) {
this.hobbies.removeAt(index);
}
onSubmit(): void {
if (this.userForm.valid) {
console.log(‘フォームが送信されました!’);
console.log(this.userForm.value); // フォーム全体の値を取得
} else {
console.log(‘フォームに無効な入力があります。’);
// 例: 無効なフィールドをハイライトするなど
this.userForm.markAllAsTouched(); // すべてのフィールドをtouched状態にする (エラー表示のため)
}
}
// 特定のコントロールにアクセスするヘルパー
get firstName() { return this.userForm.get(‘firstName’); }
get lastName() { return this.userForm.get(‘lastName’); }
get email() { return this.userForm.get(‘email’); }
}
“`
FormGroup
: フォームコントロールのグループを定義します。フォーム全体を管理する最上位のオブジェクトです。FormControl
: 単一の入力フィールドを定義します。初期値とバリデーター(Validators.required
など)を指定できます。FormBuilder
:FormGroup
やFormControl
をより簡潔に生成するためのヘルパーサービスです。FormArray
: 動的に増減するフォームコントロールの配列を管理します。趣味の入力フィールドのように、ユーザーが複数追加できるような場合に便利です。
テンプレートとのバインディング
src/app/reactive-form/reactive-form.component.html
に以下のフォームを追加します。
“`html
リアクティブフォーム
フォーム値: {{ userForm.value | json }}
フォーム有効性: {{ userForm.valid }}
“`
[formGroup]="userForm"
: HTMLの<form>
要素を、TypeScriptで定義したFormGroup
インスタンス (userForm
) にバインドします。formControlName="firstName"
: 各入力要素を、対応するFormGroup
内のFormControl
にバインドします。formArrayName="hobbies"
と[formControlName]="i"
:FormArray
とその中の個々のFormControl
をバインドする方法です。
バリデーション
リアクティブフォームでは、バリデーター関数を FormControl
の定義時に指定します。
Validators.required
: 必須入力Validators.email
: 有効なメールアドレス形式Validators.minLength(length)
: 最小文字数Validators.maxLength(length)
: 最大文字数Validators.pattern(regex)
: 正規表現パターン
カスタムバリデーターや非同期バリデーターも簡単に作成・適用できます。
最後に、app.component.html
と app-routing.module.ts
にルーティングを追加して、このフォームを表示できるようにしましょう。
“`html
“`
“`typescript
// src/app/app-routing.module.ts (抜粋)
import { ReactiveFormComponent } from ‘./reactive-form/reactive-form.component’; // 追加
const routes: Routes = [
// …
{ path: ‘reactive-form’, component: ReactiveFormComponent }, // 追加
// …
];
“`
リアクティブフォームは、テンプレート駆動フォームよりも記述量が多くなりますが、その分、プログラムからのコントロールが容易で、複雑なフォームロジックやテストが格段にやりやすくなります。大規模なアプリケーション開発では、リアクティブフォームが強く推奨されます。
第7章:HTTP通信とAPI連携
現代のWebアプリケーションのほとんどは、サーバーからデータを取得したり、サーバーにデータを送信したりするためにAPIと連携します。Angularは、HTTP通信を行うための組み込みモジュール HttpClientModule
を提供しています。
7.1 HttpClientModule
HttpClientModule
は、ブラウザの XMLHttpRequest
インターフェースや Fetch APIの上に構築されており、型付けされたリクエスト/レスポンス、エラーハンドリング、リクエスト/レスポンスインターセプトなど、多くの便利な機能を提供します。
インポート
HttpClientModule
を使用するには、まず src/app/app.module.ts
にインポートする必要があります。
“`typescript
// src/app/app.module.ts
import { NgModule } from ‘@angular/core’;
import { BrowserModule } from ‘@angular/platform-browser’;
import { HttpClientModule } from ‘@angular/common/http’; // これを追加!
// …他のインポート
@NgModule({
declarations: [
// …
],
imports: [
BrowserModule,
AppRoutingModule,
HttpClientModule, // ここに追加
// …他のモジュール
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
“`
7.2 データの取得 (get
)
HTTP通信は、主にサービスで行うのがベストプラクティスです。これにより、コンポーネントからデータ取得ロジックを分離し、再利用性を高めることができます。
ユーザーデータを取得するサービスを作成してみましょう。
bash
ng generate service data
src/app/data.service.ts
を以下のように編集します。今回は JSONPlaceholder という無料のテスト用APIを使用します。
“`typescript
// src/app/data.service.ts
import { Injectable } from ‘@angular/core’;
import { HttpClient, HttpErrorResponse } from ‘@angular/common/http’;
import { Observable, throwError } from ‘rxjs’; // RxJSのObservableとthrowErrorをインポート
import { catchError, retry } from ‘rxjs/operators’; // RxJSのオペレーターをインポート
// 取得するデータの型を定義 (任意だが推奨)
export interface Post {
userId: number;
id: number;
title: string;
body: string;
}
@Injectable({
providedIn: ‘root’
})
export class DataService {
private apiUrl = ‘https://jsonplaceholder.typicode.com/posts’; // APIのエンドポイント
constructor(private http: HttpClient) { } // HttpClientを注入
// 投稿データをすべて取得するメソッド
getPosts(): Observable
return this.http.get
.pipe(
retry(3), // エラー時に3回リトライ
catchError(this.handleError) // エラーハンドリング
);
}
// 特定のIDの投稿データを取得するメソッド
getPostById(id: number): Observable
return this.http.get${this.apiUrl}/${id}
)
.pipe(
catchError(this.handleError)
);
}
// エラーハンドリングの共通処理
private handleError(error: HttpErrorResponse) {
let errorMessage = ‘不明なエラーが発生しました。’;
if (error.error instanceof ErrorEvent) {
// クライアント側またはネットワークエラー
errorMessage = エラー: ${error.error.message}
;
} else {
// バックエンドがエラーコードを返した場合
errorMessage = サーバーエラーコード: ${error.status}, メッセージ: ${error.message}
;
}
console.error(errorMessage);
return throwError(() => new Error(errorMessage)); // エラーを再スロー
}
}
“`
HttpClient
: HTTPリクエストを実行するためのAngularのサービスです。コンストラクタで注入して使用します。get<Post[]>(this.apiUrl)
:get
メソッドはHTTP GETリクエストを送信します。ジェネリクス<Post[]>
を指定することで、返されるデータの型をTypeScriptに伝えます。Observable
:HttpClient
のメソッドは、RxJSのObservable
を返します。Observable
は非同期データストリームを扱うための強力なパターンです。pipe()
: RxJSのオペレーターをチェーンして、Observable
の振る舞いを変更します。retry(3)
: リクエストが失敗した場合に、最大3回リトライします。catchError(this.handleError)
: エラーが発生した場合にhandleError
メソッドを呼び出します。
次に、このサービスを使用してデータを表示するコンポーネントを作成します。
bash
ng generate component posts
src/app/posts/posts.component.ts
を以下のように編集します。
“`typescript
// src/app/posts/posts.component.ts
import { Component, OnInit } from ‘@angular/core’;
import { DataService, Post } from ‘../data.service’; // DataServiceとPostインターフェースをインポート
@Component({
selector: ‘app-posts’,
templateUrl: ‘./posts.component.html’,
styleUrls: [‘./posts.component.css’]
})
export class PostsComponent implements OnInit {
posts: Post[] = [];
errorMessage: string = ”;
constructor(private dataService: DataService) { } // DataServiceを注入
ngOnInit(): void {
this.getPosts();
}
getPosts(): void {
this.dataService.getPosts().subscribe({
next: (data) => { // 成功時のコールバック
this.posts = data;
},
error: (err) => { // エラー時のコールバック
this.errorMessage = err.message;
console.error(‘データ取得エラー:’, err);
},
complete: () => { // 完了時のコールバック
console.log(‘データ取得完了’);
}
});
}
}
“`
subscribe()
:Observable
から値を受け取るためにsubscribe
メソッドを呼び出します。非同期処理なので、データが返ってきたときにnext
コールバックが実行されます。エラーが発生した場合はerror
コールバックが、ストリームが完了した場合はcomplete
コールバックが実行されます。
src/app/posts/posts.component.html
に表示を追加します。
“`html
投稿一覧
- 0″>
-
{{ post.title }}
{{ post.body }}
User ID: {{ post.userId }}
“`
最後に、app.component.html
と app-routing.module.ts
にルーティングを追加します。
“`html
“`
“`typescript
// src/app/app-routing.module.ts (抜粋)
import { PostsComponent } from ‘./posts/posts.component’; // 追加
const routes: Routes = [
// …
{ path: ‘posts’, component: PostsComponent }, // 追加
// …
];
“`
これで、http://localhost:4200/posts
にアクセスすると、JSONPlaceholderから取得した投稿データが表示されるはずです。
7.3 データの送信 (post
, put
, delete
)
HttpClient
は、データの取得だけでなく、サーバーへのデータ送信(作成、更新、削除)のためのメソッドも提供します。
DataService
に追加のメソッドを定義します。
“`typescript
// src/app/data.service.ts (抜粋)
// …
export interface Post { / … / }
@Injectable({
providedIn: ‘root’
})
export class DataService {
private apiUrl = ‘https://jsonplaceholder.typicode.com/posts’;
constructor(private http: HttpClient) { }
// … getPosts, getPostById メソッド …
// 新しい投稿を作成するメソッド
createPost(post: Partial
return this.http.post
.pipe(
catchError(this.handleError)
);
}
// 投稿を更新するメソッド
updatePost(id: number, post: Partial
return this.http.put${this.apiUrl}/${id}
, post)
.pipe(
catchError(this.handleError)
);
}
// 投稿を削除するメソッド
deletePost(id: number): Observable
return this.http.delete${this.apiUrl}/${id}
)
.pipe(
catchError(this.handleError)
);
}
}
“`
そして、これらのメソッドをコンポーネントから呼び出します。
“`typescript
// src/app/posts/posts.component.ts (抜粋)
// …
export class PostsComponent implements OnInit {
// …
createDummyPost(): void {
const newPost: Partial
title: ‘Angularで新しい投稿’,
body: ‘これはテスト投稿です。’,
userId: 1
};
this.dataService.createPost(newPost).subscribe({
next: (post) => {
console.log(‘投稿作成成功:’, post);
// UIを更新する必要があれば、ここでposts配列に追加するなど
this.posts.unshift(post); // 新しい投稿をリストの先頭に追加
},
error: (err) => {
this.errorMessage = err.message;
console.error(‘投稿作成エラー:’, err);
}
});
}
deletePostById(id: number): void {
this.dataService.deletePost(id).subscribe({
next: () => {
console.log(投稿ID ${id} を削除しました。
);
this.posts = this.posts.filter(p => p.id !== id); // UIから削除された投稿を削除
},
error: (err) => {
this.errorMessage = err.message;
console.error(‘投稿削除エラー:’, err);
}
});
}
}
“`
posts.component.html
にボタンを追加して試すことができます。
“`html
投稿一覧
- 0″>
-
{{ post.title }}
{{ post.body }}
User ID: {{ post.userId }}
“`
7.4 RxJSと非同期処理
AngularのHTTP通信は、RxJS(Reactive Extensions for JavaScript)の Observable
を活用しています。Observable
は、時間の経過とともに複数の値を発行できる非同期データソースを表す強力な概念です。
Observable
:HttpClient
のメソッドはObservable
を返します。これは、非同期操作の結果(HTTPレスポンス)を「監視」できるストリームのようなものです。subscribe()
:Observable
が発行する値を受け取るためには、subscribe
メソッドを呼び出す必要があります。subscribe
しないと、HTTPリクエストは実際には送信されません。- オペレーター (
pipe()
):map
,filter
,catchError
,retry
などのRxJSオペレーターをpipe()
メソッドを介して使用することで、Observable
から発行されるデータを変換、フィルタリング、エラー処理、合成など、様々な操作を行うことができます。これにより、複雑な非同期ロジックを宣言的かつクリーンに記述できます。
RxJSは最初は難しく感じるかもしれませんが、Angular開発の重要な部分を占めるため、少しずつ慣れていくことが重要です。
7.5 CORS対策(開発時のプロキシ設定)
異なるオリジン(プロトコル、ドメイン、ポートのいずれかが異なる場合)へのHTTPリクエストは、ブラウザのセキュリティ機能であるCORS(Cross-Origin Resource Sharing)によって制限されます。開発中にフロントエンド(localhost:4200
)からバックエンド(例えば localhost:3000
や外部API)にリクエストを送信する際に、CORSエラーに遭遇することがよくあります。
本番環境では、バックエンドサーバー側でCORSヘッダーを設定して対応しますが、開発時にはAngular CLIのプロキシ設定を利用すると便利です。
-
プロキシ設定ファイルの作成: プロジェクトルートに
proxy.conf.json
というファイルを作成します。json
// proxy.conf.json
{
"/api": {
"target": "http://localhost:3000", // バックエンドAPIのURL
"secure": false,
"changeOrigin": true,
"pathRewrite": {
"^/api": "" // /api を削除してバックエンドに転送
}
}
}
この設定は、http://localhost:4200/api
へのリクエストをhttp://localhost:3000
に転送し、その際に/api
プレフィックスを削除することを意味します。 -
angular.json
の設定:angular.json
ファイルを開き、projects.[your-project-name].architect.serve.options
にproxyConfig
を追加します。json
// angular.json (抜粋)
"architect": {
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "my-first-angular-app:build",
"proxyConfig": "proxy.conf.json" // 追加
},
// ...
}
} -
開発サーバーの再起動: 設定を適用するために
ng serve
を再起動します。
これで、HttpClient
で http://localhost:4200/api/users
のようなURLにリクエストを送信すると、Angular開発サーバーがそれをインターセプトし、http://localhost:3000/users
に転送してくれるようになります。
第8章:Angularアプリケーションのテストとビルド
Angularは、テストと本番環境へのデプロイに関して強力なツールとワークフローを提供します。
8.1 テストの基本
Angular CLIで生成されたプロジェクトには、デフォルトでユニットテストとE2Eテストの環境が設定されています。
- ユニットテスト (Unit Tests): 個々のコンポーネント、サービス、パイプなどの最小単位のコードが正しく動作するかを検証します。Angularは、テストフレームワークとしてJasmineを、テストランナーとしてKarmaをデフォルトで採用しています。
- E2Eテスト (End-to-End Tests): アプリケーション全体がユーザーの視点から正しく動作するかを検証します。ブラウザを自動操作して、ユーザーのワークフローをシミュレートします。Angular CLIはかつてProtractorをデフォルトとしていましたが、現在はCypressやPlaywrightが推奨されています。
ユニットテストの実行
プロジェクトルートで以下のコマンドを実行します。
bash
ng test
このコマンドを実行すると、Karmaテストランナーが起動し、ブラウザ(通常はChrome)が開き、テスト結果がそのブラウザとターミナルの両方に表示されます。
src/app/app.component.spec.ts
を見てみましょう。これは AppComponent
のユニットテストファイルです。
“`typescript
// src/app/app.component.spec.ts
import { TestBed } from ‘@angular/core/testing’;
import { RouterTestingModule } from ‘@angular/router/testing’;
import { AppComponent } from ‘./app.component’;
describe(‘AppComponent’, () => { // テストスイートの定義
beforeEach(async () => { // 各テストが実行される前に実行される設定
await TestBed.configureTestingModule({ // テストモジュールの設定
imports: [
RouterTestingModule
],
declarations: [
AppComponent
],
}).compileComponents(); // コンポーネントのテンプレートとCSSをコンパイル
});
it(‘should create the app’, () => { // 個々のテストケース
const fixture = TestBed.createComponent(AppComponent); // AppComponentのインスタンスを作成
const app = fixture.componentInstance; // コンポーネントのインスタンスを取得
expect(app).toBeTruthy(); // コンポーネントが正常に作成されたことを検証
});
it(should have as title 'my-first-angular-app'
, () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
expect(app.title).toEqual(‘my-first-angular-app’); // titleプロパティが正しいか検証
});
it(‘should render title’, () => {
const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges(); // 変更検知を実行し、テンプレートを更新
const compiled = fixture.nativeElement as HTMLElement; // レンダリングされたDOM要素を取得
expect(compiled.querySelector(‘.content span’)?.textContent).toContain(‘my-first-angular-app app is running!’); // 表示されたテキストを検証
});
});
“`
describe()
: 関連するテストケースをグループ化する「テストスイート」を定義します。beforeEach()
: 各テストケースの前に実行される共通のセットアップ処理を定義します。ここではTestBed
を使って、テスト対象のコンポーネントやその依存関係をセットアップしています。it()
: 個々のテストケース(「仕様」や「期待する振る舞い」)を定義します。expect()
: テストの「アサーション」(検証)を行います。expect(actual).matcher(expected)
の形式で記述します。
ユニットテストは、バグの早期発見、コードの品質向上、リファクタリングの安全性確保に非常に役立ちます。
8.2 アプリケーションのビルドとデプロイ
アプリケーションを本番環境にデプロイするためには、HTML、CSS、JavaScriptの静的ファイルに「ビルド」する必要があります。Angular CLIは、このプロセスを簡単に行うことができます。
アプリケーションのビルド
プロジェクトルートで以下のコマンドを実行します。
bash
ng build
このコマンドは、開発モードでアプリケーションをビルドします。生成されるファイルは dist/[プロジェクト名]
ディレクトリに格納されます。
本番環境向けビルド
本番環境にデプロイする際は、最適化されたビルドを行うべきです。
“`bash
ng build –configuration=production
または v16以前は ng build –prod
“`
このコマンドは、以下の最適化を行います。
- AOT (Ahead-of-Time) コンパイル: アプリケーションのHTMLとTypeScriptコードを、ブラウザがダウンロードする前にJavaScriptコードに変換します。これにより、初回レンダリングが高速化され、ランタイムパフォーマンスが向上します。
- Tree Shaking: 使用されていないコードをバンドルから削除し、バンドルサイズを縮小します。
- Minification & Uglification: コードを圧縮し、変数名を短縮するなどして、ファイルサイズをさらに縮小します。
- Bundle Optimization: 複数のJavaScriptファイルを最適化された形で結合します。
これらの最適化により、生成されるファイルサイズが劇的に減少し、ロード時間が短縮され、アプリケーションのパフォーマンスが向上します。
ビルドが完了すると、dist/[プロジェクト名]
ディレクトリに以下のようなファイルが生成されます。
dist/my-first-angular-app/
├── index.html
├── main-xxxxxxxxxxxx.js # アプリケーションの主要なコード
├── polyfills-xxxxxxxxxxxx.js # ブラウザ互換性維持のためのポリフィル
├── runtime-xxxxxxxxxxxx.js # Angularランタイムコード
├── styles-xxxxxxxxxxxx.css # アプリケーションのスタイル
├── assets/ # 静的アセット(画像など)
└── favicon.ico
ファイル名に含まれるハッシュ値(xxxxxxxxxxxx
)は、キャッシュ busting(キャッシュされた古いファイルを再利用せず、常に新しいバージョンをロードさせる)のために自動生成されます。
静的ファイルホスティングサービスへのデプロイ
dist/[プロジェクト名]
内の生成されたファイルはすべて静的なファイルです。これらは、さまざまな静的ファイルホスティングサービスにアップロードするだけでデプロイできます。
人気のあるサービス:
- Firebase Hosting: Googleが提供する静的ファイルホスティングサービス。SSL、CDN、カスタムドメインなどを簡単に設定できます。
- Netlify: フロントエンド開発に特化したデプロイサービス。Gitリポジトリと連携して自動デプロイが可能です。
- Vercel: Netlifyと同様に、フロントエンドのデプロイに最適化されています。Next.jsの開発元でもあります。
- GitHub Pages: GitHubリポジトリから直接静的Webサイトをホスティングできます。
- Amazon S3 + CloudFront: AWSを使った大規模なデプロイに適しています。
これらのサービスは、通常、簡単なCLIコマンドやGit連携を設定するだけで、Angularアプリケーションを世界中に公開することができます。例えばFirebase Hostingの場合:
npm install -g firebase-tools
でFirebase CLIをインストール。firebase login
でログイン。firebase init hosting
でプロジェクトを設定(Public directoryはdist/my-first-angular-app
と指定)。firebase deploy --only hosting
でデプロイ。
これで、あなたのAngularアプリケーションがインターネット上でアクセス可能になります。
第9章:さらに学ぶために:次のステップ
このガイドでは、Angular開発の基本的な概念と操作を網羅しました。しかし、Angularの世界は非常に広範であり、さらに多くの強力な機能や高度なテクニックが存在します。ここからは、今後の学習の方向性を示すためのいくつかのトピックを紹介します。
9.1 高度なトピック
-
コンポーネント間通信:
@Input()
: 親コンポーネントから子コンポーネントへデータを渡すためのデコレータ。@Output()
とEventEmitter
: 子コンポーネントから親コンポーネントへイベントを通知するためのデコレータとクラス。- サービスを使った通信: 共通のデータやイベントをサービスを通じて共有し、任意のコンポーネント間で通信を行う方法。
- RxJS
Subject
/BehaviorSubject
: 複雑なコンポーネント間通信や状態管理のためのRxJSの機能。
-
カスタムパイプ (Custom Pipes):
- データ表示を変換(フォーマット)するためのカスタムパイプを作成する方法。例えば、日付フォーマット、通貨フォーマット、テキストの切り詰めなど。
PipeTransform
インターフェースを実装します。
-
変更検知 (Change Detection):
- AngularがUIをいつ、どのように更新するかを理解する。
ChangeDetectionStrategy.OnPush
の利用: コンポーネントの変更検知の頻度を最適化し、アプリケーションのパフォーマンスを向上させるための戦略。大規模なアプリケーションでは必須の知識です。
-
パフォーマンス最適化:
- Lazy Loading (遅延ロード): ルートごとにモジュールを分割し、必要なときにのみロードすることで、アプリケーションの初期ロード時間を短縮します。第5章で軽く触れました。
- Signals (シグナル): Angular v16から導入された新しいリアクティビティプリミティブ。変更検知をよりきめ細かく制御し、将来的にゾーンJSなしでの変更検知を可能にする可能性があります。
- TrackBy Function (
*ngFor
の改善):*ngFor
で要素をリスト表示する際に、パフォーマンスを向上させるためのtrackBy
関数。
-
Angular Material / UIライブラリ:
- Googleが開発したAngular用のUIコンポーネントライブラリ。マテリアルデザインに基づいた高品質なUIを簡単に構築できます。
- 他にもPrimeNG, NG-ZORROなど、多くのサードパーティ製UIライブラリがあります。
-
状態管理 (State Management):
- 大規模なアプリケーションでは、複数のコンポーネント間で共有されるアプリケーションの状態(データ)を効率的に管理する必要があります。
- NgRx: Reduxパターンに基づいたAngular用の状態管理ライブラリ。予測可能な状態管理を提供します。
- Akita: オブザーバブルベースの状態管理ライブラリで、よりシンプルに状態管理ができます。
-
PWA (Progressive Web App):
- Webアプリケーションをネイティブアプリのように機能させる技術(オフラインアクセス、プッシュ通知、ホーム画面への追加など)。Angular CLIにはPWAを簡単に有効にするためのコマンドがあります (
ng add @angular/pwa
)。
- Webアプリケーションをネイティブアプリのように機能させる技術(オフラインアクセス、プッシュ通知、ホーム画面への追加など)。Angular CLIにはPWAを簡単に有効にするためのコマンドがあります (
-
SSR (Server-Side Rendering) / Hydration (Angular v17+):
- 初期レンダリングをサーバーサイドで行うことで、SEO(検索エンジン最適化)を改善し、初回表示を高速化します。
- Angular v17からは、特に高速化された Hydration 機能が導入され、よりスムーズなSSRを実現できるようになりました。
9.2 公式ドキュメントの活用
Angularの学習において、最も信頼できる情報源は公式ドキュメントです。
https://angular.io/
このガイドで扱いきれなかった詳細な情報、最新の機能、ベストプラクティスが網羅されています。特定の機能について深く掘り下げたい場合は、必ず公式ドキュメントを参照する習慣をつけましょう。
9.3 コミュニティと情報源
- Angularブログ: 最新のリリース情報や開発に関する記事が公開されています。
- Stack Overflow: プログラミングに関する質問と回答のコミュニティ。Angularに関する多くの質問と解決策が見つかります。
- GitHub: Angularのソースコードや、多くのオープンソースのAngularプロジェクトが公開されています。
- Twitter/X:
#Angular
や Angular関連のハッシュタグをフォローすると、最新情報や開発者の会話を追うことができます。 - 技術ブログ、YouTubeチュートリアル: このガイド以外にも、多くの優れた学習リソースが存在します。
まとめ
この「Angular入門:開発環境構築から基本操作まで完全ガイド」を通じて、あなたはAngularの基本的な開発フローと主要な概念を習得したはずです。Angularは学習曲線が比較的急ですが、一度その堅牢な仕組みを理解すれば、大規模で保守性の高いWebアプリケーションを効率的に開発できる強力なツールとなります。
学んだことを活かして、実際に小さなアプリケーションをいくつか作成してみることを強くお勧めします。手を動かすことで、知識がより深く定着し、新たな疑問や課題に直面することで、さらに学習を進めるモチベーションが生まれるでしょう。
Angular開発の旅はまだ始まったばかりです。常に新しい知識を吸収し、挑戦し続けることで、あなたのスキルは確実に向上していくはずです。あなたのAngular開発が実り多いものとなることを願っています!