これは、Angular の公式ドキュメントの User Input の章 を意訳したものです。
駆け足で翻訳したので至らない点もありますが、あしからずご承知おきください。
バージョン 4.3.1 のドキュメントをベースにしています。
User Input
リンクをクリックする、ボタンを押す、テキストを入力するなどのユーザー操作は、DOMイベントを発生させます。このページでは、Angularイベントバインディング構文を使用して、これらのイベントをコンポーネントイベントハンドラにバインドする方法について説明します。
ユーザー入力イベントへのバインド
Angular イベントバインディングを使用して、DOM イベントに反応することができます。多くのDOMイベントはユーザー入力によってトリガーされます。これらのイベントにバインドすることで、ユーザーからの入力を得ることができます。
DOMイベントにバインドするには、DOMイベント名をカッコで囲み、引用されたテンプレートステートメントを割り当てます。
次の例は、クリックハンドラを実装するイベントバインディングを示しています。
src/app/click-me.component.ts
<button (click)="onClickMe()">Click me!</button>
等号 =
の左側の (click)
は、バインディングのターゲットとしてボタンのクリックイベントを識別します。 等号の右側の引用符で囲まれたテキストは、コンポーネントの onClickMe
メソッドを呼び出すことによってclickイベントに応答するテンプレートステートメントです。
バインディングを記述するときは、テンプレート文の実行コンテキストに注意してください。テンプレートステートメントの識別子は、特定のコンテキストオブジェクトに属します。通常、テンプレートを制御するAngularコンポーネントです。 上の例は、HTMLの1行を示していますが、HTMLはより大きなコンポーネントに属しています。
src/app/click-me.component.ts
@Component({
selector: 'click-me',
template: `
<button (click)="onClickMe()">Click me!</button>
{{clickMessage}}`
})
export class ClickMeComponent {
clickMessage = '';
onClickMe() {
this.clickMessage = 'You are my hero!';
}
}
ユーザーがボタンをクリックすると、AngularはClickMeComponentからonClickMeメソッドを呼び出します。
$event
オブジェクトからユーザー入力を取得する
DOMイベントは、コンポーネントにとって有益な情報のペイロードを保持します。 このセクションでは、各キーストローク後に入力ボックスのkeyup イベントにバインドしてユーザーの入力を取得する方法を示します。
次のコードは、keyupイベントをリッスンし、イベントペイロード($event
)全体をコンポーネントイベントハンドラに渡します。
src/app/keyup.components.ts (template v.1)
template: `
<input (keyup)="onKey($event)">
<p>{{values}}</p>
`
ユーザーがキーを押して離すと、keyupイベントが発生し、Angularは、このコードがコンポーネントの onKey()
メソッドに渡す $event
変数に対応するDOMイベントオブジェクトを受け取れます。
src/app/keyup.components.ts (class v.1)
export class KeyUpComponent_v1 {
values = '';
onKey(event: any) { // without type info
this.values += event.target.value + ' | ';
}
}
$event
オブジェクトのプロパティは、DOMイベントのタイプによって異なります。 例えば、マウスイベントは入力ボックス編集イベントとは異なる情報を含みます。
すべての標準DOMイベントオブジェクトには、イベントを発生させた要素への参照であるtargetプロパティがあります。この場合、target
は <input> 要素
を参照し、event.target.value
はその要素の現在の内容を返します。
各呼び出しの後、onKey()
メソッドは、入力ボックス値の内容をコンポーネントのvalues
プロパティのリストに追加し、その後に区切り文字(|)
を続けます。 interpolation {{ ... }}
は、values
プロパティからの累積input boxの変更を表示します。
ユーザが文字「abc」を入力し、それからバックスペースを1つずつ削除するとします。 UIに表示される内容は次のとおりです。
a | ab | abc | ab | a | |
代わりに、
event.key
をevent.target.value
に代入することで、個々のキー自体を累積することができます。この場合、同じユーザー入力が生成されます。a | b | c | backspace | backspace | backspace |
$event
の型
上記の例は $event
をany
型としてキャストします。これはコストをかけてコードを簡素化していますね。イベントオブジェクトのプロパティを明らかにし、愚かなミスを防ぐことができる型情報がありません。
次の例では、メソッドを型で書き換えます。
src/app/keyup.components.ts (class v.1 - 型付き )
export class KeyUpComponent_v1 {
values = '';
onKey(event: KeyboardEvent) { // with type info
this.values += (<HTMLInputElement>event.target).value + ' | ';
}
}
$event
は、特定の KeyboardEvent
になりました。すべての要素が value
プロパティを持っているわけではないので、入力要素にターゲットをキャストします。 OnKey
メソッドは、テンプレートから期待されるものと、イベントをどのように解釈するかをより明確に表現します。
$event
を渡すことは疑わしい練習です
イベントオブジェクトを型定義すると、DOMイベント全体をメソッドに渡すという大きな疑問が出てくるのではないでしょうか。コンポーネントは、テンプレートの詳細を認識しすぎています。それは、HTML実装に関してそれ以上のことを知らずに情報を抽出することはできません。これは、テンプレート(ユーザーが見るもの)とコンポーネント(アプリケーションがユーザーデータをどのように処理するか)の間における、関心の分離を壊しています。
次のセクションでは、テンプレート参照変数を使用してこの問題に対処する方法を示します。
テンプレート参照変数からユーザー入力を取得する
ユーザーデータを取得するもう1つの方法があります:Angular テンプレート参照変数 を使用する方法です。
これらの変数は、テンプレート内から要素への直接アクセスを提供します。テンプレート参照変数を宣言するには、識別子の前にハッシュ(またはポンド)文字 (#)
を付けます。
次の例では、テンプレート参照変数を使用して、単純なテンプレートにキーストロークループバックを実装しています。
src/app/loop-back.component.ts
@Component({
selector: 'loop-back',
template: `
<input #box (keyup)="0">
<p>{{box.value}}</p>
`
})
export class LoopbackComponent { }
<input>
要素で宣言されたboxという名前のテンプレート参照変数は、<input>
要素自体を参照します。このコードでは、ボックス変数を使用して入力要素の値を取得し、<p>
タグ間に補間を付けて表示します。
テンプレートは完全に自己完結型です。コンポーネントにバインドされず、コンポーネントは何もしません。
入力ボックスに何かを入力し、各キーストロークでディスプレイの更新を見てください。
イベントにバインドしない限り、これはまったく動作しません。
Angularは、アプリケーションがキーストロークなどの非同期イベントに応答して何かを行う場合にのみ、バインディング(つまり画面)を更新します。
この例のコードは、可能な限り最短のテンプレートステートメントである数字0にkeyup
イベントをバインドします。
ステートメントは何も役に立ちませんが、Angularの要件を満たしているので、Angularが画面を更新します。
$event
オブジェクトを調べるよりも、テンプレート参照変数を使って入力ボックスに移動する方が簡単です。テンプレート参照変数を使用してユーザーの入力を取得する、以前のkeyup
の例を書き直しました。
src/app/keyup.components.ts (v2)
@Component({
selector: 'key-up2',
template: `
<input #box (keyup)="onKey(box.value)">
<p>{{values}}</p>
`
})
export class KeyUpComponent_v2 {
values = '';
onKey(value: string) {
this.values += value + ' | ';
}
}
このアプローチの優れた点は、コンポーネントがビューからクリーンなデータ値を取得することです。$event
とその構造についての知識は必要ありません。
キーイベントフィルタリング (key.enter)
(keyup)
イベントハンドラはすべてのキーストロークをListenしています。ユーザーが入力を完了したことを示すため、Enterキーだけが重要な場合があります。イベントのノイズを減らす1つの方法は、すべての $ event.keyCode
をチェックし、キーコードがEnterの場合にのみアクションを取ることです。
より簡単な方法があります:Angularのキーアップにバインドします。疑似イベントに入ります。Angularは、ユーザーがEnterキーを押したときにのみイベントハンドラを呼び出します。
src/app/keyup.components.ts (v3)
@Component({
selector: 'key-up3',
template: `
<input #box (keyup.enter)="onEnter(box.value)">
<p>{{value}}</p>
`
})
export class KeyUpComponent_v3 {
value = '';
onEnter(value: string) { this.value = value; }
}
下記のように動作します。
On Blur
前の例では、入力ボックスの現在の状態は、ユーザーが最初にEnterキーを押さずにページ上の他の場所にマウスを移動してクリックすると失われてしまいます。コンポーネントの value
プロパティは、ユーザーが Enter キーを押した場合にのみ更新されます。
この問題を解決するには、Enter キーと blur イベントの両方をListenします。
src/app/keyup.components.ts (v4)
@Component({
selector: 'key-up4',
template: `
<input #box
(keyup.enter)="update(box.value)"
(blur)="update(box.value)">
<p>{{value}}</p>
`
})
export class KeyUpComponent_v4 {
value = '';
update(value: string) { this.value = value; }
}
Put it all together
前のページでは、データを表示する方法が示されていました。このページでは、イベントバインディング手法について説明しました。
今、すべてのヒーローのリストを表示し、新しいヒーローをリストに追加できるマイクロアプリにまとめてください。ユーザーは、入力ボックスにヒーローの名前を入力して [追加] をクリックすると、ヒーローを追加できます。
以下は「Little Tour of Heroes」のコンポーネントです。
src/app/little-tour.component.ts
@Component({
selector: 'little-tour',
template: `
<input #newHero
(keyup.enter)="addHero(newHero.value)"
(blur)="addHero(newHero.value); newHero.value='' ">
<button (click)="addHero(newHero.value)">Add</button>
<ul><li *ngFor="let hero of heroes">{{hero}}</li></ul>
`
})
export class LittleTourComponent {
heroes = ['Windstorm', 'Bombasto', 'Magneta', 'Tornado'];
addHero(newHero: string) {
if (newHero) {
this.heroes.push(newHero);
}
}
}
監視
-
テンプレート変数を使用して要素を参照する -
newHero
テンプレート変数は<input>
要素を参照します。<input>
要素の任意の兄弟または子からnewHero
を参照できます。 -
要素ではなくパス値 - newHeroをコンポーネントの
addHero
メソッドに渡す代わりに、入力ボックスの値を取得してaddHero
に渡します。 -
テンプレートステートメントをシンプルにする -
(blur)
イベントは2つのJavaScriptステートメントにバインドされています。 最初の文はaddHero
を呼び出します。 2番目のステートメントnewHero.value = ''
は、新しいヒーローがリストに追加された後に入力ボックスをクリアします。
ソースコード
以下に、このページで説明するすべてのコードを示します。
この章のまとめ
ユーザー入力とジェスチャーに応答するための基本をマスターしました。
これらのテクニックは小規模のデモンストレーションに役立ちますが、大量のユーザー入力を処理するときには、粗が出てきます。
双方向データバインディングは、データ入力フィールドとモデルプロパティの間で値を移動するためのよりエレガントでコンパクトな方法です。次のページ Forms
では、NgModel
を使用して双方向バインディングを作成する方法について説明します。