このチュートリアルでは、テンプレート駆動型フォームの作成方法について説明します。フォーム内のコントロール要素は、入力検証を含むデータプロパティにバインドされています。入力検証は、データの整合性を維持し、ユーザー体験を向上させるためのスタイリングに役立ちます。
テンプレート駆動型フォームは、双方向データバインディングを使用して、テンプレートでの変更が加えられたときにコンポーネントのデータモデルを更新し、その逆も同様に行います。
テンプレートフォームとリアクティブフォーム
Angularは、インタラクティブフォームのために2つの設計アプローチをサポートしています。テンプレート駆動型フォームでは、Angularテンプレートでフォーム固有のディレクティブを使用できます。リアクティブフォームは、フォーム構築のためのモデル駆動型アプローチを提供します。
テンプレート駆動型フォームは、小規模または単純なフォームに適していますが、リアクティブフォームはよりスケーラブルで、複雑なフォームに適しています。2つのアプローチの比較については、アプローチの選択を参照してください。
Angularテンプレートを使用して、ログインフォーム、コンタクトフォーム、ほとんどのビジネスフォームなど、あらゆる種類のフォームを構築できます。 コントロールをクリエイティブにレイアウトし、オブジェクトモデル内のデータにバインドできます。 検証ルールを指定し、検証エラーを表示し、特定のコントロールからの入力を条件付きで許可します。そして、組み込みの視覚的なフィードバックをトリガーし、その他多くのことができます。
目標
このチュートリアルでは、次の方法について学びます。
- コンポーネントとテンプレートを使用してAngularフォームを構築する
ngModel
を使用して、入力コントロールの値を読み書きするための双方向データバインディングを作成する- コントロールの状態を追跡する特別なCSSクラスを使用して、視覚的なフィードバックを提供する
- ユーザーに検証エラーを表示し、フォームの状態に基づいてフォームコントロールからの入力を条件付きで許可する
- テンプレート参照変数を使用して、HTML要素間で情報を共有する
テンプレート駆動型フォームの構築
テンプレート駆動型フォームは、FormsModule
で定義されたディレクティブに依存します。
ディレクティブ | 詳細 |
---|---|
NgModel |
アタッチされたフォーム要素の値の変更とデータモデルの変更を調整し、入力検証やエラー処理を使用してユーザー入力に対応できるようにします。 |
NgForm |
トップレベルのFormGroup インスタンスを作成し、<form> 要素にバインドして、集計されたフォームの値と検証の状態を追跡します。FormsModule をインポートすると、このディレクティブはすべての<form> タグでデフォルトでアクティブになります。特別なセレクターを追加する必要はありません。 |
NgModelGroup |
DOM要素にFormGroup インスタンスを作成してバインドします。 |
ステップの概要
このチュートリアルでは、次の手順を使用して、サンプルフォームをデータにバインドし、ユーザー入力を処理します。
- 基本的なフォームを構築する。
- サンプルデータモデルを定義する
FormsModule
など、必要なインフラストラクチャを含める
ngModel
ディレクティブと双方向データバインディング構文を使用して、フォームコントロールをデータプロパティにバインドする。ngModel
がCSSクラスを使用してコントロールの状態を報告する方法を調べる- コントロールに名前を付けて、
ngModel
からアクセスできるようにする
ngModel
を使用して、入力の有効性とコントロールの状態を追跡する。- 状態に基づいて視覚的なフィードバックを提供するためのカスタムCSSを追加する
- 検証エラーメッセージを表示および非表示にする
- モデルデータに追加することで、ネイティブHTMLボタンのクリックイベントに対応する。
- フォームの
ngSubmit
出力プロパティを使用して、フォームの送信を処理する。- フォームが有効になるまで、Submitボタンを無効にする
- 送信後、ページ上の異なるコンテンツに、完了したフォームを交換する
フォームの構築
提供されたサンプルアプリケーションは、フォームに反映されるデータモデルを定義する
Actor
クラスを作成します。src/app/actor.ts
export class Actor { constructor( public id: number, public name: string, public skill: string, public studio?: string, ) {}}
フォームのレイアウトと詳細は、
ActorFormComponent
クラスで定義されます。src/app/actor-form/actor-form.component.ts (v1)
import {Component} from '@angular/core';import {Actor} from '../actor';@Component({ selector: 'app-actor-form', templateUrl: './actor-form.component.html', standalone: false,})export class ActorFormComponent { skills = ['Method Acting', 'Singing', 'Dancing', 'Swordfighting']; model = new Actor(18, 'Tom Cruise', this.skills[3], 'CW Productions'); submitted = false; onSubmit() { this.submitted = true; } newActor() { this.model = new Actor(42, '', ''); } heroine(): Actor { const myActress = new Actor(42, 'Marilyn Monroe', 'Singing'); console.log('My actress is called ' + myActress.name); // "My actress is called Marilyn" return myActress; } //////// NOT SHOWN IN DOCS //////// // Reveal in html: // Name via form.controls = {{showFormControls(actorForm)}} showFormControls(form: any) { return form && form.controls.name && form.controls.name.value; // Tom Cruise } /////////////////////////////}
コンポーネントの
selector
値は"app-actor-form"であるため、このフォームを<app-actor-form>
タグを使用して親テンプレートにドロップできます。次のコードは、新しいアクターインスタンスを作成し、初期フォームにサンプルアクターを表示します。
import {Component} from '@angular/core';import {Actor} from '../actor';@Component({ selector: 'app-actor-form', templateUrl: './actor-form.component.html', standalone: false,})export class ActorFormComponent { skills = ['Method Acting', 'Singing', 'Dancing', 'Swordfighting']; model = new Actor(18, 'Tom Cruise', this.skills[3], 'CW Productions'); submitted = false; onSubmit() { this.submitted = true; } newActor() { this.model = new Actor(42, '', ''); } heroine(): Actor { const myActress = new Actor(42, 'Marilyn Monroe', 'Singing'); console.log('My actress is called ' + myActress.name); // "My actress is called Marilyn" return myActress; } //////// NOT SHOWN IN DOCS //////// // Reveal in html: // Name via form.controls = {{showFormControls(actorForm)}} showFormControls(form: any) { return form && form.controls.name && form.controls.name.value; // Tom Cruise } /////////////////////////////}
このデモでは、
model
とskills
のダミーデータを使用しています。 実際のアプリでは、データサービスを注入して実際のデータを取得して保存するか、これらのプロパティを入力と出力として公開します。アプリケーションは、フォーム機能を有効にし、作成されたフォームコンポーネントを登録します。
src/app/app.module.ts
import {CommonModule} from '@angular/common';import {NgModule} from '@angular/core';import {FormsModule} from '@angular/forms';import {BrowserModule} from '@angular/platform-browser';import {AppComponent} from './app.component';import {ActorFormComponent} from './actor-form/actor-form.component';@NgModule({ imports: [BrowserModule, CommonModule, FormsModule], declarations: [AppComponent, ActorFormComponent], providers: [], bootstrap: [AppComponent],})export class AppModule {}
フォームは、ルートコンポーネントのテンプレートで定義されたアプリケーションレイアウトに表示されます。
src/app/app.component.html
<app-actor-form></app-actor-form>
初期テンプレートは、2つのフォームグループと送信ボタンを持つフォームのレイアウトを定義します。 フォームグループは、Actorデータモデルの2つのプロパティ(名前とスタジオ)に対応します。 各グループには、ラベルとユーザー入力を得るためのボックスがあります。
- 名前
<input>
コントロール要素には、HTML5のrequired
属性があります - スタジオ
<input>
コントロール要素には、studio
はオプションであるため、属性がありません
Submitボタンには、スタイリングのためのいくつかのクラスがあります。 現時点では、フォームのレイアウトはすべてプレーンなHTML5で、バインディングやディレクティブはありません。
- 名前
サンプルフォームは、Twitter Bootstrapの
container
、form-group
、form-control
、btn
といったスタイルクラスを使用しています。 これらのスタイルを使用するには、アプリケーションのスタイルシートでライブラリをインポートします。src/styles.css
@import url('https://unpkg.com/bootstrap@3.3.7/dist/css/bootstrap.min.css');
フォームでは、アクターのスキルを、
ActorFormComponent
で内部的に維持されている事前定義されたskills
リストから選択する必要があります。 AngularのNgForOfディレクティブは、データ値を反復処理して、<select>
要素に値を埋め込みます。src/app/actor-form/actor-form.component.html (skills)
<div class="container"> <div [hidden]="submitted"> <h1>Actor Form</h1> <form (ngSubmit)="onSubmit()" #actorForm="ngForm"> <div class="form-group"> <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> </div> <div class="form-group"> <label for="studio">Studio Affiliation</label> <input type="text" class="form-control" id="studio" [(ngModel)]="model.studio" name="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required [(ngModel)]="model.skill" name="skill" #skill="ngModel"> <option *ngFor="let skill of skills" [value]="skill">{{ skill }}</option> </select> <div [hidden]="skill.valid || skill.pristine" class="alert alert-danger"> skill is required </div> </div> <button type="submit" class="btn btn-success" [disabled]="!actorForm.form.valid">Submit</button> <button type="button" class="btn btn-default" (click)="newActor(); actorForm.reset()">New Actor</button> <em>with</em> reset <button type="button" class="btn btn-default" (click)="newActor()">New Actor</button> <em>without</em> reset <!-- NOT SHOWN IN DOCS --> <div> <hr> Name via form.controls = {{ showFormControls(actorForm) }} </div> <!-- - --> </form> </div> <div [hidden]="!submitted"> <h2>You submitted the following:</h2> <div class="row"> <div class="col-xs-3">Name</div> <div class="col-xs-9">{{ model.name }}</div> </div> <div class="row"> <div class="col-xs-3">Studio</div> <div class="col-xs-9">{{ model.studio }}</div> </div> <div class="row"> <div class="col-xs-3">Skill</div> <div class="col-xs-9">{{ model.skill }}</div> </div> <br> <button type="button" class="btn btn-primary" (click)="submitted=false"> Edit </button> </div></div><!-- ==================================================== --> <div> <form> <!-- ... all of the form ... --> </form> </div><!-- ==================================================== --><hr><style> .no-style .ng-valid { border-left: 1px solid #CCC} .no-style .ng-invalid { border-left: 1px solid #CCC}</style><div class="no-style" style="margin-left: 4px"> <div class="container"> <h1>Actor 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="studio">Studio</label> <input type="text" class="form-control" id="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required> <option *ngFor="let skill of skills" [value]="skill">{{ skill }}</option> </select> </div> <button type="submit" class="btn btn-success">Submit</button> </form> </div> <!-- ==================================================== --> <hr> <div class="container"> <h1>Actor Form</h1> <form #actorForm="ngForm"> {{ model | json }} <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="studio">Studio</label> <input type="text" class="form-control" id="studio" [(ngModel)]="model.studio" name="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required [(ngModel)]="model.skill" name="skill"> <option *ngFor="let skill of skills" [value]="skill">{{ skill }}</option> </select> </div> <button type="submit" class="btn btn-success">Submit</button> </form> </div> <!-- EXTRA MATERIAL FOR DOCUMENTATION --> <hr> <input type="text" class="form-control" id="name" required [(ngModel)]="model.name" name="name"> TODO: remove this: {{ model.name}} <hr> <input type="text" class="form-control" id="name" required [ngModel]="model.name" name="name" (ngModelChange)="model.name = $event"> TODO: remove this: {{ model.name}}</div>
アプリケーションを今すぐ実行すると、選択コントロールにスキルのリストが表示されます。 入力要素は、まだデータ値やイベントにバインドされていないため、空欄であり、動作しません。
入力コントロールをデータプロパティにバインドする
次のステップは、入力コントロールを対応するActor
プロパティに双方向データバインディングでバインドすることです。これにより、ユーザー入力がデータモデルを更新し、データのプログラムによる変更がディスプレイを更新します。
FormsModule
で宣言されたngModel
ディレクティブを使用すると、テンプレート駆動型フォームのテンプレート内のコントロールを、データモデルのプロパティにバインドできます。
双方向データバインディングの構文[(ngModel)]="..."
を使用してディレクティブを含めると、Angularはコントロールの値とユーザー操作を追跡し、ビューとモデルを同期させることができます。
- テンプレートファイル
actor-form.component.html
を編集します。 - 名前ラベルの隣の
<input>
タグを探します。 ngModel
ディレクティブを追加し、双方向データバインディング構文[(ngModel)]="..."
を使用します。
src/app/actor-form/actor-form.component.html (excerpt)
<div class="container"> <div [hidden]="submitted"> <h1>Actor Form</h1> <form (ngSubmit)="onSubmit()" #actorForm="ngForm"> <div class="form-group"> <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> </div> <div class="form-group"> <label for="studio">Studio Affiliation</label> <input type="text" class="form-control" id="studio" [(ngModel)]="model.studio" name="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required [(ngModel)]="model.skill" name="skill" #skill="ngModel"> <option *ngFor="let skill of skills" [value]="skill">{{ skill }}</option> </select> <div [hidden]="skill.valid || skill.pristine" class="alert alert-danger"> skill is required </div> </div> <button type="submit" class="btn btn-success" [disabled]="!actorForm.form.valid">Submit</button> <button type="button" class="btn btn-default" (click)="newActor(); actorForm.reset()">New Actor</button> <em>with</em> reset <button type="button" class="btn btn-default" (click)="newActor()">New Actor</button> <em>without</em> reset <!-- NOT SHOWN IN DOCS --> <div> <hr> Name via form.controls = {{ showFormControls(actorForm) }} </div> <!-- - --> </form> </div> <div [hidden]="!submitted"> <h2>You submitted the following:</h2> <div class="row"> <div class="col-xs-3">Name</div> <div class="col-xs-9">{{ model.name }}</div> </div> <div class="row"> <div class="col-xs-3">Studio</div> <div class="col-xs-9">{{ model.studio }}</div> </div> <div class="row"> <div class="col-xs-3">Skill</div> <div class="col-xs-9">{{ model.skill }}</div> </div> <br> <button type="button" class="btn btn-primary" (click)="submitted=false"> Edit </button> </div></div><!-- ==================================================== --> <div> <form> <!-- ... all of the form ... --> </form> </div><!-- ==================================================== --><hr><style> .no-style .ng-valid { border-left: 1px solid #CCC} .no-style .ng-invalid { border-left: 1px solid #CCC}</style><div class="no-style" style="margin-left: 4px"> <div class="container"> <h1>Actor 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="studio">Studio</label> <input type="text" class="form-control" id="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required> <option *ngFor="let skill of skills" [value]="skill">{{ skill }}</option> </select> </div> <button type="submit" class="btn btn-success">Submit</button> </form> </div> <!-- ==================================================== --> <hr> <div class="container"> <h1>Actor Form</h1> <form #actorForm="ngForm"> {{ model | json }} <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="studio">Studio</label> <input type="text" class="form-control" id="studio" [(ngModel)]="model.studio" name="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required [(ngModel)]="model.skill" name="skill"> <option *ngFor="let skill of skills" [value]="skill">{{ skill }}</option> </select> </div> <button type="submit" class="btn btn-success">Submit</button> </form> </div> <!-- EXTRA MATERIAL FOR DOCUMENTATION --> <hr> <input type="text" class="form-control" id="name" required [(ngModel)]="model.name" name="name"> TODO: remove this: {{ model.name}} <hr> <input type="text" class="form-control" id="name" required [ngModel]="model.name" name="name" (ngModelChange)="model.name = $event"> TODO: remove this: {{ model.name}}</div>
HELPFUL: この例では、各入力タグの後に一時的な診断用補間{{model.name}}
が追加され、対応するプロパティの現在のデータ値が表示されます。コメントは、双方向データバインディングの動作を観察し終わったら、診断用行を削除するよう思い出させてくれます。
フォーム全体のステータスにアクセスする
コンポーネントでFormsModule
をインポートすると、Angularはテンプレートの<form>
タグにNgFormディレクティブを自動的に作成してアタッチします(NgForm
のセレクターは<form>
要素と一致するform
だからです)。
NgForm
とフォーム全体のステータスにアクセスするには、テンプレート参照変数を宣言します。
テンプレートファイル
actor-form.component.html
を編集します。テンプレート参照変数
#actorForm
を付けて<form>
タグを更新し、次の値を設定します。src/app/actor-form/actor-form.component.html (excerpt)
<div class="container"> <div [hidden]="submitted"> <h1>Actor Form</h1> <form (ngSubmit)="onSubmit()" #actorForm="ngForm"> <div class="form-group"> <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> </div> <div class="form-group"> <label for="studio">Studio Affiliation</label> <input type="text" class="form-control" id="studio" [(ngModel)]="model.studio" name="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required [(ngModel)]="model.skill" name="skill" #skill="ngModel"> <option *ngFor="let skill of skills" [value]="skill">{{ skill }}</option> </select> <div [hidden]="skill.valid || skill.pristine" class="alert alert-danger"> skill is required </div> </div> <button type="submit" class="btn btn-success" [disabled]="!actorForm.form.valid">Submit</button> <button type="button" class="btn btn-default" (click)="newActor(); actorForm.reset()">New Actor</button> <em>with</em> reset <button type="button" class="btn btn-default" (click)="newActor()">New Actor</button> <em>without</em> reset <!-- NOT SHOWN IN DOCS --> <div> <hr> Name via form.controls = {{ showFormControls(actorForm) }} </div> <!-- - --> </form> </div> <div [hidden]="!submitted"> <h2>You submitted the following:</h2> <div class="row"> <div class="col-xs-3">Name</div> <div class="col-xs-9">{{ model.name }}</div> </div> <div class="row"> <div class="col-xs-3">Studio</div> <div class="col-xs-9">{{ model.studio }}</div> </div> <div class="row"> <div class="col-xs-3">Skill</div> <div class="col-xs-9">{{ model.skill }}</div> </div> <br> <button type="button" class="btn btn-primary" (click)="submitted=false"> Edit </button> </div></div><!-- ==================================================== --> <div> <form> <!-- ... all of the form ... --> </form> </div><!-- ==================================================== --><hr><style> .no-style .ng-valid { border-left: 1px solid #CCC} .no-style .ng-invalid { border-left: 1px solid #CCC}</style><div class="no-style" style="margin-left: 4px"> <div class="container"> <h1>Actor 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="studio">Studio</label> <input type="text" class="form-control" id="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required> <option *ngFor="let skill of skills" [value]="skill">{{ skill }}</option> </select> </div> <button type="submit" class="btn btn-success">Submit</button> </form> </div> <!-- ==================================================== --> <hr> <div class="container"> <h1>Actor Form</h1> <form #actorForm="ngForm"> {{ model | json }} <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="studio">Studio</label> <input type="text" class="form-control" id="studio" [(ngModel)]="model.studio" name="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required [(ngModel)]="model.skill" name="skill"> <option *ngFor="let skill of skills" [value]="skill">{{ skill }}</option> </select> </div> <button type="submit" class="btn btn-success">Submit</button> </form> </div> <!-- EXTRA MATERIAL FOR DOCUMENTATION --> <hr> <input type="text" class="form-control" id="name" required [(ngModel)]="model.name" name="name"> TODO: remove this: {{ model.name}} <hr> <input type="text" class="form-control" id="name" required [ngModel]="model.name" name="name" (ngModelChange)="model.name = $event"> TODO: remove this: {{ model.name}}</div>
actorForm
テンプレート変数は、フォーム全体を管理するNgForm
ディレクティブインスタンスへの参照になります。アプリケーションを実行します。
名前入力ボックスに入力し始めます。
文字を追加したり削除したりすると、データモデルにも表示および非表示されます。
補間された値を表示する診断用行は、値が実際に入力ボックスからモデルに、そしてモデルから入力ボックスに戻っていることを示しています。
コントロール要素に名前を付ける
[(ngModel)]
を要素に使用する場合は、その要素のname
属性を定義する必要があります。
Angularは、割り当てられた名前を使用して、親<form>
要素にアタッチされたNgForm
ディレクティブに要素を登録します。
例では、<input>
要素にname
属性を追加し、"name"に設定しました。これは、アクターの名前を表現するのに理にかなっています。
任意のユニークな値で構いませんが、わかりやすい名前を使用すると便利です。
- スタジオとスキルに同様の
[(ngModel)]
バインディングとname
属性を追加します。 - 補間された値を表示する診断メッセージを削除できます。
- アクターモデル全体に双方向データバインディングが機能することを確認するために、コンポーネントのテンプレートの最上部に、
json
パイプを使用した新しいテキストバインディングを追加します。これは、データを文字列にシリアライズします。
これらの変更を加えた後、フォームテンプレートは次のようになります。
src/app/actor-form/actor-form.component.html (excerpt)
<div class="container"> <div [hidden]="submitted"> <h1>Actor Form</h1> <form (ngSubmit)="onSubmit()" #actorForm="ngForm"> <div class="form-group"> <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> </div> <div class="form-group"> <label for="studio">Studio Affiliation</label> <input type="text" class="form-control" id="studio" [(ngModel)]="model.studio" name="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required [(ngModel)]="model.skill" name="skill" #skill="ngModel"> <option *ngFor="let skill of skills" [value]="skill">{{ skill }}</option> </select> <div [hidden]="skill.valid || skill.pristine" class="alert alert-danger"> skill is required </div> </div> <button type="submit" class="btn btn-success" [disabled]="!actorForm.form.valid">Submit</button> <button type="button" class="btn btn-default" (click)="newActor(); actorForm.reset()">New Actor</button> <em>with</em> reset <button type="button" class="btn btn-default" (click)="newActor()">New Actor</button> <em>without</em> reset <!-- NOT SHOWN IN DOCS --> <div> <hr> Name via form.controls = {{ showFormControls(actorForm) }} </div> <!-- - --> </form> </div> <div [hidden]="!submitted"> <h2>You submitted the following:</h2> <div class="row"> <div class="col-xs-3">Name</div> <div class="col-xs-9">{{ model.name }}</div> </div> <div class="row"> <div class="col-xs-3">Studio</div> <div class="col-xs-9">{{ model.studio }}</div> </div> <div class="row"> <div class="col-xs-3">Skill</div> <div class="col-xs-9">{{ model.skill }}</div> </div> <br> <button type="button" class="btn btn-primary" (click)="submitted=false"> Edit </button> </div></div><!-- ==================================================== --> <div> <form> <!-- ... all of the form ... --> </form> </div><!-- ==================================================== --><hr><style> .no-style .ng-valid { border-left: 1px solid #CCC} .no-style .ng-invalid { border-left: 1px solid #CCC}</style><div class="no-style" style="margin-left: 4px"> <div class="container"> <h1>Actor 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="studio">Studio</label> <input type="text" class="form-control" id="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required> <option *ngFor="let skill of skills" [value]="skill">{{ skill }}</option> </select> </div> <button type="submit" class="btn btn-success">Submit</button> </form> </div> <!-- ==================================================== --> <hr> <div class="container"> <h1>Actor Form</h1> <form #actorForm="ngForm"> {{ model | json }} <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="studio">Studio</label> <input type="text" class="form-control" id="studio" [(ngModel)]="model.studio" name="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required [(ngModel)]="model.skill" name="skill"> <option *ngFor="let skill of skills" [value]="skill">{{ skill }}</option> </select> </div> <button type="submit" class="btn btn-success">Submit</button> </form> </div> <!-- EXTRA MATERIAL FOR DOCUMENTATION --> <hr> <input type="text" class="form-control" id="name" required [(ngModel)]="model.name" name="name"> TODO: remove this: {{ model.name}} <hr> <input type="text" class="form-control" id="name" required [ngModel]="model.name" name="name" (ngModelChange)="model.name = $event"> TODO: remove this: {{ model.name}}</div>
次のことに注意してください。
各
<input>
要素にはid
プロパティがあります。 これは、<label>
要素のfor
属性によって使用され、ラベルを入力コントロールに一致させます。 これは標準的なHTML機能です。各
<input>
要素には、Angularがフォームにコントロールを登録するために使用する必要なname
プロパティもあります。
効果を確認したら、{{ model | json }}
テキストバインディングを削除できます。
フォームの状態を追跡する
Angularは、フォームが送信された後にform
要素にng-submitted
クラスを適用します。このクラスは、フォームが送信された後にフォームのスタイルを変更するために使用できます。
コントロールの状態を追跡する
コントロールにNgModel
ディレクティブを追加すると、コントロールの状態を表すクラス名がコントロールに追加されます。
これらのクラスは、コントロールの状態に基づいてコントロールのスタイルを変更するために使用できます。
次の表は、コントロールの状態に基づいてAngularが適用するクラス名を説明しています。
状態 | クラス(真の場合) | クラス(偽の場合) |
---|---|---|
コントロールが訪問された。 | ng-touched |
ng-untouched |
コントロールの値が変更された。 | ng-dirty |
ng-pristine |
コントロールの値が有効。 | ng-valid |
ng-invalid |
Angularは、form
要素にng-submitted
クラスを適用しますが、
form
要素内のコントロールには適用しません。
これらのCSSクラスを使用して、コントロールの状態に基づいてコントロールのスタイルを定義します。
コントロールの状態を観察する
フレームワークによるクラスの追加と削除を確認するには、ブラウザの開発者ツールを開き、アクターの名前を表す<input>
要素を調べます。
ブラウザの開発者ツールを使用して、Name入力ボックスに対応する
<input>
要素を探します。 要素には、"form-control"に加えて、複数のCSSクラスがあることがわかります。最初に表示すると、クラスは、値が有効であり、初期化またはリセット以降値が変更されていないこと、初期化またはリセット以降コントロールが訪問されていないことを示しています。
<input class="form-control ng-untouched ng-pristine ng-valid">;
Name
<input>
ボックスで次のように操作し、表示されるクラスを観察します。見るだけで触れずにいます。 クラスは触られていないか、原始状態または有効であることを示しています。
名前のボックスをクリックし、外をクリックします。 コントロールは訪問されたため、要素には
ng-untouched
クラスではなくng-touched
クラスがあります。名前の最後にスラッシュを追加します。 これで触れられて、汚れています。
名前を消去します。 これにより値が無効になるため、
ng-invalid
クラスがng-valid
クラスに置き換えられます。
状態の視覚的なフィードバックを作成する
ng-valid
/ng-invalid
ペアは特に興味深いものです。
なぜなら、値が無効な場合に明確な視覚的な信号を送信したいからです。
また、必須フィールドをマークすることも必要です。
入力ボックスの左側に色の付いたバーを使用して、必須フィールドと無効なデータを同時にマークできます。
この方法で外観を変更するには、次の手順を実行します。
ng-*
CSSクラスの定義を追加します。- これらのクラス定義を新しい
forms.css
ファイルに追加します。 - 新しいファイルを、
index.html
と同じレベルにプロジェクトに追加します。
src/assets/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>
タグを更新します。
src/index.html (styles)
<!DOCTYPE html><html lang="en"> <head> <title>Hero Form</title> <base href="/"> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="https://unpkg.com/bootstrap@3.3.7/dist/css/bootstrap.min.css"> <link rel="stylesheet" href="assets/forms.css"> </head> <body> <app-root></app-root> </body></html>
検証エラーメッセージの表示と非表示
名前入力ボックスは必須であり、クリアするとバーが赤くなります。 これは何かが間違っていることを示していますが、ユーザーは何が間違っているのか、 どうすればいいのかわかりません。 コントロールの状態をチェックして対応することで、役立つメッセージを提供できます。
スキル選択ボックスも必須ですが、この種のエラー処理は必要ありません。なぜなら、選択ボックスはすでに選択を有効な値に制限しているからです。
エラーメッセージを適切に定義して表示するには、次の手順を実行します。
-
入力へのローカル参照を追加
テンプレートから入力ボックスのAngularコントロールにアクセスするために使用できるテンプレート参照変数を使用して、
input
タグを拡張します。例では、変数は#name="ngModel"
です。テンプレート参照変数(
#name
)は"ngModel"
に設定されています。なぜなら、それはNgModel.exportAs
プロパティの値だからです。このプロパティは、Angularに参照変数をディレクティブにどのようにリンクするかを指示します。 -
エラーメッセージを追加
適切なエラーメッセージを含む
<div>
を追加します。 -
エラーメッセージを条件付きにする
name
コントロールのプロパティを、メッセージ<div>
要素のhidden
プロパティにバインドすることで、エラーメッセージを表示または非表示にします。 -
名前への条件付きエラーメッセージを追加
次の例のように、
name
入力ボックスに条件付きエラーメッセージを追加します。src/app/actor-form/actor-form.component.html (excerpt)
<div class="container"> <div [hidden]="submitted"> <h1>Actor Form</h1> <form (ngSubmit)="onSubmit()" #actorForm="ngForm"> <div class="form-group"> <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> </div> <div class="form-group"> <label for="studio">Studio Affiliation</label> <input type="text" class="form-control" id="studio" [(ngModel)]="model.studio" name="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required [(ngModel)]="model.skill" name="skill" #skill="ngModel"> <option *ngFor="let skill of skills" [value]="skill">{{ skill }}</option> </select> <div [hidden]="skill.valid || skill.pristine" class="alert alert-danger"> skill is required </div> </div> <button type="submit" class="btn btn-success" [disabled]="!actorForm.form.valid">Submit</button> <button type="button" class="btn btn-default" (click)="newActor(); actorForm.reset()">New Actor</button> <em>with</em> reset <button type="button" class="btn btn-default" (click)="newActor()">New Actor</button> <em>without</em> reset <!-- NOT SHOWN IN DOCS --> <div> <hr> Name via form.controls = {{ showFormControls(actorForm) }} </div> <!-- - --> </form> </div> <div [hidden]="!submitted"> <h2>You submitted the following:</h2> <div class="row"> <div class="col-xs-3">Name</div> <div class="col-xs-9">{{ model.name }}</div> </div> <div class="row"> <div class="col-xs-3">Studio</div> <div class="col-xs-9">{{ model.studio }}</div> </div> <div class="row"> <div class="col-xs-3">Skill</div> <div class="col-xs-9">{{ model.skill }}</div> </div> <br> <button type="button" class="btn btn-primary" (click)="submitted=false"> Edit </button> </div></div><!-- ==================================================== --> <div> <form> <!-- ... all of the form ... --> </form> </div><!-- ==================================================== --><hr><style> .no-style .ng-valid { border-left: 1px solid #CCC} .no-style .ng-invalid { border-left: 1px solid #CCC}</style><div class="no-style" style="margin-left: 4px"> <div class="container"> <h1>Actor 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="studio">Studio</label> <input type="text" class="form-control" id="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required> <option *ngFor="let skill of skills" [value]="skill">{{ skill }}</option> </select> </div> <button type="submit" class="btn btn-success">Submit</button> </form> </div> <!-- ==================================================== --> <hr> <div class="container"> <h1>Actor Form</h1> <form #actorForm="ngForm"> {{ model | json }} <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="studio">Studio</label> <input type="text" class="form-control" id="studio" [(ngModel)]="model.studio" name="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required [(ngModel)]="model.skill" name="skill"> <option *ngFor="let skill of skills" [value]="skill">{{ skill }}</option> </select> </div> <button type="submit" class="btn btn-success">Submit</button> </form> </div> <!-- EXTRA MATERIAL FOR DOCUMENTATION --> <hr> <input type="text" class="form-control" id="name" required [(ngModel)]="model.name" name="name"> TODO: remove this: {{ model.name}} <hr> <input type="text" class="form-control" id="name" required [ngModel]="model.name" name="name" (ngModelChange)="model.name = $event"> TODO: remove this: {{ model.name}}</div>
src/app/actor-form/actor-form.component.html (hidden-error-msg)
<div class="container"> <div [hidden]="submitted"> <h1>Actor Form</h1> <form (ngSubmit)="onSubmit()" #actorForm="ngForm"> <div class="form-group"> <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> </div> <div class="form-group"> <label for="studio">Studio Affiliation</label> <input type="text" class="form-control" id="studio" [(ngModel)]="model.studio" name="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required [(ngModel)]="model.skill" name="skill" #skill="ngModel"> <option *ngFor="let skill of skills" [value]="skill">{{ skill }}</option> </select> <div [hidden]="skill.valid || skill.pristine" class="alert alert-danger"> skill is required </div> </div> <button type="submit" class="btn btn-success" [disabled]="!actorForm.form.valid">Submit</button> <button type="button" class="btn btn-default" (click)="newActor(); actorForm.reset()">New Actor</button> <em>with</em> reset <button type="button" class="btn btn-default" (click)="newActor()">New Actor</button> <em>without</em> reset <!-- NOT SHOWN IN DOCS --> <div> <hr> Name via form.controls = {{ showFormControls(actorForm) }} </div> <!-- - --> </form> </div> <div [hidden]="!submitted"> <h2>You submitted the following:</h2> <div class="row"> <div class="col-xs-3">Name</div> <div class="col-xs-9">{{ model.name }}</div> </div> <div class="row"> <div class="col-xs-3">Studio</div> <div class="col-xs-9">{{ model.studio }}</div> </div> <div class="row"> <div class="col-xs-3">Skill</div> <div class="col-xs-9">{{ model.skill }}</div> </div> <br> <button type="button" class="btn btn-primary" (click)="submitted=false"> Edit </button> </div></div><!-- ==================================================== --> <div> <form> <!-- ... all of the form ... --> </form> </div><!-- ==================================================== --><hr><style> .no-style .ng-valid { border-left: 1px solid #CCC} .no-style .ng-invalid { border-left: 1px solid #CCC}</style><div class="no-style" style="margin-left: 4px"> <div class="container"> <h1>Actor 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="studio">Studio</label> <input type="text" class="form-control" id="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required> <option *ngFor="let skill of skills" [value]="skill">{{ skill }}</option> </select> </div> <button type="submit" class="btn btn-success">Submit</button> </form> </div> <!-- ==================================================== --> <hr> <div class="container"> <h1>Actor Form</h1> <form #actorForm="ngForm"> {{ model | json }} <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="studio">Studio</label> <input type="text" class="form-control" id="studio" [(ngModel)]="model.studio" name="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required [(ngModel)]="model.skill" name="skill"> <option *ngFor="let skill of skills" [value]="skill">{{ skill }}</option> </select> </div> <button type="submit" class="btn btn-success">Submit</button> </form> </div> <!-- EXTRA MATERIAL FOR DOCUMENTATION --> <hr> <input type="text" class="form-control" id="name" required [(ngModel)]="model.name" name="name"> TODO: remove this: {{ model.name}} <hr> <input type="text" class="form-control" id="name" required [ngModel]="model.name" name="name" (ngModelChange)="model.name = $event"> TODO: remove this: {{ model.name}}</div>
この例では、コントロールが有効あるいは_原始状態_のいずれかの場合にメッセージを非表示にします。
原始状態とは、ユーザーがこのフォームに表示されてから値を変更していないことを意味します。
pristine
状態を無視すると、値が有効な場合にのみメッセージを非表示にします。
新しい空白のアクターか無効なアクターがこのコンポーネントに表示されると、何も操作する前にエラーメッセージがすぐに表示されます。
メッセージは、ユーザーが無効な変更を加えた場合にのみ表示されるようにしたいかもしれません。
コントロールがpristine
状態の間にメッセージを非表示にすると、その目的を達成できます。
次のステップで新しいアクターをフォームに追加すると、この選択肢の重要性についてわかります。
新しいアクターを追加する
この演習では、モデルデータに追加することで、ネイティブHTMLボタンのクリックイベントに対応する方法を示します。 フォームユーザーが新しいアクターを追加できるようにするには、クリックイベントに対応するNew Actorボタンを追加します。
テンプレートで、フォームの下部に"New Actor"
<button>
要素を配置します。コンポーネントファイルで、アクターデータモデルにアクター作成メソッドを追加します。
src/app/actor-form/actor-form.component.ts (New Actor method)
import {Component} from '@angular/core';import {Actor} from '../actor';@Component({ selector: 'app-actor-form', templateUrl: './actor-form.component.html', standalone: false,})export class ActorFormComponent { skills = ['Method Acting', 'Singing', 'Dancing', 'Swordfighting']; model = new Actor(18, 'Tom Cruise', this.skills[3], 'CW Productions'); submitted = false; onSubmit() { this.submitted = true; } newActor() { this.model = new Actor(42, '', ''); } heroine(): Actor { const myActress = new Actor(42, 'Marilyn Monroe', 'Singing'); console.log('My actress is called ' + myActress.name); // "My actress is called Marilyn" return myActress; } //////// NOT SHOWN IN DOCS //////// // Reveal in html: // Name via form.controls = {{showFormControls(actorForm)}} showFormControls(form: any) { return form && form.controls.name && form.controls.name.value; // Tom Cruise } /////////////////////////////}
ボタンのクリックイベントを、アクター作成メソッド
newActor()
にバインドします。src/app/actor-form/actor-form.component.html (New Actor button)
<div class="container"> <div [hidden]="submitted"> <h1>Actor Form</h1> <form (ngSubmit)="onSubmit()" #actorForm="ngForm"> <div class="form-group"> <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> </div> <div class="form-group"> <label for="studio">Studio Affiliation</label> <input type="text" class="form-control" id="studio" [(ngModel)]="model.studio" name="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required [(ngModel)]="model.skill" name="skill" #skill="ngModel"> <option *ngFor="let skill of skills" [value]="skill">{{ skill }}</option> </select> <div [hidden]="skill.valid || skill.pristine" class="alert alert-danger"> skill is required </div> </div> <button type="submit" class="btn btn-success" [disabled]="!actorForm.form.valid">Submit</button> <button type="button" class="btn btn-default" (click)="newActor(); actorForm.reset()">New Actor</button> <em>with</em> reset <button type="button" class="btn btn-default" (click)="newActor()">New Actor</button> <em>without</em> reset <!-- NOT SHOWN IN DOCS --> <div> <hr> Name via form.controls = {{ showFormControls(actorForm) }} </div> <!-- - --> </form> </div> <div [hidden]="!submitted"> <h2>You submitted the following:</h2> <div class="row"> <div class="col-xs-3">Name</div> <div class="col-xs-9">{{ model.name }}</div> </div> <div class="row"> <div class="col-xs-3">Studio</div> <div class="col-xs-9">{{ model.studio }}</div> </div> <div class="row"> <div class="col-xs-3">Skill</div> <div class="col-xs-9">{{ model.skill }}</div> </div> <br> <button type="button" class="btn btn-primary" (click)="submitted=false"> Edit </button> </div></div><!-- ==================================================== --> <div> <form> <!-- ... all of the form ... --> </form> </div><!-- ==================================================== --><hr><style> .no-style .ng-valid { border-left: 1px solid #CCC} .no-style .ng-invalid { border-left: 1px solid #CCC}</style><div class="no-style" style="margin-left: 4px"> <div class="container"> <h1>Actor 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="studio">Studio</label> <input type="text" class="form-control" id="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required> <option *ngFor="let skill of skills" [value]="skill">{{ skill }}</option> </select> </div> <button type="submit" class="btn btn-success">Submit</button> </form> </div> <!-- ==================================================== --> <hr> <div class="container"> <h1>Actor Form</h1> <form #actorForm="ngForm"> {{ model | json }} <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="studio">Studio</label> <input type="text" class="form-control" id="studio" [(ngModel)]="model.studio" name="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required [(ngModel)]="model.skill" name="skill"> <option *ngFor="let skill of skills" [value]="skill">{{ skill }}</option> </select> </div> <button type="submit" class="btn btn-success">Submit</button> </form> </div> <!-- EXTRA MATERIAL FOR DOCUMENTATION --> <hr> <input type="text" class="form-control" id="name" required [(ngModel)]="model.name" name="name"> TODO: remove this: {{ model.name}} <hr> <input type="text" class="form-control" id="name" required [ngModel]="model.name" name="name" (ngModelChange)="model.name = $event"> TODO: remove this: {{ model.name}}</div>
アプリケーションを再度実行し、New Actorボタンをクリックします。
フォームがクリアされ、入力ボックスの左側の_必須_バーが赤くなり、
name
とskill
プロパティが無効であることを示しています。 エラーメッセージは非表示になっていることに注意してください。 これは、フォームが原始状態であるためです。まだ何も変更していません。名前を入力し、New Actorを再度クリックします。
入力ボックスはもはや原始状態ではないため、
名前は必須です
というエラーメッセージが表示されます。 フォームは、New Actorをクリックする前に名前を入力したことを覚えています。フォームコントロールの原始状態を復元するには、
newActor()
メソッドを呼び出した後に、フォームのreset()
メソッドを呼び出してすべてのフラグを強制的にクリアします。src/app/actor-form/actor-form.component.html (Reset the form)
<div class="container"> <div [hidden]="submitted"> <h1>Actor Form</h1> <form (ngSubmit)="onSubmit()" #actorForm="ngForm"> <div class="form-group"> <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> </div> <div class="form-group"> <label for="studio">Studio Affiliation</label> <input type="text" class="form-control" id="studio" [(ngModel)]="model.studio" name="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required [(ngModel)]="model.skill" name="skill" #skill="ngModel"> <option *ngFor="let skill of skills" [value]="skill">{{ skill }}</option> </select> <div [hidden]="skill.valid || skill.pristine" class="alert alert-danger"> skill is required </div> </div> <button type="submit" class="btn btn-success" [disabled]="!actorForm.form.valid">Submit</button> <button type="button" class="btn btn-default" (click)="newActor(); actorForm.reset()">New Actor</button> <em>with</em> reset <button type="button" class="btn btn-default" (click)="newActor()">New Actor</button> <em>without</em> reset <!-- NOT SHOWN IN DOCS --> <div> <hr> Name via form.controls = {{ showFormControls(actorForm) }} </div> <!-- - --> </form> </div> <div [hidden]="!submitted"> <h2>You submitted the following:</h2> <div class="row"> <div class="col-xs-3">Name</div> <div class="col-xs-9">{{ model.name }}</div> </div> <div class="row"> <div class="col-xs-3">Studio</div> <div class="col-xs-9">{{ model.studio }}</div> </div> <div class="row"> <div class="col-xs-3">Skill</div> <div class="col-xs-9">{{ model.skill }}</div> </div> <br> <button type="button" class="btn btn-primary" (click)="submitted=false"> Edit </button> </div></div><!-- ==================================================== --> <div> <form> <!-- ... all of the form ... --> </form> </div><!-- ==================================================== --><hr><style> .no-style .ng-valid { border-left: 1px solid #CCC} .no-style .ng-invalid { border-left: 1px solid #CCC}</style><div class="no-style" style="margin-left: 4px"> <div class="container"> <h1>Actor 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="studio">Studio</label> <input type="text" class="form-control" id="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required> <option *ngFor="let skill of skills" [value]="skill">{{ skill }}</option> </select> </div> <button type="submit" class="btn btn-success">Submit</button> </form> </div> <!-- ==================================================== --> <hr> <div class="container"> <h1>Actor Form</h1> <form #actorForm="ngForm"> {{ model | json }} <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="studio">Studio</label> <input type="text" class="form-control" id="studio" [(ngModel)]="model.studio" name="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required [(ngModel)]="model.skill" name="skill"> <option *ngFor="let skill of skills" [value]="skill">{{ skill }}</option> </select> </div> <button type="submit" class="btn btn-success">Submit</button> </form> </div> <!-- EXTRA MATERIAL FOR DOCUMENTATION --> <hr> <input type="text" class="form-control" id="name" required [(ngModel)]="model.name" name="name"> TODO: remove this: {{ model.name}} <hr> <input type="text" class="form-control" id="name" required [ngModel]="model.name" name="name" (ngModelChange)="model.name = $event"> TODO: remove this: {{ model.name}}</div>
これで、New Actorをクリックすると、フォームとそのコントロールフラグの両方がリセットされます。
ngSubmit
でフォームを送信する
ユーザーは、フォームに記入したら送信できる必要があります。
フォームの下部にあるSubmitボタンは、それ自体では何も実行しませんが、type="submit"
であるため、フォームの送信イベントをトリガーします。
このイベントに対応するには、次の手順を実行します。
-
ngOnSubmitを監視する
フォームの
ngSubmit
イベントプロパティを、アクターフォームコンポーネントのonSubmit()
メソッドにバインドします。src/app/actor-form/actor-form.component.html (ngSubmit)
<div class="container"> <div [hidden]="submitted"> <h1>Actor Form</h1> <form (ngSubmit)="onSubmit()" #actorForm="ngForm"> <div class="form-group"> <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> </div> <div class="form-group"> <label for="studio">Studio Affiliation</label> <input type="text" class="form-control" id="studio" [(ngModel)]="model.studio" name="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required [(ngModel)]="model.skill" name="skill" #skill="ngModel"> <option *ngFor="let skill of skills" [value]="skill">{{ skill }}</option> </select> <div [hidden]="skill.valid || skill.pristine" class="alert alert-danger"> skill is required </div> </div> <button type="submit" class="btn btn-success" [disabled]="!actorForm.form.valid">Submit</button> <button type="button" class="btn btn-default" (click)="newActor(); actorForm.reset()">New Actor</button> <em>with</em> reset <button type="button" class="btn btn-default" (click)="newActor()">New Actor</button> <em>without</em> reset <!-- NOT SHOWN IN DOCS --> <div> <hr> Name via form.controls = {{ showFormControls(actorForm) }} </div> <!-- - --> </form> </div> <div [hidden]="!submitted"> <h2>You submitted the following:</h2> <div class="row"> <div class="col-xs-3">Name</div> <div class="col-xs-9">{{ model.name }}</div> </div> <div class="row"> <div class="col-xs-3">Studio</div> <div class="col-xs-9">{{ model.studio }}</div> </div> <div class="row"> <div class="col-xs-3">Skill</div> <div class="col-xs-9">{{ model.skill }}</div> </div> <br> <button type="button" class="btn btn-primary" (click)="submitted=false"> Edit </button> </div></div><!-- ==================================================== --> <div> <form> <!-- ... all of the form ... --> </form> </div><!-- ==================================================== --><hr><style> .no-style .ng-valid { border-left: 1px solid #CCC} .no-style .ng-invalid { border-left: 1px solid #CCC}</style><div class="no-style" style="margin-left: 4px"> <div class="container"> <h1>Actor 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="studio">Studio</label> <input type="text" class="form-control" id="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required> <option *ngFor="let skill of skills" [value]="skill">{{ skill }}</option> </select> </div> <button type="submit" class="btn btn-success">Submit</button> </form> </div> <!-- ==================================================== --> <hr> <div class="container"> <h1>Actor Form</h1> <form #actorForm="ngForm"> {{ model | json }} <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="studio">Studio</label> <input type="text" class="form-control" id="studio" [(ngModel)]="model.studio" name="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required [(ngModel)]="model.skill" name="skill"> <option *ngFor="let skill of skills" [value]="skill">{{ skill }}</option> </select> </div> <button type="submit" class="btn btn-success">Submit</button> </form> </div> <!-- EXTRA MATERIAL FOR DOCUMENTATION --> <hr> <input type="text" class="form-control" id="name" required [(ngModel)]="model.name" name="name"> TODO: remove this: {{ model.name}} <hr> <input type="text" class="form-control" id="name" required [ngModel]="model.name" name="name" (ngModelChange)="model.name = $event"> TODO: remove this: {{ model.name}}</div>
-
disabledプロパティをバインドする
テンプレート参照変数
#actorForm
を使用して、Submitボタンを含むフォームにアクセスし、イベントバインディングを作成します。フォームの全体的な有効性を示すプロパティを、Submitボタンの
disabled
プロパティにバインドします。src/app/actor-form/actor-form.component.html (submit-button)
<div class="container"> <div [hidden]="submitted"> <h1>Actor Form</h1> <form (ngSubmit)="onSubmit()" #actorForm="ngForm"> <div class="form-group"> <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> </div> <div class="form-group"> <label for="studio">Studio Affiliation</label> <input type="text" class="form-control" id="studio" [(ngModel)]="model.studio" name="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required [(ngModel)]="model.skill" name="skill" #skill="ngModel"> <option *ngFor="let skill of skills" [value]="skill">{{ skill }}</option> </select> <div [hidden]="skill.valid || skill.pristine" class="alert alert-danger"> skill is required </div> </div> <button type="submit" class="btn btn-success" [disabled]="!actorForm.form.valid">Submit</button> <button type="button" class="btn btn-default" (click)="newActor(); actorForm.reset()">New Actor</button> <em>with</em> reset <button type="button" class="btn btn-default" (click)="newActor()">New Actor</button> <em>without</em> reset <!-- NOT SHOWN IN DOCS --> <div> <hr> Name via form.controls = {{ showFormControls(actorForm) }} </div> <!-- - --> </form> </div> <div [hidden]="!submitted"> <h2>You submitted the following:</h2> <div class="row"> <div class="col-xs-3">Name</div> <div class="col-xs-9">{{ model.name }}</div> </div> <div class="row"> <div class="col-xs-3">Studio</div> <div class="col-xs-9">{{ model.studio }}</div> </div> <div class="row"> <div class="col-xs-3">Skill</div> <div class="col-xs-9">{{ model.skill }}</div> </div> <br> <button type="button" class="btn btn-primary" (click)="submitted=false"> Edit </button> </div></div><!-- ==================================================== --> <div> <form> <!-- ... all of the form ... --> </form> </div><!-- ==================================================== --><hr><style> .no-style .ng-valid { border-left: 1px solid #CCC} .no-style .ng-invalid { border-left: 1px solid #CCC}</style><div class="no-style" style="margin-left: 4px"> <div class="container"> <h1>Actor 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="studio">Studio</label> <input type="text" class="form-control" id="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required> <option *ngFor="let skill of skills" [value]="skill">{{ skill }}</option> </select> </div> <button type="submit" class="btn btn-success">Submit</button> </form> </div> <!-- ==================================================== --> <hr> <div class="container"> <h1>Actor Form</h1> <form #actorForm="ngForm"> {{ model | json }} <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="studio">Studio</label> <input type="text" class="form-control" id="studio" [(ngModel)]="model.studio" name="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required [(ngModel)]="model.skill" name="skill"> <option *ngFor="let skill of skills" [value]="skill">{{ skill }}</option> </select> </div> <button type="submit" class="btn btn-success">Submit</button> </form> </div> <!-- EXTRA MATERIAL FOR DOCUMENTATION --> <hr> <input type="text" class="form-control" id="name" required [(ngModel)]="model.name" name="name"> TODO: remove this: {{ model.name}} <hr> <input type="text" class="form-control" id="name" required [ngModel]="model.name" name="name" (ngModelChange)="model.name = $event"> TODO: remove this: {{ model.name}}</div>
-
アプリケーションを実行する
ボタンが有効になっていることに注意してください。まだ何も役に立つことはしていません。
-
名前の値を削除する
これは"必須"ルールに違反するため、エラーメッセージが表示されます。また、Submitボタンが無効になることにも注意してください。
ボタンの有効状態をフォームの有効性に明示的にワイヤリングする必要はありませんでした。 テンプレート参照変数を拡張されたフォーム要素に定義してから、ボタンコントロールでその変数を参照すると、
FormsModule
がこれを自動的に行いました。
フォーム送信に対応する
フォーム送信への応答を表示するには、データ入力領域を非表示にし、代わりに別のものを表示できます。
-
フォームをラップする
フォーム全体を
<div>
でラップし、そのhidden
プロパティをActorFormComponent.submitted
プロパティにバインドします。src/app/actor-form/actor-form.component.html (excerpt)
<div class="container"> <div [hidden]="submitted"> <h1>Actor Form</h1> <form (ngSubmit)="onSubmit()" #actorForm="ngForm"> <div class="form-group"> <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> </div> <div class="form-group"> <label for="studio">Studio Affiliation</label> <input type="text" class="form-control" id="studio" [(ngModel)]="model.studio" name="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required [(ngModel)]="model.skill" name="skill" #skill="ngModel"> <option *ngFor="let skill of skills" [value]="skill">{{ skill }}</option> </select> <div [hidden]="skill.valid || skill.pristine" class="alert alert-danger"> skill is required </div> </div> <button type="submit" class="btn btn-success" [disabled]="!actorForm.form.valid">Submit</button> <button type="button" class="btn btn-default" (click)="newActor(); actorForm.reset()">New Actor</button> <em>with</em> reset <button type="button" class="btn btn-default" (click)="newActor()">New Actor</button> <em>without</em> reset <!-- NOT SHOWN IN DOCS --> <div> <hr> Name via form.controls = {{ showFormControls(actorForm) }} </div> <!-- - --> </form> </div> <div [hidden]="!submitted"> <h2>You submitted the following:</h2> <div class="row"> <div class="col-xs-3">Name</div> <div class="col-xs-9">{{ model.name }}</div> </div> <div class="row"> <div class="col-xs-3">Studio</div> <div class="col-xs-9">{{ model.studio }}</div> </div> <div class="row"> <div class="col-xs-3">Skill</div> <div class="col-xs-9">{{ model.skill }}</div> </div> <br> <button type="button" class="btn btn-primary" (click)="submitted=false"> Edit </button> </div></div><!-- ==================================================== --> <div> <form> <!-- ... all of the form ... --> </form> </div><!-- ==================================================== --><hr><style> .no-style .ng-valid { border-left: 1px solid #CCC} .no-style .ng-invalid { border-left: 1px solid #CCC}</style><div class="no-style" style="margin-left: 4px"> <div class="container"> <h1>Actor 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="studio">Studio</label> <input type="text" class="form-control" id="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required> <option *ngFor="let skill of skills" [value]="skill">{{ skill }}</option> </select> </div> <button type="submit" class="btn btn-success">Submit</button> </form> </div> <!-- ==================================================== --> <hr> <div class="container"> <h1>Actor Form</h1> <form #actorForm="ngForm"> {{ model | json }} <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="studio">Studio</label> <input type="text" class="form-control" id="studio" [(ngModel)]="model.studio" name="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required [(ngModel)]="model.skill" name="skill"> <option *ngFor="let skill of skills" [value]="skill">{{ skill }}</option> </select> </div> <button type="submit" class="btn btn-success">Submit</button> </form> </div> <!-- EXTRA MATERIAL FOR DOCUMENTATION --> <hr> <input type="text" class="form-control" id="name" required [(ngModel)]="model.name" name="name"> TODO: remove this: {{ model.name}} <hr> <input type="text" class="form-control" id="name" required [ngModel]="model.name" name="name" (ngModelChange)="model.name = $event"> TODO: remove this: {{ model.name}}</div>
メインフォームは、
submitted
プロパティがフォームを送信するまでは偽であるため、最初から表示されます。これは、ActorFormComponent
からの次のフラグメントで示されています。src/app/actor-form/actor-form.component.ts (submitted)
import {Component} from '@angular/core';import {Actor} from '../actor';@Component({ selector: 'app-actor-form', templateUrl: './actor-form.component.html', standalone: false,})export class ActorFormComponent { skills = ['Method Acting', 'Singing', 'Dancing', 'Swordfighting']; model = new Actor(18, 'Tom Cruise', this.skills[3], 'CW Productions'); submitted = false; onSubmit() { this.submitted = true; } newActor() { this.model = new Actor(42, '', ''); } heroine(): Actor { const myActress = new Actor(42, 'Marilyn Monroe', 'Singing'); console.log('My actress is called ' + myActress.name); // "My actress is called Marilyn" return myActress; } //////// NOT SHOWN IN DOCS //////// // Reveal in html: // Name via form.controls = {{showFormControls(actorForm)}} showFormControls(form: any) { return form && form.controls.name && form.controls.name.value; // Tom Cruise } /////////////////////////////}
Submitボタンをクリックすると、
submitted
フラグが真になり、フォームが消えます。 -
送信された状態を追加する
フォームが送信された状態の間に別のものを表示するには、新しい
<div>
ラッパーの下に次のHTMLを追加します。src/app/actor-form/actor-form.component.html (excerpt)
<div class="container"> <div [hidden]="submitted"> <h1>Actor Form</h1> <form (ngSubmit)="onSubmit()" #actorForm="ngForm"> <div class="form-group"> <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> </div> <div class="form-group"> <label for="studio">Studio Affiliation</label> <input type="text" class="form-control" id="studio" [(ngModel)]="model.studio" name="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required [(ngModel)]="model.skill" name="skill" #skill="ngModel"> <option *ngFor="let skill of skills" [value]="skill">{{ skill }}</option> </select> <div [hidden]="skill.valid || skill.pristine" class="alert alert-danger"> skill is required </div> </div> <button type="submit" class="btn btn-success" [disabled]="!actorForm.form.valid">Submit</button> <button type="button" class="btn btn-default" (click)="newActor(); actorForm.reset()">New Actor</button> <em>with</em> reset <button type="button" class="btn btn-default" (click)="newActor()">New Actor</button> <em>without</em> reset <!-- NOT SHOWN IN DOCS --> <div> <hr> Name via form.controls = {{ showFormControls(actorForm) }} </div> <!-- - --> </form> </div> <div [hidden]="!submitted"> <h2>You submitted the following:</h2> <div class="row"> <div class="col-xs-3">Name</div> <div class="col-xs-9">{{ model.name }}</div> </div> <div class="row"> <div class="col-xs-3">Studio</div> <div class="col-xs-9">{{ model.studio }}</div> </div> <div class="row"> <div class="col-xs-3">Skill</div> <div class="col-xs-9">{{ model.skill }}</div> </div> <br> <button type="button" class="btn btn-primary" (click)="submitted=false"> Edit </button> </div></div><!-- ==================================================== --> <div> <form> <!-- ... all of the form ... --> </form> </div><!-- ==================================================== --><hr><style> .no-style .ng-valid { border-left: 1px solid #CCC} .no-style .ng-invalid { border-left: 1px solid #CCC}</style><div class="no-style" style="margin-left: 4px"> <div class="container"> <h1>Actor 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="studio">Studio</label> <input type="text" class="form-control" id="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required> <option *ngFor="let skill of skills" [value]="skill">{{ skill }}</option> </select> </div> <button type="submit" class="btn btn-success">Submit</button> </form> </div> <!-- ==================================================== --> <hr> <div class="container"> <h1>Actor Form</h1> <form #actorForm="ngForm"> {{ model | json }} <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="studio">Studio</label> <input type="text" class="form-control" id="studio" [(ngModel)]="model.studio" name="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required [(ngModel)]="model.skill" name="skill"> <option *ngFor="let skill of skills" [value]="skill">{{ skill }}</option> </select> </div> <button type="submit" class="btn btn-success">Submit</button> </form> </div> <!-- EXTRA MATERIAL FOR DOCUMENTATION --> <hr> <input type="text" class="form-control" id="name" required [(ngModel)]="model.name" name="name"> TODO: remove this: {{ model.name}} <hr> <input type="text" class="form-control" id="name" required [ngModel]="model.name" name="name" (ngModelChange)="model.name = $event"> TODO: remove this: {{ model.name}}</div>
この
<div>
は、補間バインディングで読み取り専用の俳優を表示します。これは、コンポーネントが送信された状態の間にのみ表示されます。代替表示には、_編集_ボタンが含まれます。このボタンのクリックイベントは、
submitted
フラグをクリアする式にバインドされています。 -
編集ボタンをテストする
編集ボタンをクリックして、表示を編集可能なフォームに戻します。
まとめ
このページで説明したAngularフォームは、データの修正や検証などをサポートするために、 次のフレームワーク機能を活用しています。
- Angular HTMLフォームテンプレート
@Component
デコレーターを含むフォームコンポーネントクラスNgForm.ngSubmit
イベントプロパティにバインドすることで、フォーム送信を処理する#actorForm
や#name
などのテンプレート参照変数- 双方向データバインディングのための
[(ngModel)]
構文 - 検証とフォーム要素の変更追跡のための
name
属性の使用 - 入力コントロールの参照変数の
valid
プロパティは、コントロールが有効であるか、エラーメッセージを表示する必要があるかを示します NgForm
の有効性にバインドすることで、Submitボタンの有効状態を制御する- 有効でないコントロールについてユーザーに視覚的なフィードバックを提供するカスタムCSSクラス
アプリケーションの最終バージョンを示すコードを次に示します。
actor-form/actor-form.component.ts
import {Component} from '@angular/core';import {Actor} from '../actor';@Component({ selector: 'app-actor-form', templateUrl: './actor-form.component.html', standalone: false,})export class ActorFormComponent { skills = ['Method Acting', 'Singing', 'Dancing', 'Swordfighting']; model = new Actor(18, 'Tom Cruise', this.skills[3], 'CW Productions'); submitted = false; onSubmit() { this.submitted = true; } newActor() { this.model = new Actor(42, '', ''); } heroine(): Actor { const myActress = new Actor(42, 'Marilyn Monroe', 'Singing'); console.log('My actress is called ' + myActress.name); // "My actress is called Marilyn" return myActress; } //////// NOT SHOWN IN DOCS //////// // Reveal in html: // Name via form.controls = {{showFormControls(actorForm)}} showFormControls(form: any) { return form && form.controls.name && form.controls.name.value; // Tom Cruise } /////////////////////////////}
actor-form/actor-form.component.html
<div class="container"> <div [hidden]="submitted"> <h1>Actor Form</h1> <form (ngSubmit)="onSubmit()" #actorForm="ngForm"> <div class="form-group"> <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> </div> <div class="form-group"> <label for="studio">Studio Affiliation</label> <input type="text" class="form-control" id="studio" [(ngModel)]="model.studio" name="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required [(ngModel)]="model.skill" name="skill" #skill="ngModel"> <option *ngFor="let skill of skills" [value]="skill">{{ skill }}</option> </select> <div [hidden]="skill.valid || skill.pristine" class="alert alert-danger"> skill is required </div> </div> <button type="submit" class="btn btn-success" [disabled]="!actorForm.form.valid">Submit</button> <button type="button" class="btn btn-default" (click)="newActor(); actorForm.reset()">New Actor</button> <em>with</em> reset <button type="button" class="btn btn-default" (click)="newActor()">New Actor</button> <em>without</em> reset <!-- NOT SHOWN IN DOCS --> <div> <hr> Name via form.controls = {{ showFormControls(actorForm) }} </div> <!-- - --> </form> </div> <div [hidden]="!submitted"> <h2>You submitted the following:</h2> <div class="row"> <div class="col-xs-3">Name</div> <div class="col-xs-9">{{ model.name }}</div> </div> <div class="row"> <div class="col-xs-3">Studio</div> <div class="col-xs-9">{{ model.studio }}</div> </div> <div class="row"> <div class="col-xs-3">Skill</div> <div class="col-xs-9">{{ model.skill }}</div> </div> <br> <button type="button" class="btn btn-primary" (click)="submitted=false"> Edit </button> </div></div><!-- ==================================================== --> <div> <form> <!-- ... all of the form ... --> </form> </div><!-- ==================================================== --><hr><style> .no-style .ng-valid { border-left: 1px solid #CCC} .no-style .ng-invalid { border-left: 1px solid #CCC}</style><div class="no-style" style="margin-left: 4px"> <div class="container"> <h1>Actor 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="studio">Studio</label> <input type="text" class="form-control" id="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required> <option *ngFor="let skill of skills" [value]="skill">{{ skill }}</option> </select> </div> <button type="submit" class="btn btn-success">Submit</button> </form> </div> <!-- ==================================================== --> <hr> <div class="container"> <h1>Actor Form</h1> <form #actorForm="ngForm"> {{ model | json }} <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="studio">Studio</label> <input type="text" class="form-control" id="studio" [(ngModel)]="model.studio" name="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required [(ngModel)]="model.skill" name="skill"> <option *ngFor="let skill of skills" [value]="skill">{{ skill }}</option> </select> </div> <button type="submit" class="btn btn-success">Submit</button> </form> </div> <!-- EXTRA MATERIAL FOR DOCUMENTATION --> <hr> <input type="text" class="form-control" id="name" required [(ngModel)]="model.name" name="name"> TODO: remove this: {{ model.name}} <hr> <input type="text" class="form-control" id="name" required [ngModel]="model.name" name="name" (ngModelChange)="model.name = $event"> TODO: remove this: {{ model.name}}</div>
actor.ts
export class Actor { constructor( public id: number, public name: string, public skill: string, public studio?: string, ) {}}
app.module.ts
import {CommonModule} from '@angular/common';import {NgModule} from '@angular/core';import {FormsModule} from '@angular/forms';import {BrowserModule} from '@angular/platform-browser';import {AppComponent} from './app.component';import {ActorFormComponent} from './actor-form/actor-form.component';@NgModule({ imports: [BrowserModule, CommonModule, FormsModule], declarations: [AppComponent, ActorFormComponent], providers: [], bootstrap: [AppComponent],})export class AppModule {}
app.component.html
<app-actor-form></app-actor-form>
app.component.ts
import {Component} from '@angular/core';@Component({ selector: 'app-root', templateUrl: './app.component.html', standalone: false,})export class AppComponent {}
main.ts
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';import {AppModule} from './app/app.module';platformBrowserDynamic() .bootstrapModule(AppModule) .catch((err) => console.error(err));
forms.css
.ng-valid[required], .ng-valid.required { border-left: 5px solid #42A948; /* green */}.ng-invalid:not(form) { border-left: 5px solid #a94442; /* red */}