これは、Angular の公式ドキュメントの Forms の章 を意訳したものです。
駆け足で翻訳したので至らない点もありますが、あしからずご承知おきください。
バージョン 4.3.1 のドキュメントをベースにしています。
Forms (Template-driven Forms)
フォームはビジネスアプリケーションの大黒柱です。フォームを使用してログインし、ヘルプリクエストを送信したり、注文したり、フライトを予約したり、ミーティングをスケジュールしたり・・・その他の無数のデータ入力タスクを実行します。
フォームを開発するには、ワークフローを通じて効率的かつ効果的にユーザーを誘導するデータ入力エクスペリエンスを作成することが重要です。
フォームを開発するには、設計スキル(このページでは説明の対象外です)と双方向データバインディング、変更の追跡、検証、エラー処理のフレームワークサポートが必要です。
このページでは、単純なフォームを最初から作成する方法を示します。途中で次のことを学びます:
- コンポーネントとテンプレートを使用してAngularフォームを作成します。
-
ngModel
を使用して、入力制御値を読み書きするための双方向データバインディングを作成します。 - 状態の変化とフォームコントロールの有効性を追跡します。
- コントロールの状態を追跡する特別なCSSクラスを使用して視覚的フィードバックを提供します。
- バリデーションエラーをユーザーに表示し、フォームコントロールを有効または無効にします。
- テンプレート参照変数を使用してHTML要素間で情報を共有します。
Plunkerでライブサンプルを見るか/こちらからサンプルをダウンロードを実行することができます。
Template-driven forms(テンプレート駆動フォーム)
このページに記載されているフォーム固有の指示とテクニックを使用して、Angular テンプレート構文でテンプレートを記述することにより、フォームを構築できます。
Reactive型(またはモデル駆動型)アプローチを使用してフォームを構築することもできますが、このページではテンプレート駆動フォームに焦点を当てています。
Angularテンプレートを使用してほぼすべてのフォームを作成できます - ログインフォーム、連絡フォーム、ほぼすべてのビジネスフォームを作成できます。
コントロールをクリエイティブにレイアウトし、データにバインドし、バリデーションルールを指定し、バリデーションエラーを表示し、特定のコントロールを条件付きで有効または無効にしたり、ビジュアルフィードバックをトリガしたりできます。
Angularは、あなた自身が苦労している繰り返しの多い定型的なタスクの多くを処理することで、プロセスを簡単にします。
次のようなテンプレート駆動型フォームを構築する方法を学びます:
「Hero Employment Agency」は、このフォームを使用してヒーローに関する個人情報を管理しています。すべてのヒーローは仕事が必要です。 適切なヒーローに正しい危機をアサインして一致させることが、会社のミッションです。
このフォームの3つのフィールドのうちの2つが必須です。 必須フィールドには、左側に緑色のバーが表示されます。
ヒーロー名を削除すると、フォームは注意を引くスタイルでバリデーションエラーを表示します。
Submitボタンは無効になっており、入力コントロールの左側の「必須」バーが緑色から赤色に変わります。
標準のCSSを使用して、「必須」バーの色と位置をカスタマイズできます。
このフォームは小さな手順で作成します:
-
Hero
モデルクラスを作成します。 - フォームを制御するコンポーネントを作成します。
- 最初のフォームレイアウトでテンプレートを作成します。
-
ngModel
双方向のデータバインディング構文を使用して各フォームコントロールにデータプロパティをバインドします。 - 各フォーム入力コントロールに
name
属性を追加します。 - 視覚的なフィードバックを提供するカスタムCSSを追加します。
- 検証エラーメッセージの表示と非表示を切り替えます。
-
ngSubmit
でフォームの送信を処理します。 - フォームが有効になるまで、フォームの[送信]ボタンを無効にします。
セットアップ
Setup の方法に従って、angle-forms という名前の新しいプロジェクトを作成します。
ヒーローモデルクラスを作成する
ユーザーがフォームデータを入力すると、その変更をキャプチャしてモデルのインスタンスを更新します。モデルがどのように見えるかを知るまで、フォームをレイアウトすることはできません。
モデルは、アプリケーションの重要性に関する事実を保持する「プロパティバッグ」と同じくらいシンプルにすることができます。3つの必須フィールド(id
, name
, power
)と1つのオプションフィールド(alterEgo
)を持ったHero
クラスについて説明しています。
appディレクトリに、指定されたコンテンツを含む次のファイルを作成します。
src/app/hero.ts
export class Hero {
constructor(
public id: number,
public name: string,
public power: string,
public alterEgo?: string
) { }
}
これは、要件がほとんどなく振る舞いのない貧弱なモデルです。デモ用には最適ですね。
TypeScriptコンパイラは、パブリックコンストラクタパラメータごとにパブリックフィールドを生成し、ヒーローを作成するときにそのフィールドにパラメータの値を自動的に割り当てます。
alterEgo
はオプションであるため、コンストラクタで省略することができます。alterEgo?
の疑問符(?)を気に留めておいてください。
あなたは次のように新しいヒーローを作ることができます:
src/app/hero-form.component.ts (SkyDog)
let myHero = new Hero(42, 'SkyDog',
'Fetch any object at any distance',
'Leslie Rollover');
console.log('My hero is called ' + myHero.name); // "My hero is called SkyDog"
フォームコンポーネントを作成する
Angularフォームには、HTMLベースのテンプレートと、データとユーザー対話をプログラムで処理するコンポーネントクラスの2つの部分があります。 主人公の編集者ができることを簡単に述べるので、クラスから始めましょう。
指定した内容で次のファイルを作成します。
src/app/hero-form.component.ts (v1)
import { Component } from '@angular/core';
import { Hero } from './hero';
@Component({
selector: 'hero-form',
templateUrl: './hero-form.component.html'
})
export class HeroFormComponent {
powers = ['Really Smart', 'Super Flexible',
'Super Hot', 'Weather Changer'];
model = new Hero(18, 'Dr IQ', this.powers[0], 'Chuck Overstreet');
submitted = false;
onSubmit() { this.submitted = true; }
// TODO: Remove this when we're done
get diagnostic() { return JSON.stringify(this.model); }
}
このコンポーネントには特別なものはありません。フォーム固有のコンポーネントはありません。これまでに書いたコンポーネントと区別するものはありません。
このコンポーネントを理解するには、前のページで説明したAngularの概念のみが必要です。
- コードはAngularコアライブラリと作成した
Hero
モデルをインポートします。 - "hero-form"という
@Component
セレクタの値は、このフォームを<hero-form>
タグを持つ親テンプレートにドロップできることを意味します。 -
templateUrl
プロパティは、テンプレートHTMLの別のファイルを指し示します。 - デモにふさわしい
model
とpowers
のためのダミーデータを定義しました。
実際のデータを取得して保存するためのデータサービスを挿入したり、親コンポーネントへのバインディングのためにこれらのプロパティを入力と出力として公開したりすることができます(テンプレート構文ページ内の入出力プロパティを参照)。これは現在懸念されておらず、これらの将来の変更はフォームに影響しません。
モデルのJSON表現を返すための診断プロパティを追加しました。開発中に何をしているのかを理解するのに役立ちます。あなたはそれを後で破棄するためのクリーンアップノートを残しています。
なぜフォームを別のテンプレートファイルにしているのですか?
他の場所でよく使うように、コンポーネントファイルにテンプレートをインラインで書くのはなぜですか?
すべての機会に「正しい」答えはありません。インラインテンプレートは、短い場合に便利です。ほとんどのフォームテンプレートは短くありません。 TypeScriptファイルとJavaScriptファイルは、一般的にHTMLの大部分を書く(または読み込む)のに最適な場所ではなく、HTMLとコードが混在したファイルを扱えるエディタはほとんどありません。
少数のフィールドを表示する場合でも、フォームテンプレートは大きくなる傾向があります。そのため、通常HTMLテンプレートを別のファイルに配置することをお勧めします。そのテンプレートファイルをすぐに書きます。まず、新しいHeroFormComponentを使用するようにapp.module.ts
とapp.component.ts
を修正します。
app.module.tsを修正する
app.module.ts
は、アプリケーションのルートモジュールを定義します。その中で、アプリケーションで使用する外部モジュールを特定し、このモジュールに属するコンポーネント(HeroFormComponent
など)を宣言します。
テンプレート駆動フォームは独自のモジュールにあるため、フォームを使用する前に、アプリケーションモジュールのインポート配列にFormsModule
を追加する必要があります。
「QuickStart」バージョンの内容を次のものに置き換えます。
src/app/app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
import { HeroFormComponent } from './hero-form.component';
@NgModule({
imports: [
BrowserModule,
FormsModule
],
declarations: [
AppComponent,
HeroFormComponent
],
bootstrap: [ AppComponent ]
})
export class AppModule { }
3つの変更点があります。
FormsModule
と新しいHeroFormComponent
をインポートします。FormsModule
を@NgModule
デコレータで定義されたインポートのリストに追加します。これにより、アプリケーションは、ngModel
を含むすべてのテンプレート駆動フォーム機能にアクセスできます。HeroFormComponent
を@NgModule
デコレータで定義された宣言のリストに追加します。 これにより、このモジュール全体でHeroFormComponent
コンポーネントが表示されます。
コンポーネント、ディレクティブ、またはパイプがimports配列のモジュールに属している場合は、宣言配列でそれを再宣言しないでください。
もしあなたがそれを書き、それがこのモジュールに属していれば、それを宣言配列で宣言してください。
app.component.tsを修正する
AppComponent
はアプリケーションのルートコンポーネントです。 新しいHeroFormComponent
をホストします。
「QuickStart」バージョンの内容を次のものに置き換えます。
src/app/app.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
template: '<hero-form></hero-form>'
})
export class AppComponent { }
変更は2つだけです。 template
は、単にコンポーネントのselector
プロパティで識別される新しい要素タグです。これは、アプリケーションコンポーネントがロードされたときにヒーローフォームを表示します。またクラス本体からname
フィールドを削除しました。
HTMLフォームテンプレートの初期セットアップ
次の内容のテンプレートファイルを作成します。
src/app/hero-form.component.html
<div class="container">
<h1>Hero Form</h1>
<form>
<div class="form-group">
<label for="name">Name</label>
<input type="text" class="form-control" id="name" required>
</div>
<div class="form-group">
<label for="alterEgo">Alter Ego</label>
<input type="text" class="form-control" id="alterEgo">
</div>
<button type="submit" class="btn btn-success">Submit</button>
</form>
</div>
言語は単にHTML5です。 ヒーローフィールドの2つを表示しています。名前とalterEgoを入力ボックスに入力するために開きます。
Name <input>
コントロールにはHTML5の required
属性を記述します。alterEgo
はオプションであるため、Alter Ego <input>
コントロールにはrequired
属性は適用しません。
下部に[送信]ボタンを追加して、スタイリングのためにいくつかのクラスを追加しました。
Angular固有の機能はまだ使用していません。バインディングや追加の指示はなく、レイアウトだけです。
テンプレート駆動フォームでは、FormsModuleをインポートした場合、FormsModuleを使用するために
<form>
タグに何もする必要はありません。それがどのように機能するかを確認してください。
container
、form-group
、form-control
、および btn
のクラスは、Twitter Bootstrapに由来します。 これらのクラスは純粋なお化粧です。 ブートストラップはフォームに小さなスタイルを与えます。
Angular フォームはスタイルライブラリを必要としません
Angularは、コンテナ、フォームグループ、フォームコントロール、btnクラス、または外部ライブラリのスタイルを使用しません。 AngularアプリはCSSライブラリを使用することも、まったく使用しないこともできます。
スタイルシートを追加するには、index.htmlを開き、次のリンクを<head>
に追加します。
src/index.html (bootstrap)
<link rel="stylesheet"
href="https://unpkg.com/bootstrap@3.3.7/dist/css/bootstrap.min.css">
*ngFor で power を加える
heroは、政府機関が承認した権限のリストから1つの超大国を選ぶ必要があります。 あなたはそのリストを内部的に(HeroFormComponent
の中で)管理しています。
フォームに select
を追加し、以前は「Displaying Data」ページで表示されていた手法であるngFor
を使用して、オプションをpowers
リストにバインドします。
Alter Egoグループのすぐ下に次のHTMLを追加します。
src/app/hero-form.component.html (powers)
<div class="form-group">
<label for="power">Hero Power</label>
<select class="form-control" id="power" required>
<option *ngFor="let pow of powers" [value]="pow">{{pow}}</option>
</select>
</div>
このコードは、powersリスト内の各項目に対して <option>
タグを繰り返します。pow
テンプレートの入力変数は、interpolation syntax を用いて名前を表示することで、繰り返す度にで異なる出力になっています。
ngModelによる双方向データバインディング
このまますぐにアプリケーションを実行すると、残念なことが起きます。
まだHero
がバインディングされていないので、ヒーローデータは表示されません。 以前のページからそれを行う方法を知っています。 データの表示はプロパティのバインディングを教えます。 ユーザー入力は、イベントバインディングを使用してDOMイベントをリスンする方法と、表示された値でコンポーネントプロパティを更新する方法を示します。
今度は、同時に表示、聞いて、抽出する必要があります。
すでに知っているテクニックを使用することもできますが、新しい[(ngModel)]
構文を使用すると、フォームをモデルに簡単にバインドすることができます。
Nameの<input>
タグを見つけて、次のように更新します。
src/app/hero-form.component.html (抜粋)
<input type="text" class="form-control" id="name"
required
[(ngModel)]="model.name" name="name">
TODO: remove this: {{model.name}}
input タグの後に確認用のinterpolationを追加したので、何をしているのかを見ることができます。動作確認ができたらこの記述を削除するようにTODOメモを残しています。
バインディング構文に注目してください:[(ngModel)]="..."
データを表示するにはさらに1つの追加が必要です。フォームのテンプレート変数を宣言します。次のように、
#heroForm="ngForm"
で更新します。
src/app/hero-form.component.html (excerpt)
<form #heroForm="ngForm">
変数heroForm
は、フォーム全体を管理するNgForm
ディレクティブへの参照になりました。
NgForm ディレクティブ
NgFormディレクティブとは何ですか? あなたはNgFormディレクティブを追加しませんでした。
Angularがそうしました。Angularは自動的にNgFormディレクティブを作成して
タグに添付します。NgFormディレクティブは、フォーム要素に追加機能を追加します。 ngModelディレクティブとname属性を使用して要素用に作成したコントロールを保持し、その有効性を含めてプロパティを監視します。
また、それ自身の有効なプロパティもあります。これは、含まれているすべてのコントロールが有効な場合にのみtrueです。
今すぐアプリケーションを実行して、名前の入力ボックスへ入力を開始し、文字の追加と削除を行うと、補間されたテキストが表示されて消えてしまいます。 ある時点では、次のようになります。
診断は、値が実際に入力ボックスからモデルに流れて戻ってくるという証拠です。
これは、双方向のデータバインディングです。詳細については、「テンプレート構文」ページの「NgModelによる双方向バインディング」を参照してください。
また、<input>
タグにname属性を追加し、それを "name" に設定することに注意してください。これはヒーローの名前に意味があります。 一意の値はすべて行いますが、わかりやすい名前を使用すると便利です。 [(ngModel])
をフォームと組み合わせて使用する場合、name
属性を定義する必要があります。
内部的には、AngularはFormControlインスタンスを作成し、
タグにAngularを付けたNgFormディレクティブを登録します。 各FormControlは、name属性に割り当てた名前で登録されます。 前のセクション、The NgFormディレクティブを読んでください。
同様の[(ngModel)]
バインディングと名前属性をAlter EgoとHero Powerに追加します。 入力ボックスのバインディングメッセージを破棄し、コンポーネントの診断プロパティに新しいバインディング(上部)を追加します。 その後、ヒーローモデル全体に対して双方向データバインディングが機能することを確認できます。
修正後、フォームのコアは次のようになります。
src/app/hero-form.component.html (抜粋)
{{diagnostic}}
<div class="form-group">
<label for="name">Name</label>
<input type="text" class="form-control" id="name"
required
[(ngModel)]="model.name" name="name">
</div>
<div class="form-group">
<label for="alterEgo">Alter Ego</label>
<input type="text" class="form-control" id="alterEgo"
[(ngModel)]="model.alterEgo" name="alterEgo">
</div>
<div class="form-group">
<label for="power">Hero Power</label>
<select class="form-control" id="power"
required
[(ngModel)]="model.power" name="power">
<option *ngFor="let pow of powers" [value]="pow">{{pow}}</option>
</select>
</div>
- 各input要素にはid属性があり、label要素のfor属性でそのラベルを入力コントロールと照合するために使用されます。
- 各入力要素には、フォームにコントロールを登録するためにAngularフォームで必要なnameプロパティがあります。
今すぐあなたのアプリケーションを実行し、すべてのヒーローモデルのプロパティを変更すると、フォームは次のように表示されることがあります:
フォームの上部付近の診断によって、すべての変更がモデルに反映されていることが確認されます。
{{diagnostic}}
のバインディングを削除します。
ngModelを使用して制御状態と有効性を追跡する
フォーム内でngModelを使用すると、単なる双方向データバインディング以上のことができます。 また、ユーザーがコントロールにタッチしたか、値が変更されたか、または値が無効になったかどうかが示されます。
NgModelディレクティブは状態を追跡するだけではありません。 状態を反映する特殊なAngular CSSクラスでコントロールを更新します。 これらのクラス名を利用して、コントロールの外観を変更することができます。
State Class if true Class if false
The control has been visited. ng-touched ng-untouched
The control's value has changed. ng-dirty ng-pristine
The control's value is valid. ng-valid ng-invalid
State | true時に付与されるclass | false時に付与されるclass |
---|---|---|
コントロールが操作された | ng-touched |
ng-untouched |
コントロールの値が変更された | ng-dirty |
ng-pristine |
コントロールの値がvalidである | ng-valid |
ng-invalid |
名前 <input>
タグに一時的にspyという名前のテンプレート参照変数を追加し、それを使用して入力のCSSクラスを表示します。
src/app/hero-form.component.html (抜粋)
<input type="text" class="form-control" id="name"
required
[(ngModel)]="model.name" name="name"
#spy>
<br>TODO: remove this: {{spy.className}}
今すぐアプリケーションを実行し、名前の入力ボックスを見てください。 次の手順を正確に実行してください。
- 見て、触れないでください。
- 名前ボックスの内側をクリックし、外側をクリックします。
- 名前の最後にスラッシュを追加します。
- 名前を消去します。
アクションと効果は次のとおりです。
次の遷移とクラス名が表示されます。
ng-valid
/ ng-invalid
ペアは、値が無効な場合に強いビジュアル信号を送信したいので、最も興味深いものです。 また、必須フィールドに印を付ける必要があります。 このような視覚的フィードバックを作成するには、ng-*
CSSクラスの定義を追加します。
#spy
テンプレート参照変数とTODOコメントを削除します。
視覚的なフィードバックのためにカスタムCSSを追加する
入力ボックスの左側にある色付きのバーで、必須フィールドと無効なデータを同時にマークすることができます。
この効果は、これらのクラス定義を新しいforms.cssファイルに追加することによって達成されます。このファイルは、プロジェクトにindex.htmlの兄弟として追加します。
src/forms.css
.ng-valid[required], .ng-valid.required {
border-left: 5px solid #42A948; /* green */
}
.ng-invalid:not(form) {
border-left: 5px solid #a94442; /* red */
}
このスタイルシートを含めるにはindex.htmlの<head>
をアップデートしてください:
<link rel="stylesheet" href="styles.css">
<link rel="stylesheet" href="forms.css">
バリデーションエラーメッセージの表示/非表示
フォームを改善することができます。 [名前]入力ボックスは必須で、これをオフにすると赤いバーが表示されます。 それは何かが間違っていると言いますが、ユーザーは何が間違っているのか、何をすべきかは分かりません。 コントロールの状態を利用して役立つメッセージを表示します。
ユーザーが名前を削除すると、フォームは次のようになります。
この効果を得るには、<input>
タグを次のように拡張します。
テンプレート参照変数。
近くの<div>
に "必須です"というメッセージが表示されます。このメッセージは、コントロールが無効な場合にのみ表示されます。
次に、名前入力ボックスに追加されたエラーメッセージの例を示します。
src/app/hero-form.component.html (抜粋)
<label for="name">Name</label>
<input type="text" class="form-control" id="name"
required
[(ngModel)]="model.name" name="name"
#name="ngModel">
<div [hidden]="name.valid || name.pristine"
class="alert alert-danger">
Name is required
</div>
入力ボックスにアクセスするにはテンプレート参照変数が必要ですテンプレート内からの角度コントロール。 ここではnameという名前の変数を作成し、それに "ngModel"という値を与えました。
なぜ "ngModel"ですか? ディレクティブのexportAsプロパティは、参照変数をディレクティブにリンクする方法をAngularに通知します。 ngModelディレクティブのexportAsプロパティが "ngModel"であるため、名前をngModelに設定します。
名前コントロールのプロパティをメッセージの<div>
要素のhidden
プロパティにバインドすることにより、名前エラーメッセージの表示を制御します。
src/app/hero-form.component.html (hidden-error-msg)
<div [hidden]="name.valid || name.pristine"
class="alert alert-danger">
この例では、コントロールが有効または元の状態のときにメッセージを非表示にします。 「原始」とは、ユーザーがこのフォームで表示されてから値を変更していないことを意味します。
このユーザーエクスペリエンスは開発者の選択です。いくつかの開発者はメッセージを常に表示することを望んでいます。初期状態を無視すると、値が有効な場合にのみメッセージを非表示にします。新しい(空白の)ヒーローまたは無効なヒーローでこのコンポーネントに着いたら、何かをする前にすぐにエラーメッセージが表示されます。
一部の開発者は、ユーザーが無効な変更を行った場合にのみ、メッセージを表示することを望みます。コントロールが「元気」である間にメッセージを非表示にすると、その目標が達成されます。フォームに新しいヒーローを追加すると、この選択の重要性がわかります。
ヒーローアルターエゴはオプションですので、あなたはそれを残すことができます。
ヒーローパワーの選択が必要です。必要に応じて、同じ種類のエラー処理を<select>
に追加できますが、選択ボックスではすでに有効な値に制限されているため、必須ではありません。
これで新しいヒーローをこのフォームに追加します。新しいヒーローボタンをフォームの下部に配置し、そのクリックイベントをnewHero
コンポーネントメソッドにバインドします。
src/app/hero-form.component.html (New Hero button)
<button type="button" class="btn btn-default" (click)="newHero()">New Hero</button>
src/app/hero-form.component.ts (New Hero method)
newHero() {
this.model = new Hero(42, '', '');
}
アプリケーションをもう一度実行し、New Heroボタンをクリックすると、フォームがクリアされます。 入力ボックスの左側に必要なバーは赤で、無効な名前と電源のプロパティを示します。 これは必須フィールドなので理解できます。 フォームが初期状態であるため、エラーメッセージは表示されません。 あなたはまだ何も変えていない。
名前を入力し、New Heroをもう一度クリックします。 アプリケーションには、名前が必要ですエラーメッセージが表示されます。 新しい(空の)ヒーローを作成すると、エラーメッセージは表示されません。 なぜあなたは今、1つを手に入れていますか?
ブラウザツールで要素を調べると、名前の入力ボックスが元の状態になっていないことがわかります。 フォームは、New Heroをクリックする前に名前を入力したことを記憶しています。 ヒーローオブジェクトを置き換えても、フォームコントロールの元の状態は復元されませんでした。
あなたはすべてのフラグを無条件にクリアする必要があります。これは、newHero()
メソッドを呼び出した後にフォームのreset()
メソッドを呼び出すことで実行できます。
src/app/hero-form.component.html (Reset the form)
<button type="button" class="btn btn-default" (click)="newHero(); heroForm.reset()">New Hero</button>
「New Hero」をクリックすると、フォームとコントロールフラグの両方がリセットされます。
ngSubmit でフォームをsubmitする
フォームの下部にある[Submit]ボタンは、単独では何も行いませんが、タイプ(type="submit")
のためにフォーム送信がトリガーされます。
現時点では、「フォームのsubmit」は役に立ちません。これを便利にするには、フォームのngSubmitイベントプロパティをheroフォームコンポーネントのonSubmit()メソッドにバインドします。
src/app/hero-form.component.html (ngSubmit)
<form (ngSubmit)="onSubmit()" #heroForm="ngForm">
テンプレート参照変数、#heroFormを既に定義しておき、それを値 "ngForm"で初期化しました。 さて、この変数を使用して、Submitボタンでフォームにアクセスします。
フォームの全体的な有効性は、イベントバインディングを使用してheroForm変数を介してボタンのdisabledプロパティにバインドします。 コードは次のとおりです:
src/app/hero-form.component.html (submit-button)
<button type="submit" class="btn btn-success" [disabled]="!heroForm.form.valid">Submit</button>
今すぐアプリケーションを実行すると、ボタンが有効になっていることがわかりますが、まだ便利な機能はありません。
ここで名前を削除すると、エラーメッセージに正しく記されている「必須」ルールに違反します。 [送信]ボタンも無効になっています。
感心しない? それについて少し考えてみてください。 あなたはAngularの助けを借りずにボタンの有効/無効状態をフォームの有効性に結びつけるために何かする必要がありますか?
それはこれほど簡単でした:
- (拡張された)フォーム要素にテンプレート参照変数を定義します。
- 多くの行のボタンの変数を参照してください。
2つのフォーム領域を切り替える(extra credit)
フォームをsubmitするのは現時点ではドラマチックはありません。
デモのための驚くべき観察。 正直言って、それを怒らせても、あなたは新しい形について何も教えてくれません。 しかし、これはあなたの新たに獲得した拘束力のあるスキルのいくつかを行使する機会です。
もし興味がなければ、このページのまとめにスキップしてください。
より目立つような視覚効果を得るには、データ入力領域を非表示にして別のものを表示します。
フォームを
src/app/hero-form.component.html (抜粋)
<div [hidden]="submitted">
<h1>Hero Form</h1>
<form (ngSubmit)="onSubmit()" #heroForm="ngForm">
<!-- ... all of the form ... -->
</form>
</div>
メインフォームは最初から表示されます。なぜなら、HeroFormComponentのこのフラグメントが示すように、フォームを送信するまで、サブミットされたプロパティはfalseであるからです。
src/app/hero-form.component.ts (submitted)
submitted = false;
onSubmit() { this.submitted = true; }
[送信]ボタンをクリックすると、submitted
フラグがtrue
になり、フォームは計画どおりに消えます。
フォームが提出された状態になっている間、アプリは別のものを表示する必要があります。 作成した<div>
ラッパーの下に次のHTMLを追加します。
src/app/hero-form.component.html (excerpt)
<div [hidden]="!submitted">
<h2>You submitted the following:</h2>
<div class="row">
<div class="col-xs-3">Name</div>
<div class="col-xs-9 pull-left">{{ model.name }}</div>
</div>
<div class="row">
<div class="col-xs-3">Alter Ego</div>
<div class="col-xs-9 pull-left">{{ model.alterEgo }}</div>
</div>
<div class="row">
<div class="col-xs-3">Power</div>
<div class="col-xs-9 pull-left">{{ model.power }}</div>
</div>
<br>
<button class="btn btn-primary" (click)="submitted=false">Edit</button>
</div>
ヒーローが再びあり、補間バインディングで読み取り専用で表示されます。 この<div>
は、コンポーネントがサブミットされた状態のときにのみ表示されます。
HTMLには、クリックイベントが送信済みフラグをクリアする式にバインドされた編集ボタンが含まれています。
編集ボタンをクリックすると、このブロックは消え、編集可能なフォームが再び表示されます。
まとめ
このページで説明するAngularフォームは、データの変更、検証などをサポートするために、次のフレームワーク機能を利用しています。
- Angular HTMLフォームテンプレート。
-
@Component
デコレータを持つフォームコンポーネントクラス。 - NgForm.ngSubmitイベントプロパティにバインドしてフォームの送信を処理します。
-
#heroForm
や#name
などのテンプレート参照変数。 - [(ngModel)]構文は、双方向データバインディング用です。
- 検証およびフォーム要素の変更追跡にname属性を使用する。
- コントロールが有効かどうかをチェックし、エラーメッセージを表示/非表示にするための入力コントロールの参照変数の有効なプロパティ。
- NgFormの有効性にバインドすることによって、送信ボタンの有効状態を制御します。
- 無効なコントロールについてユーザーに視覚的なフィードバックを提供するカスタムCSSクラス。
最終的なプロジェクトのフォルダ構造は次のようになります。
- angular-forms
- src
- app
- app.component.ts
- app.module.ts
- hero.ts
- hero-form.component.html
- hero-form.component.ts
- main.ts
- tsconfig.json
- index.html
- node_modules ...
- package.json
アプリケーションの最終バージョンのコードは次のとおりです。