このエントリーをはてなブックマークに追加

もくじ

今回のゴール

前回までで、ng new コマンドで雛形アプリを作り、そのコードを読み解くことでAngularアプリがどのような仕組みで動作するのかを学んできました。

いよいよ今回からは実際のアプリケーション開発に入っていきます!

この連載では、簡単なTodoアプリを作っていきます。今回は雛形アプリに1つだけ新しくコンポーネントを追加して、その動作を確認するところまでです。

前回、Angularアプリがモジュールとコンポーネントの組み合わせで作られていることを学びましたが、今回はコンポーネントの中身がどのようになっているのかをより深く理解することを目指しましょう :muscle:

初めてのコンポーネント作成

早速コンポーネントを新規作成してみましょう。今回はTodoアプリのうち、Todoを編集するためのフォーム のコンポーネントを作成していきます。

ちなみに、ここから先は、作業によるコード差分を管理しやすいよう、gitなどを使ってコードをバージョン管理しながら手を動かしていくことをおすすめします :+1:

さて、ng コマンドには、ng generate という様々なファイルを自動生成するためのコマンドが用意されています。新しくコンポーネントを作成する際には ng generate component コマンドを使うのが便利です。

プロジェクトのルートディレクトリ(/path/to/angular-todo 直下)にいる状態で、以下のコマンドを実行してみてください。

$ ng generate component components/todo-form

実行すると、以下のようなディレクトリ構成で4つのファイルが生成されます。

$ tree src/app/components
src/app/components
└── todo-form
    ├── todo-form.component.html
    ├── todo-form.component.scss
    ├── todo-form.component.spec.ts
    └── todo-form.component.ts

前回学んだとおり、コンポーネントとは「HTMLテンプレート・スタイル・ロジックをひとまとめにしたUI部品」のことでした。

ng generate component コマンドで生成した4つのファイルのうち、todo-form.component.ts がコンポーネントのロジックを記述する本体のクラスファイルです。中身を覗いてみましょう。

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-todo-form',
  templateUrl: './todo-form.component.html',
  styleUrls: ['./todo-form.component.scss']
})
export class TodoFormComponent implements OnInit {

  constructor() { }

  ngOnInit() {
  }

}

TodoFormComponent クラスが定義されていますが、中身は特に何も処理が書かれていない状態になっています。

その上の @Component({}) で囲まれた部分を見てみると、前回コードリーディングしたルートコンポーネント(AppComponent)と同じように、

  selector: 'app-todo-form',
  templateUrl: './todo-form.component.html',
  styleUrls: ['./todo-form.component.scss']

といった記述がありますね。

どうやら templateUrl styleUrls によって、コンポーネントをレンダリングするためのHTMLテンプレートと、そのテンプレートに適用するスタイルを指定するようです :ok_hand:

そして selector: 'app-todo-form' ですが、ここは AppComponent においては selector: 'app-root' となっていた部分です。ここで指定した文字列が、このコンポーネントをビューに配置する際のタグ名になります。

つまり、別のコンポーネントのHTMLテンプレート内に <app-todo-form></app-todo-form> というタグを書くと、その箇所に TodoFormComponent を挿入することができるというわけです :ok_hand:

COLUMN

ここでは、ng generate component components/todo-form というコマンドで TodoFormComponent を生成しましたが、単に ng generate component todo-form とだけ書いても実行可能です。 作りたいコンポーネントの名前の前に、今回のように components/ などと格納箇所を示すディレクトリパス(src/app からの相対パス)を付け足すことで、任意の場所にコンポーネントのファイル群を生成することができるのです。

今回はより整理しやすいディレクトリ構成とするために、components/ 配下にコンポーネントのファイル群を格納するようにしました。

ng generate component コマンドで利用できるオプションなど、より詳しい情報は 公式のリファレンス をご参照ください。

モジュールへの登録

ところで、コンポーネントは作るだけではダメで、モジュールに登録することでそのモジュール内で利用できるようになる のでしたよね。今回作った TodoFormComponent も当然ながらモジュールに登録することが必要です。

雛形アプリの時点で git commit していた人は、この時点で git diff してみてください。src/app/app.module.ts に以下のような差分が出ているのではないでしょうか。

import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';
+ import { TodoFormComponent } from './components/todo-form/todo-form.component';

@NgModule({
  declarations: [
-   AppComponent
+   AppComponent,
+   TodoFormComponent
  ],
  imports: [
    BrowserModule

そう、ng generate component コマンドを使ってコンポーネントを生成すると、自動でルートモジュールにコンポーネントを登録してくれる のです :+1:

これで、ルートモジュール内で TodoFormComponent を自由に使えるようになりました。

作ったコンポーネントをアプリに組み込んでみる

では、いよいよ TodoFormComponent をアプリに組み込んで表示させてみましょう。

src/app/app.component.html の中身を丸ごと削除して、<app-todo-form></app-todo-form> という一行だけが書かれた状態にしてみてください。

- <!-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -->
- <!-- * * * * * * * * * * * The content below * * * * * * * * * * * -->
- <!-- * * * * * * * * * * is only a placeholder * * * * * * * * * * -->
- <!-- * * * * * * * * * * and can be replaced. * * * * * * * * * * * -->
                :
                略
                :
- <!-- * * * * * * * * * * End of Placeholder * * * * * * * * * * * -->
- <!-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -->
-
-
+ <app-todo-form></app-todo-form>

ng serve --open で以下のような画面が表示されていれば成功です :+1:

TodoFormComponent のHTMLテンプレートである src/app/todo-form/todo-form.compoentn.html の中身を覗いてみてください。

<p>todo-form works!</p>

となっていますね。

ルートコンポーネントのHTMLを <app-todo-form></app-todo-form> という一行だけにしたので、TodoFormComponent のHTMLだけが表示されている状態になったわけです :+1:

Todoオブジェクトの型を決めておく

さて、今後いくつかのコンポーネントを追加してTodoアプリを作り込んでいくわけですが、その際にやり取りするデータの型が決まっていると何かと楽になるので、今のうちにTodoオブジェクトの型を作っておきましょう。

$ mkdir src/app/models
$ touch src/app/models/todo.ts

src/app/models/todo.ts というファイルを作って、以下のようなコードを書いてください。

export interface Todo {
  name: string;
  isDone: boolean;
}

この、nameisDone という2つのプロパティを持った Todo インターフェースを使ってデータのやり取りをしていきます :+1:

Todoオブジェクトを画面から編集できるようにする

それではいよいよ、Todoオブジェクトを画面から編集できるようにしていきましょう :muscle:

コンポーネントクラスを修正

src/app/components/todo-form/todo-form.component.ts に以下のコードを追記してみてください。

import { Component, OnInit } from '@angular/core';
+ import { Todo } from '../../models/todo';

@Component({
  selector: 'app-todo-form',
  templateUrl: './todo-form.component.html',
  styleUrls: ['./todo-form.component.scss']
})
export class TodoFormComponent implements OnInit {
+
+ public todo: Todo = {
+   name: '',
+   isDone: false,
+ };

  constructor() { }

  ngOnInit() {
  }

}

追記したコードの意味は以下のとおりです。

  • 先ほど作成した Todo インターフェースの定義ファイルをimportした上で
  • Todo 型のpublicなクラス変数 todo を宣言し
  • 初期値として { name: '', isDone: false } を代入している

まだTypeScriptの文法に戸惑いがあるかもしれませんが、やっていること自体はごく簡単ですね :+1:

HTMLテンプレートを修正

では続いて、画面を作り込んでいきましょう。

src/app/components/todo-form/todo-form.component.html を以下のように修正してください。

- <p>todo-form works!</p>
+ <input type="text" [(ngModel)]="todo.name">
+ <input type="checkbox" [(ngModel)]="todo.isDone">

<input> タグを使って、Todoの名前入力用のテキストフィールドと完了済みかどうかのチェックボックスを設置しています。

が、それぞれに何やら [(ngModel)]="todo.name" [(ngModel)]="todo.isDone" という記述がありますね :thinking:

実は、ngModel はAngularに標準で用意されているディレクティブ(ビューで利用できる命令の一種)の1つで、双方向バインディング を実現するもっとも基本的な手段になります :muscle:

双方向バインディングとは、コンポーネント本体とビューの間でデータを同期する仕組みのことで、この場合、画面上でテキストフィールドの値を書き換えたり、チェックボックスのON/OFFを切り替えたりするたびに、TodoFormComponent クラスのクラス変数 todonameisDone の値がリアルタイムで変更されます。

ちなみに、「双方向 」というだけあって、逆にクラス内で todo に何かを代入する処理を実行すると、画面側にもそれが反映されます。(今回は、{ name: '', isDone: false } を初期値として代入しているので、画面の初期表示は 名前:空欄 完了済:チェックなし となるはずです :+1:

ngModelを使うために、FormsModuleをインポート

先ほど、双方向バインディングを実現するためにHTMLテンプレート内で ngModel を使用しましたが、実はこの機能は ng new しただけの雛形アプリには含まれていません。

ngModel を利用するためには、Angular標準の FormsModule というモジュールを追加でインポート する必要があります :muscle:

Angularには「モジュール」という機構があり、必要に応じて複数のモジュールを組み合わせてアプリを構築できるようになっていることは前回ざっくりお伝えしたかと思います。「モジュールを組み合わせる」と表現しましたが、より具体的には、あるモジュールに他のモジュールをインポートする ことによってそれを実現します。

今回は、AppModuleFormsModule をインポートする ことで、AppModule 内で FormsModule が持っている ngModel という機能を使えるようにしておきます :+1:

具体的には、src/app/app.module.ts に以下のようなコードを追記すればOKです。

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
+ import { FormsModule } from '@angular/forms';

import { AppComponent } from './app.component';
import { TodoFormComponent } from './components/todo-form/todo-form.component';

@NgModule({
  declarations: [
    AppComponent,
    TodoFormComponent
  ],
  imports: [
    BrowserModule,
+   FormsModule,
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

@NgModule({}) の中の imports: [] という配列に、FormsModule を追加しただけですね :+1:

動作確認

ここまでで、無事にTodoオブジェクトを画面から編集できるようになりました! :tada:

画面の状態はこんな感じになっているかと思います。テキストフィールドとチェックボックスで、todo 変数の中身を変更することができます。

…が、実際に変更できているのかどうかが見えないので、何の手応えもありませんね :scream:

というわけで、todo 変数の中身を画面に表示するようにして、実際に値が変更されていることを目視できるようにしてみましょう :muscle:

src/app/components/todo-form/todo-form.component.html に以下の一行を追記してみてください。

<input type="text" [(ngModel)]="todo.name">
<input type="checkbox" [(ngModel)]="todo.isDone">
+ {{ todo|json }}

{{ }} は、コンポーネントが持つクラス変数をビューに表示するためのAngularのテンプレート記法です。

単に {{ todo }} としてしまうと、オブジェクトである todo を文字列として表現できず [object Object] といった表示になってしまうため、ここでは Angular標準の json パイプ を使って、todo の中身をJSON形式で表現した文字列を画面に表示するようにしてあります。

この状態で画面を操作してみると、以下のように画面の入力に合わせて todo の中身が同期的に変更されていることが分かると思います。これが双方向バインディングです :raised_hands:

次回予告

というわけで、今回は実際のTodoアプリを作るにあたり、Todoを編集するためのコンポーネントを新たに作成し、中身を実装してきました。コンポーネントをアプリに組み込む手順や、クラスファイルとHTMLテンプレートの関係などが前回よりも深くご理解いただけたのではないかと思います。

次回はTodoアプリの開発をさらに進めるべく、Todo一覧画面の実装に取り組んでいきます。

お楽しみに! :raised_hands:


このエントリーをはてなブックマークに追加

もくじ

今回のゴール

前回作成した雛形アプリのソースコードを覗いてみて、Angularアプリが動く仕組みをざっくり理解することを目指しましょう。

本記事では、ngコマンドによって隠蔽されているwebpackについての記述は割愛しています。

Angularアプリが動作する仕組み

ng serve は何をしている?

前回、ng new で作成した雛形アプリを ng serve コマンドで起動しましたね。このときアプリ内部では何が起こっているのかを簡単に確認してみましょう。

起点となっているファイルは、angular.json です。

Angularアプリのソースコードには angular.json というアプリケーション全体の設定を行うためのファイルがあり、ng serve コマンドはこのファイルで設定されている内容を元にアプリケーションを起動します。

angular.json の中を見てみると、以下のような箇所があります。

"index": "src/index.html",
"main": "src/main.ts",

これらの設定により、ng serve コマンドでアプリを起動すると、src/main.ts がエントリポイントとして読み込まれ、プログラムの実行結果が src/index.html にレンダリングされます :+1:

main.ts は何をしている?

では、その main.ts は何をしているのでしょうか。

ファイルを開いてみると、以下のような簡素なコードが書かれています。

import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from './app/app.module';
import { environment } from './environments/environment';

if (environment.production) {
  enableProdMode();
}

platformBrowserDynamic().bootstrapModule(AppModule)
  .catch(err => console.error(err));

ポイントは最後から2行目の

platformBrowserDynamic().bootstrapModule(AppModule)

です。

なんとなく、「AppModuleを」「ブラウザ環境向けに」「起動する」 というようなことをしているっぽいコードですね。

また、よく見ると4行目に

import { AppModule } from './app/app.module';

とあり、どうやら AppModule とやらは src/app/app.module.ts ファイルから読み込まれているようです。

import文においてファイル拡張子 .ts は省略することが可能です。

AppModule の中身はどうなっている?

少し深追いしてみましょう。

main.ts はどうやら src/app/app.module.ts から読み込んだ AppModule というものを起動するという仕事をしているようでした。

では、その AppModule の中身はどうなっているのでしょうか?実際に覗いてみましょう。

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

なんだかゴチャゴチャと書かれていますね :thinking:

難しいことはよく分かりませんが、

import { AppComponent } from './app.component';
  declarations: [
    AppComponent
  ],
  bootstrap: [AppComponent]

あたりを見るに、どうやら src/app/app.component.ts から AppComponent とやらを読み込んで、それを起動するといった仕事をしていそうです。

AppComponent の中身はどうなっている?

もう少しだけ深追いしてみましょう。

src/app/app.component.ts の中身を確認すると、以下のようになっています。

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent {
  title = 'angular-todo';
}

やっと html とか scss とかのファイル名が出てきましたね :bulb:

試しに src/app/app.component.html の中身を覗いてみてください。やたらと長いHTMLが出てきますが、よくよく見てみると

この画面のHTMLが書かれている気がします!

つまり、

  • main.tsAppModule を起動する
  • AppModuleAppComponent を読み込んでいる
  • AppComponentapp.component.html を読み込んでいる

という構造になっているように見えますね :+1:

index.html には何が書いてある?

少し話を戻して、

ng serve コマンドでアプリを起動すると、src/main.ts がエントリポイントとして読み込まれ、プログラムの実行結果が src/index.html にレンダリングされます :+1:

と言ったうちの、src/index.html のほうには何が書かれているかを確認してみましょう。

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>AngularTodo</title>
  <base href="/">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
  <app-root></app-root>
</body>
</html>

これまた簡素なHTMLですね。

ポイントは最後から3行目の

  <app-root></app-root>

です。どこかで見たことがあるぞ?と思った人は鋭い :sunglasses:

src/app/app.component.ts の中身を思い出してみましょう。

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent {
  title = 'angular-todo';
}

4行目に

  selector: 'app-root',

とありますね。

詳しくは分かりませんが、どうやら AppComponent が読み込んでいた app.component.html の中身は、index.html<app-root></app-root> の部分にレンダリングされる仕組みになっているようです :bulb:

モジュールとコンポーネント

ここまでで、

  1. angular.json に、src/main.ts の実行結果を src/index.html にレンダリングする、という設定が記載されている
  2. src/main.tsAppModule を読み込んで起動している
  3. AppModuleAppComponent を読み込んで起動している
  4. AppComponent で読み込んでいる src/app/app.component.html のHTMLが、src/index.html に埋め込まれる形でレンダリングされている

といった関係性が見えてきました。

Angularでは、アプリを構成する機能を モジュール という単位で分割して作成できるようになっており、1つ以上のモジュールを組み合わせることでアプリ全体を構成します。

雛形アプリでは、AppModule というモジュールが1つだけ存在しています。AppModule は、アプリ起動時に最初に読み込まれる特別なモジュールで、ルートモジュールと呼ばれます。(どんな手順で読み込まれるかは、先に読んできた通りですね :ok_hand:

また、Angularでは、HTMLテンプレート・スタイル・ロジックをひとまとめにした コンポーネント という単位でUI部品を作っていきます。作ったコンポーネントは、モジュールに登録することでそのモジュール内で利用可能になります。

雛形アプリでは、AppModuleAppComponent が読み込まれており、それが index.html に挿入されるようになっていました。この、index.html に挿入されるコンポーネントはルートコンポーネントと呼ばれます。

雛形アプリはルートモジュールとルートコンポーネントだけが存在している状態ですが、実際のアプリ開発では、自分でコンポーネントを追加したり、必要に応じてモジュールを分割したりしながらアプリを作り込んでいきます :muscle:

図にすると以下のようなイメージです。

次回予告

というわけで、今回は ng new コマンドで作成した雛形アプリのソースコードを覗いて、その構造を確認してきました。Angularアプリがモジュールとコンポーネントという単位で動いているイメージをざっくりとご理解いただけたかと思います。

次回は新しくコンポーネントを作ってアプリに組み込んでみます。

お楽しみに! :raised_hands:


このエントリーをはてなブックマークに追加

もくじ

はじめに

この連載では、フロントエンドフレームワーク「Angular」をこれから学んでみたい方向けの入門コンテンツをお届けしたいと思います。

Angularには 公式のチュートリアル が用意されていますが、内容がやや盛りだくさんで、まったくの初心者には少しハードルが高いという声も耳にします。

そこで、公式のチュートリアルを始める前に、もっと気軽に トータル1時間でさらっと基本を学んでいただける ような内容にできればと考えています。

実際に簡単なToDoアプリを作りながら、Angularの基本機能を学んでいただく流れになります。ぜひ最後までお付き合いください。

今回のゴール

Angularでは、「Angular CLI」というCLIツールが用意されています。

通常、Angularでアプリを開発する場合、Angular CLIを使ってアプリケーションの雛形を生成するところから第一歩が始まります。

連載第一回である今回は、ひとまず難しいことは考えずに、この一歩目を体験してみることにしましょう。

Angular CLIをインストール

Angular CLIは、npm 経由で提供されています。

以下のように @angular/cli パッケージをグローバルインストールすることで、Angular CLIが提供するコマンド群を使えるようになります。

npm install -g @angular/cli

インストールができたら、以下のように打ち込んでみましょう。

ng version

以下のようなアスキーアートとともに、インストールされたAngular CLIのバージョンが表示されたと思います。

     _                      _                 ____ _     ___
    / \   _ __   __ _ _   _| | __ _ _ __     / ___| |   |_ _|
   / △ \ | '_ \ / _` | | | | |/ _` | '__|   | |   | |    | |
  / ___ \| | | | (_| | |_| | | (_| | |      | |___| |___ | |
 /_/   \_\_| |_|\__, |\__,_|_|\__,_|_|       \____|_____|___|
                |___/


Angular CLI: 8.3.7
  :
  :

@angular/cli パッケージをグローバルインストールしたことで、ng というコマンドが使えるようになったということです。

表示されているバージョン番号(8.3.7)は本稿執筆時点の最新版です。

このバージョンのAngular CLIは、nodeのバージョンが 10.9.0以上 かつ 13.0.0未満 であることが 前提となっている ため、もしインストールされているnodeのバージョンが古すぎるような場合は、あらかじめnodeのバージョンをアップデートしておきましょう :+1:

この ng コマンドにはたくさんのサブコマンドが用意されており、Angularを使ったアプリ開発を様々な場面でサポートしてくれます。

ng help (あるいは単に ng )を実行することで、利用可能なサブコマンドの一覧を確認できます。

アプリケーションの雛形を生成する

それでは早速、ng コマンドを使ってAngularアプリケーションの雛形を生成してみましょう。

適当な作業用ディレクトリに移動して、以下のコマンドを実行してみてください。

$ ng new angular-todo

実行すると、いくつか質問が表示されます。ここでは、以下のように回答してください。

  • ? Would you like to add Angular routing? No
  • ? Which stylesheet format would you like to use? SCSS

質問に答えると、あとはしばらく待って、

Successfully initialized git.

といった成功を表すメッセージが出力されれば完了です。

ng new コマンドの引数で指定した angular-todo という名前のディレクトリが作られているので、

$ cd angular-todo

してください。

生成された雛形アプリを実行してみる

これで雛形の生成は完了です。実際に動かしてみましょう。

ここでも ng コマンドを使います。以下のコマンドを実行すると、ローカルサーバーが立ち上がり、自動的にブラウザが開きます。

$ ng serve --open

おめでとうございます! :tada:

無事、AngularでHello Worldすることができました!(Hello World とはどこにも書いてませんが :sweat_smile:

ものすごく簡単でしたね!

次回予告

というわけで、今回はAngular CLIをインストールして、ng new コマンドを使ってアプリケーションの雛形を生成しました。

次回 は実際にアプリのソースコードを触ってみて、どういった仕組みでページが作られているのかを学んでいきます。

お楽しみに! :raised_hands: