Edited at

AngularJS 2.0 Step By Step Guide

More than 3 years have passed since last update.

この内容は、AngularJS 2.0のStep By Step Guideを翻訳したものです。

注: 「1.Getting Started」は本家のWebサイトから既に削除されています。2,3は、DEVELOPER GUIDEとして2015/10/16現在も存在しています。


1. 始めよう

JavaScriptでゼロからシンプルなAngular2 アプリケーションを始めましょう。

4つのステップで行っていきます。


  1. 新しいプロジェクトフォルダとindex.htmlの作成

  2. app.jsの中でアプリケーションのルートコンポーネントを書く

  3. アプリを起動する

  4. 動かす


新しいプロジェクトフォルダとindex.htmlの作成

アプリケーションプロジェクトを格納するための新しいフォルダを作成します。たぶん次のようにするでしょう:

mkdir firstNgApp && cd firstNgApp

その後、プロジェクトフォルダにindex.htmlファイルを追加し、以下のHTMLを打ち込んでください。

<!DOCTYPE html>

<html>
<head>
<script src="https://code.angularjs.org/2.0.0-alpha.34/angular2.sfx.dev.js"></script>
<script src="app.js"></script>
</head>
<body>
<my-app></my-app>
</body>
</html>

このアプリケーションは、<head>要素内で2つのスクリプトを読み込みます:


  • angular.js, Angular2 ライブラリ

  • app.js, 私たちが書くことになるアプリケーションのJavaScriptコード

<body>内には、<my-app>と呼ばれる要素があります。これはアプリケーションのルートのプレースホルダです。Angularはこのアプリケーションの内容をここに表示するでしょう。


アプリケーションのコンポーネントを書く

以下の内容を持つapp.jsファイルを作成します:

var AppComponent = ng

.Component({
selector: 'my-app'
})
.View({
template: '<h1>My First Angular 2 App</h1>'
})
.Class({
constructor: function () { }
});

一歩下がって斜め読みしてみると、ngと呼ばれるグローバルなAngular名前空間オブジェクトに由来する3つのメソッドを連鎖することによって、appComponentと命名された視覚的なコンポーネントを作成しているのがわかります。

var appComponent = ng

.Component({...})
.View({...})
.Class({...})

Componentメソッドは、これが"my-app"と命名された要素を制御するコンポーネントであることをAngularに伝えます。

.Component({

selector: 'my-app'
})

私たちが上記のindex.htmlにそのような要素を追加したのをあなたは覚えているかもしれません。

Viewメソッドは、コンポーネントのビュー(見た目)を定義するHTMLテンプレートを指定します。

.View({

template: '<h1>My First Angular 2 App</h1>'
})

この例では、HTMLテンプレートをインラインで書いています。後で、私たちはViewテンプレートファイルにHTMLを移動し、templateUrlにそのテンプレートのファイル名をアサインするでしょう。ほとんどの些細なテンプレートを除いて、そのような練習を私たちは好むでしょう。

Classメソッドは、コンポーネント自身を実装する場所であり、ビューとUIの一部として適切な全ての振る舞いをバインドする属性やメソッドを与えます。

.Class({

constructor: function () { }
});

このコンポーネントは最小の実装を持ちます: 何もすることがないので、何もしないno-opコンストラクタです。今後の例で、より興味深いコンポーネントのクラスを見ていきます。


動かす

私たちのアプリケーションの静的なファイル(index.htmlとapp.js)を提供するためのファイルサーバが必要です。

もしあなたのマシンにPythonがある場合は、あなたは幸運です: Pythonは基本的な静的ファイルサーバを提供しています。ターミナルウィンドウを開いて、以下を打ち込んでください:

python -m SimpleHTTPServer 8000

その後、http://localhost:8000 をブラウザで開くと、シンプルなテキストメッセージが表示されるでしょう:

もしPythonを持っていない場合は、サーバをインストールする必要があります。http-server, superstatic, またはlive-serverといった多くのnodeベースの静的サーバの一つをあなたは気に入るかもしれません。

この例では、私たちはlive-serverを使います。なぜなら、live-serverはデフォルトでライブリロードを実行しますし、変更した際にブラウザの更新を見るのは楽しいからです。

ターミナル(Windows/Linuxではコマンドライン)を開いて、以下を入力してください:

npm install -g live-server

もしまだnodeやnpmを持っていない場合は、最初にそれらをインストールしてください。それらはフロントエンド開発ツールとして欠かせないものです。

インストールが完了した後に、ポート8000番でサーバを開始してください。

live-server --port=8000

live-serverはブラウザを読み込み、そしてアプリケーションが変更された際にはページをリフレッシュします。


TypeScript型定義ファイルの追加(任意)

(TypeScriptの話なので割愛)


全てがツリー

私たちは、Angularアプリをコンポーネントのツリーと考えることができます。

私たちが語ってきたAppComponentは、アプリケーションが生きている間は、トップレベルコンテナ(ツリーのルート)として動作します。 AppComponentという名前について特別なことはなく、私たちが理解できるものなら何でも利用可能です。

アプリケーションがビューを描画することになるindex.htmlファイル内の要素に対して、ルートコンポーネントをピン留めしました。その要素はと呼びましたが、この名前に特別な意味はありません。

ルートコンポーネントは、アプリケーションのための初期テンプレートを読み込みます。そのテンプレートは、情報を表示し、ユーザジェスチャを受け取るためのメニューバー、ビュー、フォームなどといった他のコンポーネントを読み込むことができるでしょう。

そして、これらのコンポーネントは、ブラウザのページがネストされた機能の深いツリーになるまで、さらに多くのコンポーネントを読み込むでしょう。

以下のページでは、私たちはこれらのシナリオの例を見ていくことになります。


2. 情報の表示

情報の表示は、全ての良いアプリケーションのためのジョブ番号1です。Angularにおいて、あなたはHTMLテンプレート内で情報を要素にバインドし、情報が変更された際にAngularは自動的にUIを更新します。


表示コントローラプロパティ

では、プロパティやプロパティのリストをどのように表示するかを見ていきましょう。その後、状況に基づいた内容の条件付きで表示します。最終的にUIは以下のようになるでしょう:


エントリポイントの作成

あなたのお気に入りのエディタを開いて、以下の内容を持つshow-properties.htmlファイルを作成してください:

<display></display>

この<display>コンポーネントは、あなたがアプリケーションを挿入する場所として動作します。この例の残りはこのような(先ほど説明したような)構造を仮定し、異なる部分のみにフォーカスします。


インターポレーション(補間、挿入句)を使ったプロパティの表示

テンプレート内にテキストをバインドするための単純な方法は、内部にプロパティ名を置いたインターポレーションを使うことです。

これを機能させるために、もう一つshow-properties.jsファイルを作成し、以下を追加してください:

// ES5

function DisplayComponent() {
this.myName = "Alice";
}
DisplayComponent.annotations = [
new angular.ComponentAnnotation({
selector: "display"
}),
new angular.ViewAnnotation({
template:
'<p>My name: {{ myName }}</p>'
})
];

あなたはこのアプリのために、ビューとコントローラを包含するコンポーネントをちょうど定義しました。ビューはテンプレートを定義します:

<p>My name: {{ myName }}</p>

Angularは自動的に、myNameの値を引いてそれをブラウザに挿入します。そして、あなたが何もしなくても、その変更をいつでも更新します。

ここで注意することの一つとして、あなたはDisplayComponentクラスを記述しましたが、どこでもそれに対してnewを呼んでいません。あなたのクラスがDOM内の'display'という名前の要素に関連付けられることによって、Angularは自動的にDisplayComponentのnewを呼び出してテンプレートの一部にそのプロパティをバインドすることを知っています。

あなたがテンプレートを構築する際に、このようなデータバインディングはあなたのコントローラクラスが持つプロパティと同じスコープにアクセスします。ここでのあなたのクラスは、たった一つのプロパティ、myNameを持つDisplayComponentです。

NOTE

templateを使った場合はインラインビューを指定することになりますが、大きなテンプレートのためには、代わりにあなたはそれらを分離されたファイルに移動してtemplateUrlによってそれらを読み込みたくなるでしょう。


配列プロパティの作成とビューでのNgForの利用

単一のプロパティから発展させて、リストとして表示する配列を作ります。

//ES5

function DisplayComponent() {
this.myName = "Alice";
this.names = ["Aarav", "Martín", "Shannon", "Ariana", "Kai"];
}

配列の各項目についてDOM要素のコピーを作成するためのNgForディレクティブを使って、あなたはテンプレート内でこの配列を利用することが可能です。

//ES5

template:
'<p>My name: {{ myName }}</p>' +
'<p>Friends:</p>' +
'<ul>' +
'<li *ng-for="#name of names">' +
'{{ name }}' +
'</li>' +
'</ul>',

これを機能させるために、Angularがテンプレートによって使われるNgForディレクティブのインクルードを知るために、あなたはそれを追加する必要があります:

//ES5

DisplayComponent.annotations = [
...
new angular.ViewAnnotation({
...
directives: [angular.NgFor]
})
];

リロードすると、あなたの友だちの一覧を得られるでしょう!

Angularは、あなたが行った変更をDOM内の一覧に反映するでしょう。新しい項目を追加すると、それはあなたの一覧の中に現れます。項目を消せば、Angularはその<li>を削除します。項目の順番を変えれば、AngularはDOMの一覧の順番を矛盾なく並べ替えます。

再び、その仕事を行う数行を見てみましょう:

//HTML

<li *ng-for="#name of names">
{{ name }}
</li>

これを読み解くための方法は以下です:


  • ng-for : 配列のようなイテレータ内の各項目のDOM要素を作成します。

  • #name : 'name'としてイテレータの個々の値を参照します。

  • of names : 現在のコントローラ内で'names'という名前の利用可能なイテレータとして利用します。

この書式を使うことで、あなたは任意のイテレート可能なオブジェクトから一覧のUIを作り出すことができます。


配列プロパティのためのクラスの作成とコンポーネントへのインジェクト

さらに多くを得る前に、コントローラ内に直接モデル(ここでは配列)を配置することは推奨されることではないということを言及しなければなりません。私たちは、他のクラスがモデルの権限を提供し、コントローラ内にそれをインジェクトすることで、関心を分離すべきです。

友達のリストを持つモデルを提供するために、FriendsServiceクラスを作ります。

function FriendsService() {

this.names = ["Aarav", "Martín", "Shannon", "Ariana", "Kai"];
}

今、DisplayComponent内の現在の友達の一覧を、インジェクト可能なFriendsServiceを含むことで置き換え、コンストラクタ内でそのサービスをインクルードし、そして最後にDisplayComponent内のnamesのリストを、あなたが渡したサービスによって提供されるnameにセットします。

ES5 NOTE

ここでの依存性注入の書式は低レベルAPIを使っていて、えーっと、あまり良くはないです。Angular 1で機能していた方法にマッチするシンタックスシュガー構文を考えています。これがすぐに変更されることを期待していてください。

//ES5

function DisplayComponent(friends) {
this.myName = "Alice";
this.names = friends.names;
}
DisplayComponent.annotations = [
new angular.ComponentAnnotation({
selector: "display",
appInjector: [FriendsService]
}),
new angular.ViewAnnotation({
template: '{{ myName }} <ul> <li *for="#name of names">{{ name }}</li> </ul>',
directives: [angular.NgFor]
})
];
DisplayComponent.parameters = [[FriendsService]];
document.addEventListener("DOMContentLoaded", function() {
angular.bootstrap(DisplayComponent);
});


NgIfを使った条件指定の情報表示

最後に、次に進む前に、NgIfを使った条件指定によるUIの一部分の表示を取り扱いましょう。NgIfディレクティブは、あなたが提供した式に基づいて、DOMに要素を追加またはDOMから要素を削除します。

あなたのテンプレートの最後にパラグラフを追加することによって、どうアクションするか見てみましょう。

<p *ng-if="names.length > 3">You have many friends!</p>

あなたはまたNgIfディレクティブを追加する必要があります。これにより、Angularはそれを含むことを知ります。

//ES5

directives: [angular.NgFor, angular.NgIf]

現在リスト内に6個の項目があるので、あなたは多くの友達がいるとして、お祝いメッセージを見るでしょう。リストから3つの項目を削除してブラウザを再読込すると、もはやそのメッセージは表示されないことがわかります。

//ES5

function DisplayComponent(friends) {
this.myName = "Alice";
this.names = friends.names;
}
DisplayComponent.annotations = [
...
new angular.ViewAnnotation({
template: '
'<p>My name: {{ myName }}</p>' +
'<p>Friends:</p>' +
'<ul>' +
'<li *ng-for="#name of names">' +
'{{ name }}' +
'</li>' +
'</ul>' +
'<p *ng-if="names.length > 3">You have many friends!</p>'',
directives: [angular.NgFor, angular.NgIf]
})
];
function FriendsService () {
this.names = ["Aarav", "Martín", "Shannon"];
}


3. ユーザの入力

DOMイベントは、Angularにおいてユーザの入力をドライブします。あなたはclick、mouseover、keyupのようなネイティブイベントを使うことができます。AngularはDOM要素にイベントを登録するために特別な書式を使います。このセクションは、イベントシンタックスの利用の全ての入力および出力を取り扱います。


イベントシンタックスを使ったユーザ入力への反応

あなたは、イベントシンタックスを使うことで、アプリケーションがユーザの入力に反応させることができます。イベントシンタックスは、丸括弧によって囲まれたイベント名で開始します: (event)。その際、コントローラの関数はイベント名に関連されます: (event)="controllerFn()"。

入力のような特定の制御のために、あなたは以下のようにkeyupイベントをあなたのコントローラ上のメソッドを呼び出すようにすることができます:

<input (keyup)="myControllerMethod()">


ローカル変数

前の例では、#var書式を使ってローカル変数としてテンプレートの他の部分に要素を参照可能にすることができます。これとイベントを使うことで、私たちは”ユーザがタイプした際にテキストを更新する”という古い例を行うことができます:

<input #myname (keyup)>

<p>{{myname.value}}</p>

#mynameは、下の<p>要素で参照されるローカル変数をテンプレート内に作成します。(keyup)は、keyupイベントが発生した際に更新を動作させることをAngularに伝えます。そして、{{myname.value}}は<p>要素のテキストノードを入力値の属性にバインドします。

もう少し複雑な何かをしましょう。ここでは、以下のように、ユーザが項目を入力してそれらを追加した場合を見ていきます:


配列プロパティの作成

所定の初期ブートストラップを使って、リストの相互作用を管理することになるコントローラクラスを作成します。コントローラの内部では、項目の初期リストを持つ配列を追加します。その後、呼ばれた際に配列に新しい項目をプッシュするメソッドを追加します。

//ES5

function TodoList() {
this.todos = ["Eat Breakfast", "Walk Dog", "Breathe"];
this.addTodo = function(todo) {
this.todos.push(todo);
};
}

プロダクションベストプラクティス

前の例の際に、プロダクションアプリケーションにおいては、あなたのモデルを別のクラスに分離して、TodoListの中にそれをインジェクトするでしょう。ここでは簡潔さのために省略しました。


TODOリストの表示

*ng-forイテレータを使って、TODOの配列内の各項目の<li>を作成し、値にそのテキストをセットします。

<ul>

<li *ng-for="#todo of todos">
{{ todo }}
</li>
</ul>


ボタンクリックによるリストへのTODOの追加

今、ユーザがリストに項目するためのテキスト入力とボタンを追加します。上記で見た通り、#varnameを使ってテンプレート内にローカル変数参照を作成可能です。ここではそれを#todotextと呼びます。

<input #todotext>

最終的に、あなたのコントローラのaddTodo()メソッドにクリックイベントの対象をバインドすることを指定し、値をそれに渡します。todotextと名付けた参照を作成してあるので、あなたはtodotext.valueとして値を取得可能です。

<button (click)="addTodo(todotext.value)">Add Todo</button>

そしてその後、TodoListにdoneTyping()メソッドを作成し、todotextの追加を処理します。

doneTyping($event) {

if($event.which === 13) {
this.addTodo($event.target.value);
$event.target.value = null;
}
}


最終的なコード

//ES5

function TodoList() {
this.todos = ["Eat Breakfast", "Walk Dog", "Breathe"];
this.addTodo = function(todo) {
this.todos.push(todo);
};
this.doneTyping = function($event) {
if($event.which === 13) {
this.addTodo($event.target.value);
$event.target.value = null;
}
}
}
TodoList.annotations = [
new angular.ComponentAnnotation({
selector: "todo-list"
}),
new angular.ViewAnnotation({
template:
'<ul>' +
'<li *ng-for="#todo of todos">' +
'{{ todo }}' +
'</li>' +
'</ul>' +
'<input #textbox (keyup)="doneTyping($event)">' +
'<button (click)="addTodo(textbox.value)">Add Todo</button>',
directives: [angular.NgFor]
})
];
document.addEventListener("DOMContentLoaded", function() {
angular.bootstrap(TodoList);
});