やること
Angular(v19)のチュートリアル1つ目、「ブラウザでAngularを学ぶ」を一通りやっていきます。
なお、ブラウザだとフォルダ構成やファイルが全く意味不明なので、本記事ではソースコードをダウンロードしてローカルで行います。
実況開始
早速始めます。まずは準備からです。
事前準備
-
適当なフォルダを作成します。ここでは
AngularTutorial
という名前にします。 -
AngularTutorial
直下に移動してnodeのバージョンを22に以上にし、コマンドラインでnpm install @angular/cli@19.0.0
を実行してAngular(v19)をローカルインストールします。 -
ng new learn-angular(好きな名前でいいです)
を実行し、新規プロジェクトを作成します。出来たらlearn-angular
直下に移動します。 -
展開したフォルダ内のsrcフォルダをコピーし、先ほどコマンドで作成したプロジェクト内のsrcフォルダをそれに差し替えます。
-
ng serve
を実行し、出てきたリンクにアクセスします。アクセス先のページに「Welcome To Angular!」と表示されているはずです。
準備は以上でOKです。
ここから先は手元のソースコードを修正しながら進めていきます。
学習開始
各タイトルをクリックすると公式サイトの該当ページにジャンプできます。
0. チュートリアル
Angularを理解するためにはHTML、CSS、JavaScriptの基本を知っておく必要があるそうです。たしかに。
1. Angularのコンポーネント
Angularはアプリケーションの構成をコンポーネント単位で考え構築していきます。
まずは手元のsrc/app/app.component.ts
の内容を、チュートリアルの本章のページに表示されているものに書き換えましょう。コピペすればいいです。なおこの操作は各章の開始ごとにやることになります。
1-1. コンポーネントテンプレートの更新
src/app/app.component.ts
のtemplateを更新します。
1-2. コンポーネントスタイルの更新
同様に、styleを追加します。
紫色で「Hello Universe」と出ていればOKです。各ページの「解答を表示」で確認しながら進めていきましょう。
2.コンポーネントの更新
今まではただのHTML・CSSでしたが、ここからはコンポーネントのTypeScriptクラスを使ってアプリを制御していきます。
2-1. cityというプロパティを追加
まずは変数を準備します。
2-2. コンポーネントテンプレートの更新
テンプレートに埋め込みます。{{}}で囲む書き方を覚えましょう。
2-3. 補間のさらなる練習
はい。
3.コンポーネントの組み立て
ここからはコンポーネントが複数出てきます。
コンポーネントはng generate component {コンポーネント名}}
で作成することが一般的ですが、小さいコンポーネントであればべた書きすることもあるようです。
3-1. UserComponentへの参照を追加
AppComponentにUserComponentを埋め込みます。「Username: youngTech」と表示されるはずです。
3-2. さらにマークアップを追加
section要素にするだけです。
4. コンポーネントの制御フロー @if
いままでは変数に値を入れて中身を表示するだけでしたが、実はもっとプログラミングっぽい制御が可能です。まずはif文です。v16まで(たしか)の*ngIf
よりもかなり分かりやすいですね。素晴らしい。
4-1. isServerRunningというプロパティを作成する
まずは判定材料となるプロパティを作ります。
4-2. テンプレートで@ifを使用する
よくあるif文のまんまですね。
4-3. テンプレートで@elseを使用する
elseも追加します。falseを代入して動きを確かめましょう。
5. コンポーネントの制御フロー @for
次はfor文です。
5-1. usersプロパティを追加
for文で使う配列を作ります。
5-2. テンプレートを更新
for文を使います。track
が「なんじゃい」って感じがします。
6. Angularのプロパティバインディング
HTMLの属性などを、クラスのプロパティの値から設定することが出来ます。
6-1. isEditableというプロパティを追加する
普通にクラスにプロパティを追加します。
6-2. contentEditableにバインドする
HTMLにはcontentEditable
という属性が存在します。それを`isEditable'の値により設定してみます。今回はtrueです。
ページの上部をクリックすると、下記画像のようにその要素内の文字列を編集できることが確認出来ます。
7. イベント処理
ボタンクリックなど、ユーザーの操作に応答した処理を実装します。
7-1. イベントハンドラーを追加
onMouseOver()関数内にメッセージを設定する処理を追加します。
7-2. テンプレートイベントにバインド
テンプレート側にonMouseOver()関数を発動させるようにバインドさせます。
他にもいろいろなイベントがありますよ。
https://web-designer.cman.jp/javascript_ref/event_list/
8. @Input を使ったコンポーネント間の通信
親コンポーネントから子コンポーネントへ値を渡すことが出来ます。
なお本章ではapp.component.ts
の他にuser.component.ts
も作成する必要があります。ファイルを追加しましょう。
8-1. @Input プロパティを定義する
AppComponent
からUserComponent
に値を渡すことを目指します。
まずはUserComponent
の方に@Input()プロパティを追加し、そのプロパティをテンプレートに表示させるようにしましょう。
8-2. @Input プロパティに値を渡す
AppComponent
のテンプレートに値を渡すコードを記述します。
9. @Outputを使ったコンポーネント間の通信
逆に、子コンポーネントから親コンポーネントに値を返すことも出来ます。こちらは少し難しいかもしれません。
本章ではchild.component.ts
を追加する必要があります。
9-1. @Outputプロパティを追加する
まずはChildComponent
に@OutputプロパティであるaddItemEvent
を追加します。
9-2. addItemメソッドを完成させる
亀をemitするメソッドを完成させましょう。
9-3. AppComponentテンプレートを更新する
親コンポーネント側に子コンポーネントのイベントを購読するコードを追記します。
$event
に子コンポーネントからemitされたものが入っているようです。
やっぱり少し難しいですね。
ここまでが基礎の基礎って感じみたいです。次からはまた少し本格的になります。
10. 遅延ビュー
様々な事情によりロードを遅らせたい場合、遅延可能ビューで実現出来ます。
app.comments.component.ts
を追加しましょう。
10-1. コメントコンポーネントの周りに @defer ブロックを追加する
遅延させたいコンポーネントを@defer{}
で囲むと遅延させることが出来ます。
10-2. プレースホルダーを追加する
@placeholder{}
ブロックに読み込み前の表示内容を記述出来ます。ある種のif~else文みたいですね。
10-3. ロードブロックを追加する
@loading{}
ブロックにロード中の表示内容を記述出来ます。if~else if~else文みたいですね。
10-4. 最小期間を追加する
目をこらすとちらつきが確認できるはず。
minimum
を設定することで解消されます。2秒はちょっと長いですね。
10-5. ビューポートトリガーを追加する
一旦黙って追加しましょう。
10-6. コンテンツを追加する
ビューポートトリガーを実感するためのコンテンツを追加します。
スクロールが到達した時点でローディングが開始されることが分かります。
なんだか一気に本格的になりました。が、難易度自体はそれほどだと思うのでここから先も頑張りましょう。
11. 画像の最適化
画像の処理です。もう一度ページ右上からダウンロードして、public/assets
をコピーして手元のコードのsrc/asset
を差し替えましょう。logo.svg
が適切なパスにいればOKです。また、AppComponentのテンプレートにUserComponentを埋め込むなどして対象のテンプレートを表示させましょう。
画像が表示出来ないので後回し。
svgをちょっと勉強しないとだめな感じかも。分かる方教えて頂けますと幸いです。
12. ルーティングの有効化
ページ遷移を実装します。3章に渡るようなので、めげずに頑張りましょう。
12-1. app.routes.ts ファイルの作成
よく分からんが黙って書く。
12-2. プロバイダーへのルーティングの追加
Routerをアプリに認識させる。
12-3. コンポーネントへの RouterOutlet のインポート
コンポーネントにインポートする。
よく分かりませんが、ルーターを作ってアプリに登録してコンポーネントにインポートしました。まだ遷移出来る状態ではないです。なのに次でsrc
ごと書き換わるのが少しモヤっとします(多分筆者の理解不足)。
13 ルートを定義する
ページ遷移の続きです。
user/user.component
が隠されてしまっているので、もう一度ダウンロードしてsrc
フォルダごと差し替えましょう。
13-1. app.routes.tsでルートを定義する
チュートリアルに従って、HomeComponent
およびUserComponent
へのパスを設置します。
13-2. ルート定義にタイトルを追加する
タイトルも追加してあげます。
これでページ遷移出来る状態になりました。おめでとうございます。
次章ではページ遷移を更にブラッシュアップさせていきます。
14. RouterLinkを使ったルートへのリンク
現状、ページ遷移時にページ全体がリロードされてしまい、やや不快nちらつきが発生しています。本章ではこの問題を解決します。
14-1. RouterLinkディレクティブのインポート
RouterLink
というのをインポートします。
14-2. テンプレートへのrouterLinkの追加
hrefをrouterLinkに書き換えます。
実際に動かしてみましょう。画面遷移の際にちらつきがなくなりましたね。
15. フォーム
ユーザーからの入力を受け取るフォームをAngularで実現します。「Angularで実現」とはすなわち、「ユーザーからの入力値をコンポーネントのクラスのプロパティにバインドする」ということです。
フォームは全4章に渡る長編となり、本章ではAngularでフォームを導入する初手を学びます。
15-1. 入力フィールドの作成
まずはinputタグの作成です。ここは普通のHTMLの話ですね。
15-2. FormsModuleのインポート
FormsModuleというのをインポートしましょう。
15-3. 入力の値へのバインディングの追加
inputタグに[(ngModel)]="変数名"
としてバインディングします。
ページ上でバインディングされていることが確認できるはずです。
16. フォームコントロールの値を取得する
本章ではフォームの値をコンポーネントのクラスで受けて処理する方法を学びます。
16-1. テンプレートに入力フィールドの値を表示する
まずはベタっと表示させます。前の章と同じ状態になります。
16-2. 入力フィールドの値を取得する
ボタンクリック時に発動する関数を作ります。this.
でプロパティにアクセスしましょう。Ialert()`がどんな動きをするかは動かしてみてのお楽しみです。
17. リアクティブフォーム
Angularのフォームの書き方にはテンプレート駆動型とモデル駆動型の2種類が存在します。
今までは(ngModel)を導入するなど直接templateに書き込んでいましたが、これらはテンプレート駆動型です。
本章からはモデル駆動型の書き方を学んでいきます。モデル駆動型は少しテクニカルな代わりに柔軟性が高いため、複雑なロジックを実現することが出来たりします。
17-1. ReactiveFormsモジュールのインポート
モデル駆動型で書くためにリアクティブフォームというのを使います。
まずはそれをインポートしましょう。
17-2. FormGroupオブジェクトをFormControlsで作成
とりあえず見よう見まねで書きます。
17-3. FormGroupとFormControlsをフォームにリンク
作成したFormGroupオブジェクトの各プロパティをテンプレート内の入力箇所にリンクさせます。
17-4. フォームの更新を処理
フォームに入力された値を表示出来るようにします。
17-5. FormGroupの値にアクセス
submitボタンを押した時に発動する関数を作り、入力値を表示する処理を追加します。
ここは前の章と同じです。
17-6. ngSubmitをフォームに追加
ボタンに(click)を付けても同じ挙動になりますが、(ngSubmit)というイベントハンドラーを使うのが適切なようです。
18. フォームの検証
フォームの値が適切なものかどうかをチェックする機能を追加します。こういったチェックのことをバリデーションと呼んだりします。
18-1. バリデーターのインポート
バリデーションチェックを実装するためのライブラリをインポートします。
18-2. フォームへの検証の追加
各FormControl
に引数としてバリデーターを渡すことが出来ます。複数の場合は配列にして渡します。
18-3. テンプレートでのフォーム検証の確認
フォームの入力状態が正しいかどうかの判定結果はフォームグループのvalid
プロパティが持っています。
これをボタンのdisabled
属性に渡すことで、不適切な入力のときは送信出来ないようにします。
フォームに関しては以上です。お疲れ様でした。
19. 注入可能なサービスの作成
依存性の注入は、Angularが実行時にアプリケーションが必要とするリソースを_提供_できる機能であると考えてください。
なるほど。。
筆者は語れるほど詳しくないですが、「デザインパターン」「依存性の注入」あたりを調べると雰囲気がつかめると思います。
19-1. @Injectableデコレーターを追加する
デコレータを追加することで、CarServiceを注入可能にします。
19-2. デコレータを構成する
rootに提供することで、アプリ全体で利用可能なサービスとして登録されます。
ここで終わっていますが、AppComponentの方のコードも確認しましょう。CarServiceをインポートして、コンポーネントにinjectして使用しています。
20. インジェクトベースの依存性の注入
19章でやったのはインジェクトベースの依存性の注入です。他に、コンストラクタベースの依存性の注入というのもあります。本章では改めてインジェクトベースの依存性の注入を学びます
20-1. CarService を注入する
AppComponentにCarServiceを注入します。
20-2. carService インスタンスを使用する
CarServiceのgetCars()メソッドで得られる文字列を加工してdisplayプロパティに代入します。
20-3. AppComponent テンプレートを更新する
表示させます。
21. コンストラクタベースの依存性の注入
続いてコンストラクタベースの依存性の注入について学びます。
オブジェクト指向を知っていると分かるのですが、こちらの方式の方が依存関係が明瞭です。
21-1. コンストラクタベースのDIを使用するようにコードを更新する
20章ではクラスのプロパティとしてサービスを受け取っていましたが、本章ではクラスのコンストラクターの引数として設定しています。
サービスの注入については以上です。
22. パイプ
パイプは、日時の表記を地域ごとに設定するなど、テンプレート内のデータを変換するために用いられる関数です。
22-1. LowerCase パイプをインポートする
本章ではサンプルとしてLowerCaseパイプを使用します。小文字に変換するやつです。
22-2. パイプをテンプレートのインポートに追加する
テンプレートで使うので忘れずに入れておきましょう。
22-3. パイプをテンプレートに追加する
これがパイプの書き方の一番シンプルなものです。
大文字も含んでいるはずの文字列が全て小文字で表示されていることが確認できると思います。
23. パイプによるデータのフォーマット
パイプは関数です。ということは当然引数を持つパイプも存在します。本章ではそのような種類のパイプの使い方をいくつか書いてみます。
具体例を見ていくだけでノーコメントで失礼します。
23-1. DecimalPipe を使用して数値をフォーマットする
23-2. DatePipe を使用して日付をフォーマットする
23-3. CurrencyPipe を使用して通貨をフォーマットする
なおパイプ一覧は公式ドキュメントのこのページに書いてあります。
24. カスタムパイプの作成
ここまではAngularが持っているパイプを使ってきましたが、オリジナルでパイプを作成し使用することも出来ます。
24-1. ReversePipe の作成
「reverse」という名前をつけてアプリ上で使えるようにします。
24-2. transform 関数の実装
ここは普通のプログラミングです。文字列を反転させる処理を書きます。
24-3. テンプレートで ReversePipe を使用する
ここまできたら後は22章と同じように、インポートしてパイプをくぐらせてあげればOKです。
文字列が逆さまになりましたね。
おわりに
お疲れ様でした!!
全部やり切ると結構疲れますね。
画像が表示出来なかったのが心残りなので気が向いたら調査してみます。