概要
AngularのFormの書き方は主に2つあります。
1つはTemplate Drivenなやり方。
もう1つはModel Driven(Reactive Form)なやり方。
フォームの作り方を調べた時にどっちがどっちの情報なのか分からず混乱したのでまとめてみました。
今回はTemplate Drivenの方を紹介します。
環境
- angular-cli 1.0.0-beta.25.5
- Angular 2.4.3
完成品
今回の成果物はこちら
書き方
Submitボタンを押したらconsole.log()に吐くようなフォームを作ってみます。
template.component.html
<form #f="ngForm"> <label>Firstname:</label> <input type="text" name="first" ngModel> <label>Lastname:</label> <input type="text" name="last" ngModel> <button type="submit" (click)="loginForm(f.value)">Submit</button> <div> <span>{{ f.value | json }}</span> </div> </form>
ポイント
#f="ngForm"
でフォームの値を変数として保持する- ↑の変数に値を保持させるために、
input
の中でname
とngModel
をつける。f
の各フィールド名はname
として登録される f.value
で全フィールドを見ることができる- 変数をView(HTML)からModel(Component)に渡すため、関数の引数に
f.value
を渡す
template.component.ts
import { Component, OnInit } from '@angular/core'; @Component({ selector: 'app-template', templateUrl: './template.component.html', styleUrls: ['./template.component.css'] }) export class TemplateComponent implements OnInit { constructor() { } ngOnInit() { } loginForm(value: any) { console.log(value); } }
今回の書き方だと特に必要な対応はないです。
app.component.html
<h1> {{title}} </h1> <app-template></app-template>
ポイント
<app-template></app-template>
を追記
app.module.ts
import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { FormsModule } from '@angular/forms'; // here import { HttpModule } from '@angular/http'; import { AppComponent } from './app.component'; import { TemplateComponent } from './template/template.component'; @NgModule({ declarations: [ AppComponent, TemplateComponent ], imports: [ BrowserModule, FormsModule, // here HttpModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }
ポイント
FormsModule
をimportします。
動作確認
文字を入力してみます。
Viewで設定していた
<div> <span>{{ f.value | json }}</span> </div>
によって、f.value
の値が即時反映されています。注意なのはsubmitを押すまではModelには渡されないところです。
submitで関数の引数に渡されて初めてModelで処理することができます。
ngModelの書き方の違い
今回はngModel
だけを書いていたのですが、調べてみると分かるようにngModelの書き方は
- ngModel
- [ngModel]
- [(ngModel)]
と複数あります。これらの違いを説明していきます。
ngModel
<form #f="ngForm"> ... <input type="text" name="name" ngModel> ... <button type="submit" (click)="loginForm(f.value)">Submit</button> </form>
これは先程説明したように、入力した文字列がf.value
に入ります。
ただし、Component側には行かないので関数の引数にf
を渡す必要があります。
[ngModel]
Model -> Viewへの単方向バインディングのやり方です。
<form #f="ngForm"> ... <input type="text" name="name" [ngModel]="user.name"> ... <button type="submit" (click)="loginForm(f.value)">Submit</button> </form>
これはComponent側(Model側)のデータが初期値として入ります。
ただし、変更してもf.value
は変わりますが、Component内のデータuser
は変わりません。
なのでComponent側に渡したければ関数の引数として渡す必要があります。
「Component側(Model側)のデータが初期値として入ります」といったように、この書き方の場合はまずComponent側に以下のように変数を用意する必要があります。
class User { first: string; last: string; } @Component({ selector: 'app-template-2', templateUrl: './template-2.component.html', styleUrls: ['./template-2.component.css'] }) export class Template2Component implements OnInit { public user: User; // here constructor() { } ngOnInit() { this.user = new User(); } loginForm(value: any) { console.log(value); } }
動作確認をしてみます。
入力してみると
f.value
は変わっていますが、Model側のuser
は変わらないことがわかります。
[(ngModel)]
Model <-> Viewの双方向バインディングのやり方です。
<form #f="ngForm"> ... <input type="text" name="name" [(ngModel)]="user.name"> ... <button type="submit" (click)="loginForm()">Submit</button> </form>
これはComponent側(Model側)のデータが初期値としてf.value
に入ります。
また変更すれば即時にComponent側のデータが変更されます。
なので関数の引数として渡す必要がありません。
Component側は先程の[ngModel]と変わりません。loginForm()
の引数を削ればOKです。
動作確認をすると
入力してみると
f.value
もuser
も変わっています。
このようにModel側に即座にデータがバインドされるので、関数の引数として渡す必要がありません。