[angular2]表單的操作和驗證template driven and model driven

[angular2]表單的操作和驗證template driven and model driven

前言

在angular裡面,google提供了兩種表單的操作和驗證方式,一種是類似angularjs的方式,稱之為template driven,另一種則是用ts來定義大部份表單的行為,叫做model driven,這篇則是來紀錄一下兩種的語法,為何要記錄呢?我只是希望要有一篇很像是cheat sheet的方式,所以不會想要介紹太多,如果想要學習理解的話,可以直接參考官網就好了,Validation。

導覽

  1. template driven
  2. model driven(reactive form)
  3. 結論

template driven

在網路上有關於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);
  }
}

model driven(reactive form)

也就是驗證的部份,還有很多關於表單定義的部份,改成在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的樣子,所以也不想解釋太多,如果想看很多解釋才能理解的話,直接去看官網吧,如果有更好的寫法建議,也請提供給筆者。