はい、承知いたしました。Angularについて、初心者向けに基本を徹底解説する詳細な記事を記述します。約5000語を目指し、各概念を丁寧に説明します。
Angularとは?初心者向けに基本を徹底解説
はじめに:Web開発の進化とAngularの登場
現代のWebアプリケーションは、もはや単なる静的な情報表示の場ではありません。ユーザーは、リアルタイムでのデータ更新、スムーズな画面遷移、デスクトップアプリケーションのような操作感をWebブラウザ上で求めています。Gmail、Google Maps、Slack、Trelloのようなアプリケーションを思い浮かべてみてください。これらはすべて、Webブラウザ上で動作する非常にリッチでインタラクティブなアプリケーションです。
このような複雑なWebアプリケーションを効率的かつ保守性高く開発するために、JavaScriptのフレームワークが生まれました。jQueryのようなライブラリが登場し、DOM操作を容易にしましたが、アプリケーション全体の状態管理や構造化には限界がありました。そこで、アプリケーション全体の開発をより体系的にサポートするフレームワークが必要とされました。
Angularは、Googleによって開発・保守されている、オープンソースのフロントエンド開発フレームワークです。元々は「AngularJS」という名前で2010年に登場しましたが、その後の大規模な改修を経て、全く新しいフレームワークとして2016年に「Angular 2」としてリリースされました。現在一般的に「Angular」と呼ばれるのは、このAngular 2以降のバージョンを指します(AngularJSとは互換性がありません)。
Angularは、シングルページアプリケーション(SPA: Single Page Application)の開発に特化しています。SPAとは、一度ブラウザにページを読み込んだ後は、ページの再読み込みを行わずに、JavaScriptを使って動的にコンテンツを書き換えることで画面遷移やデータの更新を行うアプリケーションのことです。これにより、デスクトップアプリケーションに近い高速で滑らかなユーザー体験を提供できます。
Angular以外にも、ReactやVue.jsといった人気のフロントエンドフレームワーク・ライブラリがありますが、それぞれに特徴があります。Angularは、フレームワークとして多くの機能(ルーティング、HTTP通信、フォーム管理など)を標準で提供しており、大規模なアプリケーション開発に適した堅牢な構造と厳格なルールを持っているのが特徴です。
なぜAngularを学ぶのか? Angularのメリット
Angularを学ぶことには、いくつかの大きなメリットがあります。
- 構造化された開発: Angularは明確な構造と開発パラダイムを提供します。これにより、チーム開発がしやすく、大規模なプロジェクトでもコードの整合性を保ちやすくなります。コンポーネント、モジュール、サービスといった概念がコードを整理するのに役立ちます。
- 高いパフォーマンス: Angularは、変更検知の最適化やAOT (Ahead-of-Time) コンパイルなどの仕組みにより、高い実行パフォーマンスを実現します。特に大規模なアプリケーションにおいて、その恩恵を受けられます。
- 豊富な機能: ルーティング、HTTPクライアント、フォーム処理、テストユーティリティなど、多くの必要な機能がフレームワーク自体に組み込まれています。これらのために別途ライブラリを探して組み合わせる手間が省けます。
- TypeScriptの活用: AngularはTypeScriptを強く推奨し、フレームワーク自体もTypeScriptで記述されています。TypeScriptはJavaScriptに静的型付けの概念を加えたもので、開発中にエラーを早期に発見したり、コードの可読性・保守性を高めたりするのに非常に有効です。大規模プロジェクトではその恩恵がさらに大きくなります。
- 強力なエコシステムとツール: Angular CLI (Command Line Interface) という強力なツールが提供されており、プロジェクトの作成、コンポーネントやサービスの生成、ビルド、テストといった開発の多くの側面を効率化できます。また、Googleによるサポートや、活発なコミュニティによる情報やライブラリが豊富に存在します。
- 保守性: 明確なパターンと規約があるため、一度Angularの流儀を理解すれば、他の開発者が書いたAngularコードも比較的容易に理解・保守できます。
Angularの難しさ?
一方で、AngularはReactやVue.jsと比較して、「学習コストがやや高い」と言われることがあります。これは、Angularが提供する概念や機能が多く、それらを理解するのに時間がかかるためです。TypeScriptの習得も必要になります。しかし、一度これらの基本的な概念を習得してしまえば、Angularの提供する構造の上で効率的に開発を進めることができるようになります。
この記事では、Angularの基本的な概念(コンポーネント、モジュール、サービス、データバインディング、ルーティングなど)を初心者向けに、具体的なコード例を交えながら徹底的に解説します。最後まで読み進めれば、Angularアプリケーションの基本的な仕組みを理解し、簡単なアプリケーションを開発できるようになることを目指します。
事前準備:Angular開発に必要なもの
Angularの開発を始める前に、いくつかの準備が必要です。
1. Web開発の基本知識
Angularはフロントエンドフレームワークなので、以下の基本的なWeb開発技術の知識が前提となります。
- HTML: Webページの構造を記述するためのマークアップ言語。コンポーネントのテンプレートとして使用します。
- CSS: Webページの見た目を装飾するためのスタイルシート言語。コンポーネントのスタイルとして使用します。
- JavaScript: Webページに動きやインタラクティブな要素を加えるためのプログラミング言語。Angularアプリケーションの核となるロジックを記述します。
- TypeScript: AngularはTypeScriptの使用を強く推奨しています。TypeScriptはJavaScriptに静的型付けなどの機能を追加した言語で、JavaScriptのコードをより構造化し、大規模開発に適したものにします。JavaScriptを書いた経験があれば、TypeScriptの学習は比較的容易です。この記事でもTypeScriptの基本的な部分に触れますが、別途TypeScriptの入門資料も参照すると理解が深まります。
2. 開発環境の準備
Angular開発には以下のソフトウェアが必要です。
- Node.js: Angular CLIを実行するために必要です。Node.jsにはnpm (Node Package Manager) も含まれています。
- Node.jsの公式サイトからLTS (長期サポート) 版をダウンロードしてインストールしてください。インストール後、ターミナルやコマンドプロンプトで
node -v
およびnpm -v
を実行して、バージョン情報が表示されるか確認してください。
- Node.jsの公式サイトからLTS (長期サポート) 版をダウンロードしてインストールしてください。インストール後、ターミナルやコマンドプロンプトで
- npm または Yarn: JavaScriptのパッケージ管理ツールです。npmはNode.jsに同梱されています。Yarnも代替として利用可能です。
- Angular CLI: Angularアプリケーションの作成、開発、ビルド、テストなどを効率化するためのコマンドラインツールです。
- Node.jsとnpmをインストールした後、ターミナルで以下のコマンドを実行してグローバルにインストールします。
bash
npm install -g @angular/cli - インストール後、
ng version
を実行してバージョン情報が表示されるか確認してください。
- Node.jsとnpmをインストールした後、ターミナルで以下のコマンドを実行してグローバルにインストールします。
- 統合開発環境 (IDE) またはコードエディタ: Angularのコードを書くためのエディタです。TypeScriptのサポートが充実しているものがおすすめです。
- Visual Studio Code (VS Code): Microsoft製の無料で高機能なエディタです。TypeScriptのサポートが非常に優れており、Angular開発において最も一般的に使用されています。Angular Language Serviceなどの拡張機能も利用できます。
- 他の選択肢としては、WebStorm (有料だが強力なJavaScript/TypeScript IDE)、Sublime Text、Atomなどがあります。
この記事では、VS Codeを使用することを前提に解説を進めます。
準備が整ったら、いよいよAngularアプリケーションを作成してみましょう。
Angularプロジェクトを作成してみよう
Angular CLIを使うと、簡単に新しいAngularプロジェクトを作成できます。ターミナルを開き、プロジェクトを作成したいディレクトリに移動して、以下のコマンドを実行します。
bash
ng new my-first-angular-app
ng new
は新しいAngularプロジェクトを作成するコマンドです。my-first-angular-app
はプロジェクト名です。任意の名前をつけてください。
コマンドを実行すると、いくつか質問されます。
Would you like to add Angular Routing? (y/N)
: Angularのルーティング機能を追加するかどうか。現時点ではy
を選択して構いません。これにより、アプリケーション内でページ遷移を実現するための基本的な設定が行われます。Which stylesheet format would you like to use? (CSS, SCSS, Sass, Less, Stylus)
: スタイルシートの形式を選択します。初心者はCSS
を選択するのが最もシンプルです。後から変更も可能です。
質問に答えると、Angular CLIがプロジェクトのディレクトリ構造を作成し、必要なパッケージ(npmモジュール)をインストールします。これには少し時間がかかる場合があります。
インストールが完了したら、作成されたプロジェクトディレクトリに移動します。
bash
cd my-first-angular-app
これで、Angularアプリケーションを開発する準備ができました。
アプリケーションを実行してみる
プロジェクトディレクトリ内で、以下のコマンドを実行すると、開発サーバーが起動し、アプリケーションをブラウザで確認できます。
bash
ng serve --open
ng serve
は開発サーバーを起動するコマンドです。--open
(または-o
) オプションを付けると、サーバー起動後に自動的にWebブラウザが開き、アプリケーションが表示されます。
通常、アプリケーションは http://localhost:4200/
で表示されます。初期状態では、Angularのウェルカムページが表示されます。
ng serve
コマンドを実行している間、ソースコードを変更して保存すると、アプリケーションが自動的にリロードされ、変更が即座にブラウザに反映されます(ホットリロード)。これは開発効率を大幅に向上させます。開発サーバーを停止するには、ターミナルで Ctrl + C
を押します。
Angularプロジェクトの基本構造を理解する
ng new
コマンドで作成されたプロジェクトのディレクトリ構造を見てみましょう。特に重要なファイルやディレクトリをいくつか説明します。
my-first-angular-app/
├── .angular/ # Angular CLI のキャッシュなど
├── .git/ # Git リポジトリ (git init した場合)
├── .vscode/ # VS Code の設定ファイル (VS Code で開いた場合)
├── node_modules/ # プロジェクトの依存パッケージ (npm install でインストールされる)
├── src/ # アプリケーションのソースコード
│ ├── app/ # アプリケーションの主要なコード
│ │ ├── app-routing.module.ts # ルーティング設定 (ng new で routing を追加した場合)
│ │ ├── app.component.css # Rootコンポーネントのスタイル
│ │ ├── app.component.html # Rootコンポーネントのテンプレート
│ │ ├── app.component.spec.ts # Rootコンポーネントのテストファイル
│ │ ├── app.component.ts # Rootコンポーネントのクラスファイル
│ │ └── app.module.ts # アプリケーションのRootモジュール
│ ├── assets/ # 画像などの静的ファイル
│ ├── environments/ # 開発環境と本番環境などの設定ファイル
│ ├── favicon.ico # ファビコン
│ ├── index.html # アプリケーションのエントリーポイントとなるHTMLファイル
│ ├── main.ts # アプリケーションのエントリーポイントとなるTypeScriptファイル
│ ├── polyfills.ts # ブラウザ間の互換性のためのポリフィル
│ ├── styles.css # グローバルなスタイルシート
│ └── test.ts # テスト設定
├── angular.json # Angular CLI のプロジェクト設定ファイル
├── package.json # プロジェクトの依存関係とスクリプト設定
├── package-lock.json # package.json の正確なバージョンと依存関係を記録
├── README.md # プロジェクトの説明
├── tsconfig.json # TypeScript のコンパイラ設定
├── tsconfig.app.json # アプリケーションコードの TypeScript 設定
├── tsconfig.spec.json # テストコードの TypeScript 設定
└── ...その他の設定ファイル
主要なファイル/ディレクトリの説明:
node_modules/
: プロジェクトが依存するすべてのライブラリやパッケージが格納される場所です。このディレクトリの内容はnpmによって管理されます。ソース管理(Gitなど)には通常含めません。src/
: アプリケーションのソースコードが配置されるルートディレクトリです。src/index.html
: アプリケーションがブラウザで最初に読み込まれるHTMLファイルです。SPAなので、基本的にはこのファイルだけが読み込まれ、その後の画面更新はJavaScriptで行われます。このファイルには<app-root></app-root>
というカスタムタグが含まれています。これは、アプリケーションのルートコンポーネントが表示される場所を示しています。src/main.ts
: アプリケーションのエントリーポイントです。ここでAngularのプラットフォームが起動され、Rootモジュール (AppModule
) が読み込まれてアプリケーションが開始されます。src/styles.css
: アプリケーション全体に適用されるグローバルなスタイルシートです。src/app/
: アプリケーションの主要なロジックが含まれるディレクトリです。src/app/app.component.*
: アプリケーションのルートコンポーネントを構成するファイル群です (.ts
,.html
,.css
,.spec.ts
)。src/app/app.module.ts
: アプリケーションのRootモジュールです。アプリケーションの開始点であり、アプリケーションで使用されるほとんどのコンポーネント、サービス、その他の要素がここで登録(あるいはインポート)されます。
angular.json
: Angular CLIの構成ファイルです。プロジェクトのビルド設定、開発サーバーの設定、テスト設定などが記述されています。package.json
: Node.jsプロジェクトの設定ファイルです。プロジェクト名、バージョン、依存関係(dependencies
とdevDependencies
)、実行可能なスクリプト(ng serve
などをnpm start
などで実行できるように定義)などが記述されています。tsconfig.json
: TypeScriptのコンパイラ設定ファイルです。TypeScriptコードをJavaScriptにコンパイルする際のルールなどが定義されています。
プロジェクト構造を理解することは、どこに何を書けば良いかを判断する上で重要です。次に、Angularの最も基本的な構成要素である「コンポーネント」について詳しく見ていきましょう。
Angularの基本構成要素:コンポーネント
Angularアプリケーションは、コンポーネントの集まりとして構築されます。コンポーネントは、ユーザーインターフェース(UI)の一部を管理する独立したブロックです。例えば、Webサイトのヘッダー、フッター、ナビゲーションバー、記事一覧、個別の記事表示画面などは、それぞれが独立したコンポーネントとして設計できます。
コンポーネントは、以下の3つの要素から構成されます。
- テンプレート (Template): コンポーネントのUI構造を定義するHTMLコードです。
- クラス (Class): コンポーネントのデータ(プロパティ)とロジック(メソッド)を定義するTypeScriptコードです。
- メタデータ (Metadata):
@Component
デコレーターを使って、Angularにそのクラスがコンポーネントであることを知らせ、テンプレートやスタイル、セレクターなどの設定情報を提供します。
ng new
で作成されたプロジェクトに含まれる app.component.ts
ファイルを見てみましょう。
“`typescript
// src/app/app.component.ts
import { Component } from ‘@angular/core’;
@Component({
selector: ‘app-root’, // このコンポーネントが使用されるHTMLタグの名前
templateUrl: ‘./app.component.html’, // テンプレートファイルのパス
styleUrls: [‘./app.component.css’] // スタイルシートファイルのパス (配列)
})
export class AppComponent {
title = ‘my-first-angular-app’; // クラスのプロパティ
// クラスのメソッド (例: ボタンクリック時の処理など)
changeTitle(newTitle: string): void {
this.title = newTitle;
}
}
“`
import { Component } from '@angular/core';
:@angular/core
パッケージからComponent
デコレーターをインポートしています。@Component({...})
: これはデコレーターと呼ばれるものです。TypeScriptの機能で、クラスやプロパティ、メソッドにメタデータを追加するために使用されます。@Component
デコレーターは、その直下のクラス (AppComponent
) がAngularコンポーネントであることを示し、コンポーネントの設定情報(メタデータ)を提供します。selector: 'app-root'
: このコンポーネントをHTMLテンプレートで使用する際のカスタムHTMLタグ名を定義します。index.html
に書かれていた<app-root></app-root>
がこれにあたります。templateUrl: './app.component.html'
: このコンポーネントのテンプレートとして使用するHTMLファイルのパスを指定します。styleUrls: ['./app.component.css']
: このコンポーネントに適用するスタイルシートファイルのパスを指定します。配列なので複数のファイルを指定できます。ここで指定したスタイルは、デフォルトではこのコンポーネントとその子要素にのみ適用されるようにスコープされます(View Encapsulation)。
export class AppComponent { ... }
: コンポーネントのクラス定義です。このクラスのプロパティやメソッドが、コンポーネントのデータや振る舞いを定義します。export
することで、他のファイルからこのクラスをインポートして利用できるようになります。title = 'my-first-angular-app';
:title
という名前のプロパティを定義しています。初期値は'my-first-angular-app'
です。このプロパティの値はテンプレートから参照したり変更したりできます。
新しいコンポーネントを作成する
Angular CLIを使えば、新しいコンポーネントを簡単に生成できます。プロジェクトディレクトリ内で以下のコマンドを実行します。
“`bash
ng generate component my-new-component
または省略形
ng g c my-new-component
“`
このコマンドは、src/app/my-new-component/
という新しいディレクトリを作成し、その中に以下のファイルを生成します。
my-new-component.component.ts
my-new-component.component.html
my-new-component.component.css
my-new-component.component.spec.ts
また、このコンポーネントが属するモジュール(デフォルトではAppModule
)の app.module.ts
に、生成したコンポーネントを自動的に登録してくれます。
生成された my-new-component.component.ts
は以下のようになります。
“`typescript
// src/app/my-new-component/my-new-component.component.ts
import { Component } from ‘@angular/core’;
@Component({
selector: ‘app-my-new-component’, // 生成されたセレクター名
templateUrl: ‘./my-new-component.component.html’,
styleUrls: [‘./my-new-component.component.css’]
})
export class MyNewComponentComponent {
// コンポーネントのロジックやデータはここに記述
}
“`
生成された my-new-component.component.html
は以下のようになります。
“`html
my-new-component works!
“`
この新しいコンポーネントを使うには、他のコンポーネントのテンプレートにそのセレクター <app-my-new-component></app-my-new-component>
を記述します。例えば、app.component.html
に追加してみましょう。
“`html
Welcome to {{ title }}!
“`
ng serve
を実行している状態でこれを保存すると、ブラウザに「my-new-component works!」というテキストが表示されるはずです。
コンポーネントはアプリケーションのUIを構築する上で最も基本的な要素です。複数のコンポーネントを組み合わせて、複雑なUIを持つアプリケーションを構築していきます。
テンプレート構文とデータバインディング
Angularのテンプレートは標準のHTMLを拡張したものです。特別な構文を使うことで、コンポーネントのクラスとテンプレートの間でデータをやり取りしたり、DOMの構造や要素の属性を変更したり、イベントに応答したりできます。この仕組みをデータバインディングと呼びます。
データバインディングには主に4つの種類があります。
- 補間 (Interpolation): クラスのプロパティ値をテンプレートに表示する(一方通行)。
- プロパティバインディング (Property Binding): クラスのプロパティ値をDOM要素のプロパティ(属性)に設定する(一方通行)。
- イベントバインディング (Event Binding): DOMイベント(クリックなど)をクラスのメソッド呼び出しに紐づける(一方通行)。
- 双方向バインディング (Two-Way Binding): UI要素(入力フィールドなど)の値とクラスのプロパティを同期させる(双方向)。
それぞれのデータバインディングについて、具体的な例を見ていきましょう。app.component.ts
と app.component.html
を編集して試してみます。
まず、app.component.ts
を以下のように変更します。
“`typescript
// src/app/app.component.ts
import { Component } from ‘@angular/core’;
@Component({
selector: ‘app-root’,
templateUrl: ‘./app.component.html’,
styleUrls: [‘./app.component.css’]
})
export class AppComponent {
title = ‘my-first-angular-app’;
imageUrl = ‘https://angular.io/assets/images/logos/angular/[email protected]’; // 画像URLを追加
buttonText = ‘Change Title’; // ボタンのテキストを追加
isButtonDisabled = false; // ボタンの活性状態を追加
inputText = ”; // 入力フィールドのテキストを追加
// メソッドを追加
changeTitle(newTitle: string): void {
this.title = newTitle;
}
onButtonClick(): void {
this.changeTitle(‘Title Changed!’);
this.isButtonDisabled = true; // ボタンを無効にする
}
onInput(event: Event): void {
const inputElement = event.target as HTMLInputElement;
this.inputText = inputElement.value;
}
}
“`
次に、app.component.html
を編集します。
“`html
{{ title }}
画像のURL: {{ imageUrl }}
入力されたテキスト: {{ inputText }}
計算結果: {{ 5 + 3 }}
イベントバインディングで入力されたテキスト(手動同期): {{ inputText }}
双方向バインディングで変更されるタイトル: {{ title }}
“`
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’;
import { MyNewComponentComponent } from ‘./my-new-component/my-new-component.component’;
@NgModule({
declarations: [
AppComponent,
MyNewComponentComponent // ng generate component で自動的に追加されます
],
imports: [
BrowserModule,
AppRoutingModule,
FormsModule // <– これを追加
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
“`
解説:
- 補間
{{ ... }}
: クラスのプロパティ名を波括弧で囲むだけで、その値が表示されます。簡単なJavaScript式も記述可能です。プロパティが更新されると、表示も自動的に更新されます。 - プロパティバインディング
[property]="expression"
: HTML要素のプロパティ(属性)に、コンポーネントクラスのプロパティの値をバインドします。例えば、[src]="imageUrl"
は、<img>
タグのsrc
属性にAppComponent
クラスのimageUrl
プロパティの値を設定します。属性名の前に角括弧[]
を付けます。式の部分にはクラスのプロパティだけでなく、簡単な式や関数呼び出しも書けます。[disabled]="isButtonDisabled"
のように、真偽値を使って属性の有無を制御することもよく行われます。 - イベントバインディング
(event)="method()"
: HTML要素のイベントが発生した際に、コンポーネントクラスのメソッドを実行します。例えば、(click)="onButtonClick()"
は、ボタンがクリックされたときにAppComponent
クラスのonButtonClick()
メソッドを呼び出します。イベント名の周りに丸括弧()
を付けます。イベントオブジェクト$event
をメソッドに渡すこともできます ((input)="onInput($event)"
)。 - 双方向バインディング
[(ngModel)]="property"
: これは、プロパティバインディングとイベントバインディングを組み合わせたもので、フォーム入力要素 (<input>
,<textarea>
,<select>
) の値と、コンポーネントクラスのプロパティを常に同期させます。例えば、<input type="text" [(ngModel)]="title">
では、入力フィールドにテキストを入力するとtitle
プロパティの値が更新され、逆にtitle
プロパティをコードで更新すると、入力フィールドの値も更新されます。双方向バインディングを使うには、関連するモジュール(通常はRootモジュールまたは機能モジュール)にFormsModule
をインポートする必要があります。構文は[()]
で、バナナを箱に入れたように見えることから「バナナ・イン・ザ・ボックス構文」と呼ばれることもあります。
これらのデータバインディングを理解することは、AngularでインタラクティブなUIを構築する上で非常に重要です。
ディレクティブ
Angularのディレクティブは、DOM要素やコンポーネントに新しい振る舞いを追加したり、DOMの構造を変更したりするために使用されます。コンポーネント自体も、テンプレートを持つ特殊なディレクティブと考えることができます。
ディレクティブは大きく3種類に分けられます。
- コンポーネント (Components): テンプレートを持つディレクティブ。UIの主要なブロックを構築します(これまでに説明しました)。
- 構造ディレクティブ (Structural Directives): DOMツリーの構造(要素の追加や削除)を変更するディレクティブ。先頭にアスタリスク
*
が付きます。 - 属性ディレクティブ (Attribute Directives): 要素の見た目や振る舞い(属性、CSSクラス、スタイルなど)を変更するディレクティブ。アスタリスクは付きません。
構造ディレクティブ
DOM要素の追加・削除によって構造を変更します。よく使われるものに *ngIf
と *ngFor
があります。
-
*ngIf
: 条件に基づいて要素を表示したり非表示にしたりします(実際にはDOMに追加・削除します)。
“`html
{{ title }}
// …
export class AppComponent {
// … 他のプロパティ
showMessage = false; // 初期値は非表示// … 他のメソッド
}
`showMessage` が `true` の場合のみ、`<p>` 要素がDOMに追加され表示されます。`false` の場合はDOMから削除されます。
html
* **`*ngFor`**: コレクション(配列など)を反復処理し、リスト要素などを繰り返し生成します。
ユーザーリスト
- {{ user.name }} ({{ user.age }}歳)
// …
export class AppComponent {
// … 他のプロパティ
users = [
{ name: ‘Alice’, age: 30 },
{ name: ‘Bob’, age: 25 },
{ name: ‘Charlie’, age: 35 }
];// … 他のメソッド
}
``
*ngFor=”let user of users”は、
users配列の各要素を
userという変数に代入しながら繰り返し処理を行います。繰り返しごとに
要素が生成され、テンプレート内の
{{ user.name }}や
{{ user.age }}は現在の
user` オブジェクトのプロパティ値に置き換えられます。
属性ディレクティブ
既存の要素の属性、クラス、スタイルなどを変更します。よく使われるものに [ngClass]
と [ngStyle]
があります。
-
[ngClass]
: 条件に基づいてCSSクラスを追加したり削除したりします。プロパティバインディングの形式を使います。
css
/* app.component.css に追加 */
.highlight {
background-color: yellow;
}
.error {
color: red;
font-weight: bold;
}
“`html
このテキストのスタイルは動的に変わります。
// …
export class AppComponent {
// … 他のプロパティ
isHighlighted = true;
hasError = false;// … 他のメソッド
}
`[ngClass]` には、キーがクラス名、値が真偽値となるオブジェクトを渡します。値が `true` のクラスが要素に追加されます。
html
* **`[ngStyle]`**: 条件に基づいてインラインスタイルを追加したり削除したりします。プロパティバインディングの形式を使います。
このテキストのスタイルも動的に変わります。
// …
export class AppComponent {
// … 他のプロパティ
myColor = ‘blue’;
myFontSize = 16;// … 他のメソッド
}
``
[ngStyle]には、キーがCSSプロパティ名、値がスタイル値となるオブジェクトを渡します。CSSプロパティ名はキャメルケースで記述します(例:
backgroundColor)。ピクセルなどの単位を付ける場合は
font-size.pxのように
.単位` を追加します。
ディレクティブは、テンプレート内で複雑な条件分岐や繰り返し、スタイルの動的な変更を簡潔に記述するための強力なツールです。
パイプ
パイプ (Pipe) は、テンプレート内でデータを表示する際に、その形式を変換するために使用されます。例えば、日付を整形したり、数値を通貨形式に変換したり、文字列を大文字に変換したりといった処理に使われます。
パイプは、補間式 {{ ... }}
やプロパティバインディング [property]="..."
の中で、|
演算子を使って適用します。
構文: {{ value | pipeName[:parameter1[:parameter2]] }}
Angularには様々な組み込みパイプがあります。
DatePipe
: 日付のフォーマットUpperCasePipe
: 文字列を大文字に変換LowerCasePipe
: 文字列を小文字に変換CurrencyPipe
: 数値を通貨形式に変換DecimalPipe
: 数値を10進数形式に変換PercentPipe
: 数値をパーセント形式に変換JsonPipe
: JavaScriptオブジェクトをJSON文字列に変換AsyncPipe
: 非同期データソース(PromiseやObservable)の値を解決して表示
例を見てみましょう。
“`typescript
// app.component.ts にプロパティを追加
// …
export class AppComponent {
// … 他のプロパティ
currentDate = new Date();
price = 1234.56;
asyncData: Promise
// … 他のメソッド
}
“`
“`html
パイプの例
現在日時 (デフォルト): {{ currentDate }}
現在日時 (指定フォーマット): {{ currentDate | date:’yyyy/MM/dd HH:mm:ss’ }}
現在日時 (短い日付): {{ currentDate | date:’shortDate’ }}
価格 (デフォルト): {{ price }}
価格 (通貨 – USD): {{ price | currency:’USD’ }}
価格 (通貨 – JPY, シンボル表示): {{ price | currency:’JPY’:’symbol’ }}
価格 (通貨 – EUR, 桁数指定): {{ price | currency:’EUR’:’symbol’:’1.2-2′ }}
大文字: {{ ‘hello angular’ | uppercase }}
小文字: {{ ‘HELLO ANGULAR’ | lowercase }}
オブジェクトをJSONに: {{ { name: ‘Angular’, version: 16 } | json }}
非同期データ: {{ asyncData | async }}
“`
パイプを使うことで、テンプレート内でデータの表示形式を簡単に変更できます。パイプは連鎖させることも可能です ({{ value | pipe1 | pipe2 }}
).
モジュール (NgModules)
Angularアプリケーションは、モジュール (NgModule) によって構造化されます。モジュールは、関連するコンポーネント、サービス、パイプ、ディレクティブなどをまとめるための論理的なまとまりです。これにより、アプリケーションを機能ごとに分割し、コードの整理と再利用を促進できます。
すべてのAngularアプリケーションには、少なくとも1つのルートモジュールが必要です。これは通常 src/app/app.module.ts
で定義される AppModule
です。
app.module.ts
の構造を見てみましょう。
“`typescript
// src/app/app.module.ts
import { NgModule } from ‘@angular/core’; // NgModule デコレーターをインポート
import { BrowserModule } from ‘@angular/platform-browser’; // ブラウザでの動作に必要なモジュール
import { FormsModule } from ‘@angular/forms’; // 双方向バインディングに必要なモジュール
import { AppRoutingModule } from ‘./app-routing.module’; // ルーティングモジュール
import { AppComponent } from ‘./app.component’; // アプリケーションのRootコンポーネント
import { MyNewComponentComponent } from ‘./my-new-component/my-new-component.component’; // 作成したコンポーネント
@NgModule({ // NgModule デコレーター
declarations: [ // このモジュールに「所属」するコンポーネント、パイプ、ディレクティブを宣言
AppComponent,
MyNewComponentComponent
// 他のコンポーネント、パイプ、ディレクティブもここにリストする
],
imports: [ // このモジュールが機能するために必要な他のモジュールをインポート
BrowserModule, // ブラウザアプリケーションで必須
AppRoutingModule, // ルーティング機能を提供
FormsModule // 双方向バインディング機能を提供
// HttpClientModule (HTTP通信用), ReactiveFormsModule (リアクティブフォーム用) などもここにインポート
],
providers: [ // このモジュールが提供するサービスを登録
// サービスはここに登録すると、このモジュール内のどこからでもインジェクション可能になる
// providedIn: ‘root’ を使ったサービスはここに登録する必要はない (Angular 6+ 推奨)
],
bootstrap: [AppComponent] // アプリケーション起動時に最初にロードされるルートコンポーネント (ルートモジュールのみ)
})
export class AppModule { } // モジュールのクラス定義
“`
@NgModule({...})
: これは、このクラス (AppModule
) がAngularモジュールであることを示し、その設定情報を提供します。declarations
: このモジュールに属する宣言可能項目(components, pipes, directives)をリストします。ここで宣言された項目は、このモジュール内で相互に利用できるようになります。注意: コンポーネント、パイプ、ディレクティブは、1つのモジュールでのみ宣言できます。他のモジュールで再宣言することはできません。imports
: このモジュールが利用する他のモジュールをリストします。例えば、BrowserModule
はブラウザ上でAngularアプリケーションを動作させるための基本的な機能を提供します。AppRoutingModule
はアプリケーションのルーティング設定を含んでいます。FormsModule
は双方向バインディングに必要な機能を提供します。これらのモジュールで宣言/提供されている項目を、このモジュール内で利用できるようになります。providers
: このモジュールが提供するサービスをリストします。ここに登録されたサービスは、このモジュールとその子(このモジュールをインポートしたモジュールや、このモジュール内で宣言されたコンポーネントなど)から利用できるようになります。ただし、Angular 6以降では、サービス自体に@Injectable({ providedIn: 'root' })
を指定することで、自動的にRootモジュールで提供される(アプリケーション全体で利用可能になる)ようになり、通常はここにリストする必要はなくなりました。bootstrap
: アプリケーション起動時に最初に読み込まれる(ブートストラップされる)コンポーネントをリストします。これはルートモジュール (AppModule
) のみに存在する設定です。ここにリストされたコンポーネントが、index.html
の<app-root>
のような場所に挿入されて描画されます。
フィーチャーモジュール
大規模なアプリケーションでは、アプリケーションを機能ごとに複数のモジュールに分割することが一般的です。これをフィーチャーモジュールと呼びます。例えば、ユーザー認証に関する機能、商品管理に関する機能、注文処理に関する機能などをそれぞれ独立したモジュールとして作成します。
フィーチャーモジュールを作成するには、Angular CLIの ng generate module
コマンドを使います。
“`bash
ng generate module products –routing
または
ng g m products –routing
“`
--routing
オプションを付けると、そのモジュール専用のルーティングファイル (products-routing.module.ts
) も一緒に生成されます。
フィーチャーモジュールを使うメリットはいくつかあります。
- コードの整理: 関連するコードが1つの場所にまとまり、プロジェクト全体が整理されます。
- 再利用性: 特定のモジュールを他のアプリケーションや別の箇所で再利用しやすくなります。
- 遅延ロード (Lazy Loading): アプリケーション起動時にすべてのモジュールをロードするのではなく、ユーザーが特定の機能にアクセスしたときに初めてそのモジュールをロードする(遅延ロード)設定が容易になります。これにより、初期ロード時間を短縮できます。
フィーチャーモジュール内で宣言されたコンポーネントなどをRootモジュールや他のフィーチャーモジュールから利用したい場合は、そのフィーチャーモジュールの @NgModule
の exports
プロパティで、公開したい項目をリストする必要があります。そして、そのフィーチャーモジュールを利用したい側のモジュールの imports
配列に、そのフィーチャーモジュールをインポートします。
モジュールは、Angularアプリケーションの構造を理解し、管理するための重要な概念です。
サービスと依存性注入 (Dependency Injection)
コンポーネントはUI表示の役割を担いますが、アプリケーションのロジック(データの取得、計算処理、状態管理など)はコンポーネントから分離して、サービスとして定義することが推奨されます。
サービスは、特定の機能を提供するクラスです。コンポーネントとは異なり、サービスはテンプレートを持たず、通常 @Injectable()
デコレーターが付けられます。
サービスを作成する
Angular CLIでサービスを生成します。
“`bash
ng generate service data
または
ng g s data
“`
これにより、src/app/data.service.ts
のようなファイルが生成されます。
“`typescript
// src/app/data.service.ts
import { Injectable } from ‘@angular/core’;
@Injectable({
providedIn: ‘root’ // このサービスをアプリケーションのRootで提供することを指定 (Angular 6+ 推奨)
})
export class DataService {
private data = [‘データ1’, ‘データ2’, ‘データ3’]; // サンプルデータ
constructor() {
console.log(‘DataServiceインスタンスが作成されました’);
}
getData(): string[] {
return this.data;
}
addData(item: string): void {
this.data.push(item);
}
}
“`
@Injectable()
: このデコレーターは、このサービスが他のサービスやコンポーネメントに「注入(inject)」可能であることをAngularに伝えます。また、{ providedIn: 'root' }
オプションを付けると、このサービスがアプリケーション全体で利用可能なシングルトン(インスタンスが一つだけ)として提供されるようになります。これにより、Rootモジュールのproviders
配列に登録する必要がなくなります。constructor()
: サービスの初期化処理を記述します。getData()
,addData()
: このサービスが提供する具体的な機能(メソッド)です。
依存性注入 (Dependency Injection – DI)
サービスを利用したいコンポーネントや他のサービスは、そのサービスのインスタンスを自分で生成するのではなく、Angularの依存性注入 (DI) システムに任せます。DIは、クラスが必要とする依存関係(ここではサービス)を外部から提供するデザインパターンです。
Angularでは、通常、クラスのコンストラクターで必要なサービスを型ヒント付きで宣言することで、DIシステムが自動的にサービスのインスタンスを生成(または既存のインスタンスを提供)して、それをコンストラクターの引数として渡してくれます。
AppComponent
で DataService
を使ってみましょう。
“`typescript
// src/app/app.component.ts
import { Component, OnInit } from ‘@angular/core’; // OnInit をインポート
import { DataService } from ‘./data.service’; // 作成したサービスをインポート
@Component({
selector: ‘app-root’,
templateUrl: ‘./app.component.html’,
styleUrls: [‘./app.component.css’]
})
export class AppComponent implements OnInit { // OnInit インターフェースを実装
// … 他のプロパティ
dataList: string[] = []; // サービスから取得したデータを保持するプロパティ
newItem = ”; // 追加する新しいデータの入力値
// コンストラクターで DataService をインジェクション
constructor(private dataService: DataService) {
// コンストラクターではサービスのインスタンスが利用可能になる
// UIロジックやデータ取得などの処理は ngOnInit で行うのが一般的
}
// コンポーネント初期化時のライフサイクルメソッド
ngOnInit(): void {
console.log(‘AppComponent が初期化されました’);
this.dataList = this.dataService.getData(); // サービスからデータを取得
}
addNewItem(): void {
if (this.newItem.trim()) {
this.dataService.addData(this.newItem.trim()); // サービスにデータを追加
this.dataList = this.dataService.getData(); // データを再取得して表示を更新
this.newItem = ”; // 入力フィールドをクリア
}
}
}
“`
“`html
サービスとDIの例
サービスから取得したデータ:
- {{ item }}
“`
解説:
constructor(private dataService: DataService)
:AppComponent
のコンストラクターの引数にprivate dataService: DataService
と記述することで、AngularのDIシステムはDataService
のインスタンスを探し(ここでは{ providedIn: 'root' }
の設定によりアプリケーション全体で利用可能なシングルトンインスタンス)、それをdataService
という名前のインスタンス変数に注入してくれます。private
キーワードを使うことで、インスタンス変数の宣言と初期化を同時に行えます。ngOnInit()
: これはコンポーネントのライフサイクルメソッドの一つです。コンポーネントが初期化された後に一度だけ実行されます。データ取得など、コンポーネントが表示される前に必要な初期化処理は、通常このメソッド内で行います(コンストラクターは依存関係の注入に使うのが主な目的です)。OnInit
インターフェースを実装することで、このメソッドを使うことを明示しています。- テンプレートでは、
*ngFor
を使ってdataList
の内容を表示し、[(ngModel)]
とイベントバインディングを使って新しいデータを入力・追加するフォームを作成しています。addNewItem
メソッドの中で、注入されたdataService
インスタンスのメソッドを呼び出してデータの操作を行っています。
DIを使うことで、コンポーネントは特定のサービス実装に依存せず、抽象的な「〇〇サービス」という役割に依存するようになります。これにより、テスト時にモックのサービスに簡単に置き換えられたり、コードの変更が容易になったりといったメリットがあります。
ルーティング
シングルページアプリケーション(SPA)では、URLの変更に応じて表示するコンポーネントを切り替える必要があります。この機能を提供するのがルーティングです。Angularのルーティング機能を使うと、URLパスとコンポーネントを簡単に紐づけることができます。
ng new
コマンドで --routing
オプションを選択した場合、app-routing.module.ts
というファイルが生成されています。これがアプリケーションのルーティング設定の中心となります。
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 = [
// ここにルートオブジェクトを定義
// 例: { path: ‘path/to/page’, component: YourComponent }
];
@NgModule({
imports: [RouterModule.forRoot(routes)], // ルートモジュールでルーティング設定をインポート
exports: [RouterModule] // 他のモジュールでルーティング機能を使うためにエクスポート
})
export class AppRoutingModule { }
“`
RouterModule
とRoutes
は@angular/router
パッケージからインポートします。const routes: Routes = [...]
は、ルーティング規則を定義するRoute
オブジェクトの配列です。@NgModule
のimports
配列でRouterModule.forRoot(routes)
をインポートしています。forRoot()
メソッドは、アプリケーションのルートレベルでルーティングを構成するために使用されます。フィーチャーモジュールでルーティングを定義する場合はRouterModule.forChild(routes)
を使用します。exports: [RouterModule]
は、ルーティング関連のディレクティブ(routerLink
,router-outlet
など)を他のモジュールで使用できるようにエクスポートしています。
ルートを定義する
routes
配列に、URLパスとそれに対応するコンポーネントを定義した Route
オブジェクトを追加していきます。
例として、HomeComponent
と AboutComponent
という2つのコンポーネントがあるとします(これらは ng g c home
と ng g c about
で作成してください)。
“`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’; // 作成したコンポーネントをインポート
import { AppComponent } from ‘./app.component’; // Rootコンポーネント (今回は使いませんが例として)
const routes: Routes = [
{ path: ”, component: HomeComponent }, // パスが空文字列(”)の場合はHomeComponentを表示 (ルートパス)
{ path: ‘about’, component: AboutComponent }, // パスが’/about’の場合はAboutComponentを表示
// { path: ‘items/:id’, component: ItemDetailComponent }, // パラメーター付きのパス
{ path: ‘**’, redirectTo: ”, pathMatch: ‘full’ } // 定義されていないパスはルートパスにリダイレクト (ワイルドカード)
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
“`
- 各ルートオブジェクトは通常
path
とcomponent
プロパティを持ちます。path
: URLのパスセグメントを指定します。先頭の/
は不要です。component
: そのパスに対応して表示するコンポーネントを指定します。
path: ''
: これはアプリケーションのルートパス (/
) を表します。path: '**'
: これはワイルドカードパスで、定義されている他のどのパスにも一致しない場合にマッチします。通常、404ページを表示したり、ルートパスにリダイレクトしたりするために使用されます。redirectTo
: 指定されたパスにリダイレクトします。pathMatch: 'full'
または'prefix'
:redirectTo
と一緒に使用し、リダイレクトの際にパスがどのようにマッチする必要があるかを指定します。'full'
はパス全体が完全に一致する必要があることを意味し、リダイレクトでは通常'full'
を使用します。
ルーティングアウトレット (<router-outlet>
)
ルーティングによって表示されるコンポーネントは、HTMLテンプレートの特定の場所に挿入されます。この挿入場所を指定するのが、<router-outlet>
ディレクティブです。通常、アプリケーションのルートコンポーネント (app.component.html
) に配置します。
“`html
Welcome to {{ title }}!
“`
ブラウザのURLが /
の場合、<router-outlet>
の位置に HomeComponent
が表示されます。URLが /about
の場合、<router-outlet>
の位置に AboutComponent
が表示されます。
ナビゲーション
別のルートに移動する方法は主に2つあります。
-
宣言的ナビゲーション (
routerLink
ディレクティブ): テンプレートでリンクとして定義します。
“`html
Aboutページへ
トップページへ
`routerLink` ディレクティブを使用することで、標準の `<a href="...">` とは異なり、ページの再読み込みなしにSPAとしてナビゲーションが行われます。動的なパスを生成する場合はプロパティバインディング形式 `[routerLink]` を使用し、パスセグメントを配列で指定します。
typescript
2. **プログラム的ナビゲーション (`Router` サービス):** コンポーネントクラスのコード内で、JavaScriptのロジックに基づいてナビゲーションを行います。
// app.component.ts (または任意のコンポーネント)import { Router } from ‘@angular/router’; // Routerサービスをインポート
// … コンポーネントクラス定義
constructor(private router: Router) { // Routerサービスをインジェクション
// …
}navigateToAbout(): void {
this.router.navigate([‘/about’]); // /about パスへ移動
}navigateToItemDetail(itemId: number): void {
this.router.navigate([‘/items’, itemId]); // 例: /items/123 のようなパスへ移動
}
``
Routerサービスをコンストラクターでインジェクションし、その
navigate()メソッドを使います。
navigate()メソッドには、
routerLink` と同様にパスセグメントの配列を渡すことができます。
ルーティング機能は、複雑なSPAにおいてユーザーフレンドリーなナビゲーションを実現するために不可欠です。
TypeScriptの基本的な要素
AngularはTypeScriptで記述されており、開発においてもTypeScriptの使用が強く推奨されています。TypeScriptはJavaScriptに静的型付けやクラスベースのオブジェクト指向などの機能を追加した言語で、開発効率とコードの品質を向上させます。
Angular開発で特によく使われるTypeScriptの機能について簡単に触れておきます。JavaScriptの経験があれば、比較的容易に理解できるはずです。
1. 型付け (Types)
変数の型を指定することで、どのような種類のデータがその変数に格納されるかを明示します。これにより、開発中に型に関するエラーを検出できます。
“`typescript
let name: string = ‘Angular’; // 文字列型
let version: number = 16; // 数値型
let isAwesome: boolean = true; // 真偽値型
let users: string[] = [‘Alice’, ‘Bob’]; // 文字列の配列
let numbers: Array
let person: { name: string, age: number }; // オブジェクト型 (プロパティの型を指定)
person = { name: ‘Charlie’, age: 30 };
let data: any = 100; // どんな型でも許容 (TypeScriptのメリットを損なうため、避けられるなら避ける)
data = ‘hello’;
function greet(personName: string): void { // 関数の引数と戻り値の型
console.log(‘Hello, ‘ + personName);
}
// greet(123); // エラー: 引数の型が異なる
“`
2. インターフェース (Interfaces)
オブジェクトの「形」(どのようなプロパティを持ち、それらがどのような型か)を定義するために使用されます。データの構造を明確にしたり、コードの契約を定義したりするのに役立ちます。
“`typescript
interface User {
id: number;
name: string;
email?: string; // ? を付けると省略可能なプロパティ
}
function displayUser(user: User): void {
console.log(ID: ${user.id}, Name: ${user.name}
);
if (user.email) {
console.log(Email: ${user.email}
);
}
}
let myUser: User = { id: 1, name: ‘Alice’ };
displayUser(myUser);
let anotherUser: User = { id: 2, name: ‘Bob’, email: ‘[email protected]’ };
displayUser(anotherUser);
// let invalidUser: User = { id: 3 }; // エラー: name プロパティが不足
“`
サービスが返すデータの型などをインターフェースで定義することがよくあります。
3. クラス (Classes)
Angularのコンポーネント、サービスなどはすべてクラスとして定義されます。クラスは、プロパティ(データ)とメソッド(振る舞い)を持つオブジェクトの設計図です。
“`typescript
class Person {
name: string;
private age: number; // private はクラス内部からのみアクセス可能
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
greet(): void {
console.log(Hello, my name is ${this.name}.
);
}
getAge(): number { // private プロパティへのアクセスメソッド
return this.age;
}
}
let person1 = new Person(‘Alice’, 30);
person1.greet(); // 出力: Hello, my name is Alice.
console.log(person1.getAge()); // 出力: 30
// console.log(person1.age); // エラー: age は private
“`
クラスの継承 (extends
) やインターフェースの実装 (implements
) なども利用できます。コンポーネントクラスが OnInit
などのライフサイクルインターフェースを実装するのはこの機能を使っています。
4. デコレーター (Decorators)
@Component
, @Injectable
, @NgModule
など、Angularで多用される @
から始まる記号はデコレーターです。デコレーターは、クラス、プロパティ、メソッド、アクセサーにメタデータをアタッチしたり、それらの定義を変更したりするための特別な種類の宣言です。これは、Angularフレームワークがクラスをどのように扱うべきかを知るための情報を提供します。
TypeScriptのこれらの機能は、Angularコードの可読性、保守性、安全性を高める上で非常に重要です。最初からすべてを完璧に理解する必要はありませんが、コード例を見ながら徐々に慣れていくことが大切です。
その他の重要な概念 (簡単に)
ここまでで、Angularの基本的な構成要素であるコンポーネント、モジュール、サービス、ルーティング、そしてデータバインディングとディレクティブといったテンプレート構文の基礎を学びました。これ以外にも、Angularアプリケーションを構築する上で重要ないくつかの概念があります。ここではそれらを簡単に紹介します。
1. HTTPクライアント
外部APIからデータを取得したり、サーバーにデータを送信したりするには、HTTP通信が必要です。Angularは @angular/common/http
モジュールで HttpClient
というサービスを提供しています。
HttpClient
を使用するには、Rootモジュール(AppModule
)に HttpClientModule
をインポートする必要があります。
“`typescript
// src/app/app.module.ts
import { HttpClientModule } from ‘@angular/common/http’; // インポート
@NgModule({
// …
imports: [
// …
HttpClientModule // ここに追加
],
// …
})
export class AppModule { }
“`
サービス内で HttpClient
をインジェクションして使用します。HTTPメソッド(get
, post
, put
, delete
など)に対応するメソッドが用意されています。これらのメソッドは RxJS の Observable を返します。
“`typescript
// src/app/data.service.ts (例: 外部APIからデータを取得)
import { Injectable } from ‘@angular/core’;
import { HttpClient } from ‘@angular/common/http’; // インポート
import { Observable } from ‘rxjs’; // Observable をインポート
interface Todo { // 取得するデータのインターフェースを定義
userId: number;
id: number;
title: string;
completed: boolean;
}
@Injectable({
providedIn: ‘root’
})
export class DataService {
private apiUrl = ‘https://jsonplaceholder.typicode.com/todos’; // ダミーAPIのURL
constructor(private http: HttpClient) { } // HttpClient をインジェクション
getTodos(): Observable
return this.http.get
}
// 例: POSTリクエスト
// createTodo(todo: Todo): Observable
// return this.http.post
// }
}
“`
コンポーネントでサービス経由でデータを取得する際は、返される Observable を購読 (subscribe
) する必要があります。
“`typescript
// src/app/app.component.ts (例: サービスからデータを取得し表示)
import { Component, OnInit } from ‘@angular/core’;
import { DataService } from ‘./data.service’;
import { Todo } from ‘./data.service’; // インターフェースもインポート
import { Observable } from ‘rxjs’; // Observable をインポート
import { tap } from ‘rxjs/operators’; // オペレーターをインポート (今回は tap のみ使用例)
@Component({
// …
})
export class AppComponent implements OnInit {
// …
todos: Todo[] = []; // 取得した Todo リスト
constructor(private dataService: DataService) { }
ngOnInit(): void {
// サービスから Observable を取得し、購読
this.dataService.getTodos().pipe(
tap(data => console.log(‘取得したTodoデータ:’, data)) // デバッグ用のオペレーター
).subscribe(
(data: Todo[]) => { // 成功時のコールバック
this.todos = data;
},
(error) => { // エラー時のコールバック
console.error(‘データ取得エラー:’, error);
},
() => { // 完了時のコールバック (省略可)
console.log(‘データ取得完了’);
}
);
}
}
“`
“`html
Todoリスト (HTTPクライアントの例)
- {{ todo.title }} (完了: {{ todo.completed ? ‘はい’ : ‘いいえ’ }})
“`
非同期処理であるHTTP通信を扱う上で、RxJSのObservableパターンは非常に重要です。subscribe()
しないとリクエストは実行されません。また、コンポーネントが破棄される際に購読を解除 (unsubscribe()
) してメモリリークを防ぐことが推奨されますが、async
パイプを使えばAngularが自動的に管理してくれます。
2. フォーム (Forms)
ユーザーからの入力を扱うフォームは、Webアプリケーションでよく使われる機能です。Angularには、フォームを扱うための2つの異なるアプローチがあります。
- テンプレート駆動フォーム (Template-Driven Forms): テンプレート内でディレクティブ (
ngModel
など) を使用してフォームロジックを記述します。シンプルで基本的なフォームに適しています。FormsModule
が必要です。 - リアクティブフォーム (Reactive Forms): コンポーネントクラス内でフォームコントロールをプログラム的に定義し、管理します。複雑なフォーム、動的なフォーム、厳密なバリデーションが必要な場合に適しています。
ReactiveFormsModule
が必要です。
どちらのアプローチも強力ですが、リアクティブフォームの方がより柔軟でテストしやすいため、大規模なアプリケーションではこちらが推奨される傾向があります。
3. ライフサイクル (Lifecycle Hooks)
Angularコンポーネントやディレクティブには、その生存期間中に特定のタイミングで実行されるメソッドがあります。これらをライフサイクルフックと呼びます。
ngOnChanges
: 入力プロパティの値が変更されたときに呼ばれます。ngOnInit
: コンポーネントが初期化された後に呼ばれます(コンストラクターの後に一度だけ)。データの取得や初期化処理によく使われます。ngDoCheck
: Angularの変更検知メカニズムが実行されるたびに呼ばれます。ngAfterContentInit
: コンテンツ投影(<ng-content>
)されたコンテンツが初期化された後に呼ばれます。ngAfterContentChecked
: コンテンツ投影されたコンテンツが変更検知によってチェックされた後に呼ばれます。ngAfterViewInit
: コンポーネントのビューと子ビューが初期化された後に呼ばれます。DOM操作によく使われます。ngAfterViewChecked
: コンポーネントのビューと子ビューが変更検知によってチェックされた後に呼ばれます。ngOnDestroy
: コンポーネントが破棄される直前に呼ばれます。イベントリスナーの解除やObservableの購読解除など、クリーンアップ処理に使われます。
これらのフックを使用するには、対応するインターフェース (OnInit
, OnDestroy
など) をコンポーネントクラスに実装し、対応するメソッド (ngOnInit()
, ngOnDestroy()
) を記述します。
4. RxJSとObservable
Angularは非同期処理を扱うためにRxJS (Reactive Extensions for JavaScript) というライブラリと、その主要な概念であるObservableを広く利用しています。HTTPクライアントのメソッドや、Angularのイベントシステム、ルーティングのパラメータなど、多くの場所でObservableが使われています。
Observableは、時間の経過とともに複数の値を「発行」するストリームのようなものです。これを購読 (subscribe
) することで、発行された値を受け取ったり、エラーを処理したり、完了を通知されたりできます。
“`typescript
import { Observable } from ‘rxjs’;
const observable = new Observable(subscriber => {
subscriber.next(1);
subscriber.next(2);
subscriber.next(3);
setTimeout(() => {
subscriber.next(4);
subscriber.complete(); // 完了を通知
}, 1000);
});
console.log(‘購読開始’);
observable.subscribe({
next: (value) => console.log(‘受け取った値:’, value),
error: (err) => console.error(‘エラー:’, err),
complete: () => console.log(‘完了’),
});
console.log(‘購読開始のコードは終了’);
“`
RxJSには、Observableを変換したりフィルタリングしたりするための強力なオペレーター(map
, filter
, tap
, switchMap
など)が多数用意されています。Angularで効果的に開発するには、RxJSとObservableの基本的な理解が不可欠です。
5. テスト (Testing)
Angular CLIでプロジェクトを生成すると、単体テスト (Unit Testing) とエンドツーエンドテスト (End-to-End Testing) のための設定が自動的に含まれます。
- 単体テスト: 各コンポーネント、サービス、パイプなどが個別に正しく動作するかをテストします。Jasmine (テストフレームワーク) と Karma (テストランナー) がデフォルトで使われます。
ng test
コマンドで実行します。 - エンドツーエンドテスト: アプリケーション全体がユーザーの視点から正しく動作するかをテストします。Protractor がデフォルトでしたが、現在は Cypress や Playwright などが推奨されています。
ng e2e
コマンドで実行します(設定が必要)。
テストはアプリケーションの品質と保守性を保つ上で非常に重要です。
6. ビルドとデプロイ
開発サーバー (ng serve
) は開発用に最適化されていますが、本番環境にデプロイする際には、コードを最適化して静的なファイルにビルドする必要があります。これには ng build
コマンドを使用します。
“`bash
ng build –configuration production
Angular 9+ では –configuration production がデフォルトになりました
ng build
“`
このコマンドを実行すると、最適化されたJavaScript、CSS、HTMLファイルが dist/
ディレクトリ内に生成されます。この dist/
ディレクトリの内容を、Webサーバー(Apache, Nginxなど)や静的ホスティングサービス(Netlify, Vercel, Firebase Hosting, GitHub Pagesなど)に配置すればデプロイ完了です。
ng build
は、AOT (Ahead-of-Time) コンパイル(実行前にテンプレートをJavaScriptコードにコンパイル)、ツリーシェイキング(未使用コードの削除)、コード分割などの最適化を自動で行います。
これからどう学ぶか?
この記事では、Angularの最も基本的な概念と、それらがどのように連携してアプリケーションを構築するかを概観しました。しかし、Angularにはさらに多くの機能や応用パターンがあります。
- フォームのバリデーション、カスタムバリデーター
- コンポーネント間のより高度な連携 (
@Input
,@Output
, ViewChild, ContentChild) - カスタムディレクティブ、カスタムパイプの作成
- インターセプターを使ったHTTPリクエスト/レスポンスの共通処理
- 状態管理パターン (NgRx, Akitaなど)
- アニメーション
- 国際化 (i18n) とローカライズ (l10n)
- サーバーサイドレンダリング (SSR) とユニバーサル
- プログレッシブWebアプリケーション (PWA) 化
- テストの書き方と実践
これらのトピックは、本格的なAngularアプリケーション開発に進むにつれて必要になってくるでしょう。
学習を進める上での次のステップとしては、以下がおすすめです。
- 実際に手を動かす: この記事で学んだ概念を使って、簡単なアプリケーションをゼロから構築してみましょう。Todoリスト、簡単なブログ、フォームを使ったデータ入力画面など、小さなプロジェクトから始めるのが良いでしょう。
- 公式ドキュメント: Angularの公式ドキュメントは非常に充実しており、各機能の詳細な説明やAPIリファレンスが載っています。困ったときはまず公式ドキュメントを参照しましょう。(英語ですが、最近は日本語翻訳も進んでいます)
- チュートリアルやコース: 公式のチュートリアル(Tour of Heroesなど)や、Udemy, Coursera, Pluralsightなどのオンライン学習プラットフォームで提供されているAngularコースを受講するのも効果的です。
- コミュニティに参加する: Stack Overflowで質問したり、Angular関連の技術ブログを読んだり、Meetupなどのコミュニティイベントに参加したりすることで、他の開発者から学んだり、最新情報を得たりできます。
- GitHubでコードを読む: オープンソースのAngularプロジェクトのコードを読むことで、実際の開発現場でのコードの書き方や設計パターンを学ぶことができます。
Angularは多機能で学習曲線がやや急かもしれませんが、一度基本をマスターすれば、堅牢で保守性の高い大規模なWebアプリケーションを効率的に開発できるようになります。
まとめ
この記事では、初心者向けにAngularの基本を徹底解説しました。
- AngularはGoogleが開発するSPA構築のためのフレームワークであること
- コンポーネントがAngularアプリケーションの基本的なUIブロックであること
- データバインディング(補間、プロパティ、イベント、双方向)でコンポーネントとテンプレートが連携すること
- ディレクティブ(
*ngIf
,*ngFor
,[ngClass]
,[ngStyle]
など)がDOM要素を操作すること - パイプがテンプレートでのデータ表示形式を変換すること
- モジュール(NgModule)がコードを整理し、アプリケーション構造を定義すること
- サービスがビジネスロジックやデータ管理を担い、依存性注入(DI)でコンポーネントから利用されること
- ルーティングがSPAでの画面遷移を管理すること
- TypeScriptの基本的な型付け、インターフェース、クラス、デコレーターがAngular開発で重要であること
- HTTPクライアント、フォーム、ライフサイクルフック、RxJS、テスト、ビルドといった関連概念
Angularの学習は一歩ずつ進めることが重要です。この記事が、Angularの世界へ踏み出すための一助となれば幸いです。焦らず、楽しみながら学習を進めてください。
Happy Coding!