angular

angular.io Guide: User Input

More than 1 year has passed since last update.

これは、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 | |

key up 1

代わりに、event.keyevent.target.valueに代入することで、個々のキー自体を累積することができます。この場合、同じユーザー入力が生成されます。

a | b | c | backspace | backspace | backspace |

$eventの型

上記の例は $eventany型としてキャストします。これはコストをかけてコードを簡素化していますね。イベントオブジェクトのプロパティを明らかにし、愚かなミスを防ぐことができる型情報がありません。

次の例では、メソッドを型で書き換えます。

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> タグ間に補間を付けて表示します。

テンプレートは完全に自己完結型です。コンポーネントにバインドされず、コンポーネントは何もしません。

入力ボックスに何かを入力し、各キーストロークでディスプレイの更新を見てください。

loop back

イベントにバインドしない限り、これはまったく動作しません。

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; }
}

下記のように動作します。

key up 3

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

以下は「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 を使用して双方向バインディングを作成する方法について説明します。