[angular2]表單的操作和驗證template driven and model driven
前言
在angular裡面,google提供了兩種表單的操作和驗證方式,一種是類似angularjs的方式,稱之為template driven,另一種則是用ts來定義大部份表單的行為,叫做model driven,這篇則是來紀錄一下兩種的語法,為何要記錄呢?我只是希望要有一篇很像是cheat sheet的方式,所以不會想要介紹太多,如果想要學習理解的話,可以直接參考官網就好了,Validation。
導覽
在網路上有關於template driven的寫法有很多種,我只記錄一下我個人覺得比較好的寫法,用一個(#employeeName)template reference來代表要驗證的名稱,而html的name就等於我們binding的欄位,所以實際上當我們判斷error的時候,用的是template reference來做的,不是用html的name哦,而form1則是代表這整個表單的狀態,是否sumbit過或是否驗證過
<div>
<form #form1="ngForm" (ngSubmit)="submit(form1)">
<div>
<label for="employeeName">employee name</label>
<input id="employeeName" type="text" name="employeeName" ngModel #employeeName="ngModel" required/>
<span *ngIf="employeeName.errors?.required && form1.submitted">employee name is required</span>
</div>
<div>
<label for="companyAddress">company address</label>
<input id="companyAddress" type="text" name="companyAddress" ngModel #companyAddress="ngModel" required/>
<span *ngIf="companyAddress.errors?.required && form1.submitted">company address is required</span>
</div>
<div>
<input type="submit" value="submit" [disabled]="form1.invalid" />
</div>
</form>
</div>
import { Component } from '@angular/core';
import { NgForm } from "@angular/forms";
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
submit(form1: NgForm) {
console.log(form1);
}
}
如果我們需要把employee name放進employee的物件,company name放到company的物件,可以使用ngModelGroup的方式,然後如果在ts裡面想要直接參考到template reference的話,可以用ViewChild
<div>
<form #form1="ngForm" (ngSubmit)="submit()">
<div ngModelGroup="employee">
<label for="employeeName">employee name</label>
<input id="employeeName" type="text" name="name" #employeeName="ngModel" ngModel required/>
<span *ngIf="employeeName?.errors?.required">employee name is required</span>
</div>
<div ngModelGroup="company">
<label for="companyAddress">company address</label>
<input id="companyAddress" type="text" name="address" ngModel #companyAddress="ngModel" required/>
<span *ngIf="companyAddress.errors?.required">company address is required</span>
</div>
<div>
<input type="submit" value="submit" />
</div>
</form>
</div>
import { Component, ViewChild } from '@angular/core';
import { NgForm } from "@angular/forms";
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
@ViewChild('form1') form1: NgForm;
submit() {
console.log(this.form1);
}
}
也就是驗證的部份,還有很多關於表單定義的部份,改成在ts裡面定義,首先需要在app.module.ts裡面,import需要用到的module
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';
import { AppComponent } from './app.component';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
FormsModule,
HttpModule,
ReactiveFormsModule //model driven用到的module
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
下面則是model driven的寫法
<div>
<form [formGroup]="user" (ngSubmit)="submit()">
<div>
<label for="employeeName">employee name</label>
<input id="employeeName" type="text" formControlName="name"/>
<span *ngIf="user.get('name').hasError('required')">employee name is required</span>
</div>
<div>
<label for="companyAddress">company address</label>
<input id="companyAddress" type="text" formControlName="address"/>
<span *ngIf="user.get('address').hasError('required')">company address is required</span>
</div>
<div>
<input type="submit" value="submit" />
</div>
</form>
</div>
import { Component, ViewChild } from '@angular/core';
import { NgForm, FormGroup, FormControl, Validators } from "@angular/forms";
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
user: FormGroup;
constructor() {
this.user = new FormGroup({
name: new FormControl('',Validators.required),
address: new FormControl('',Validators.required)
});
}
submit(){
console.log(this.user);
}
}
如果要把name和address改成兩個物件的話
<div>
<form [formGroup]="user" (ngSubmit)="submit()">
<div>
<label for="employeeName">employee name</label>
<input id="employeeName" type="text" formControlName="name"/>
<span *ngIf="user.get('name').hasError('required')">employee name is required</span>
</div>
<div formGroupName="company">
<label for="companyAddress">company address</label>
<input id="companyAddress" type="text" formControlName="address"/>
<span *ngIf="user.get('company').get('address').hasError('required')">company address is required</span>
</div>
<div>
<input type="submit" value="submit" />
</div>
</form>
</div>
import { Component, ViewChild } from '@angular/core';
import { NgForm, FormGroup, FormControl, Validators } from "@angular/forms";
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
user: FormGroup;
constructor() {
this.user = new FormGroup({
name: new FormControl('', Validators.required),
company: new FormGroup({
address: new FormControl('', Validators.required)
})
});
}
submit() {
console.log(this.user);
}
}
另一種使用FormBuilder的寫法,template寫法不變
import { Component, ViewChild } from '@angular/core';
import { NgForm, FormGroup, FormControl, Validators, FormBuilder } from "@angular/forms";
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
user: FormGroup;
constructor(private fb: FormBuilder) {
this.user = this.fb.group({
name: ['', Validators.required],
company: this.fb.group({
address: ['', Validators.required]
})
});
}
submit() {
console.log(this.user);
}
}
其實寫法有很多種,我只是記錄一下自己比較會用到也覺得比較好的寫法,此篇文章主要對我來說就像cheat sheet的樣子,所以也不想解釋太多,如果想看很多解釋才能理解的話,直接去看官網吧,如果有更好的寫法建議,也請提供給筆者。