Angular 2 表單
本章節我們將為大家介紹如何使用組件和範本構建一個 Angular 表單。
利用 Angular 範本,我們可以創建各種類型表單,例如:登錄表單,聯繫人表單,商品詳情表單等,而且我們也為這些表單的字段添加數據校驗。
接下來我們一步步來實現表單的功能。
創建專案
導入初始化專案。
完整的專案創建可以參考:Angular 2 TypeScript 環境配置
或者直接下載源代碼:點我下載
解壓後,修改目錄名為angular-forms,修改 angular-forms/package.json 檔中的 "name": "angular-quickstart" 為 "name": "angular-forms"。
完成後,我們執行 cnpm install 來載入依賴包。
創建 Site 模型
以下創建了一個簡單的模型類 Site,包含了三個必需字段:id,name,url,一個可選字段:alexa。
在 angular-forms/app 目錄下創建 site.ts 檔,代碼如下:
app/site.ts 檔:
export class Site {
constructor(
public id: number,
public name: string,
public url: string,
public alexa?: number
) { }
}
以下代碼中,標為 public 的為公有字段,alexa 後添加一個問號(?)表示可選字段。
創建一個表單組件
每個 Angular 表單分為兩部分:一個基於 HTML 的範本,和一個基於代碼的組件,它用來處理數據和用戶交互。
在 angular-forms/app 目錄下創建 site-form.component.ts 檔,代碼如下:
app/site-form.component.ts 檔:
import { Component } from '@angular/core';
import { Site } from './site';
@Component({
moduleId: module.id,
selector: 'site-form',
templateUrl: 'site-form.component.html'
})
export class SiteFormComponent {
urls = ['www.xuhuhu.com', 'www.google.com',
'www.taobao.com', 'www.facebook.com'];
model = new Site(1, 'IT研修', this.urls[0], 10000);
submitted = false;
onSubmit() { this.submitted = true; }
get diagnostic() { return JSON.stringify(this.model); }
}
實例中導入了 Component 裝飾器和 Site 模型。
@Component 選擇器 "site-form" 表示我們可以通過一個 <site-form> 標籤,把此表單扔進父範本中。
templateUrl 屬性指向一個獨立的HTML範本檔,名叫 site-form.component.html。
diagnostic 屬性用於返回這個模型的JSON形式。
定義應用的根模組
修改 app.module.ts 來定義應用的根模組,模組中指定了引用到的外部及聲明屬於本模組中的組件,比如 SiteFormComponent。
因為範本驅動的表單有它們自己的模組,所以我們得把 FormsModule 添加到本應用的 imports 數組中,這樣我們才能使用表單。
app/app.module.ts 檔代碼如下
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 { SiteFormComponent } from './site-form.component';
@NgModule({
imports: [
BrowserModule,
FormsModule
],
declarations: [
AppComponent,
SiteFormComponent
],
bootstrap: [ AppComponent ]
})
export class AppModule { }
創建根組件
修改根組件檔 app.component.ts,將 SiteFormComponent 放在其中。
app/app.component.ts 檔:
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
template: '<site-form></site-form>'
})
export class AppComponent { }
創建一個初始 HTML 表單範本
創建範本檔 site-form.component.html ,代碼如下所示:
app/site-form.component.html 檔:
<div class="container">
<h1>網站表單</h1>
<form>
<div class="form-group">
<label for="name">網站名</label>
<input type="text" class="form-control" id="name" required>
</div>
<div class="form-group">
<label for="alexa">alexa 排名</label>
<input type="text" class="form-control" id="alexa">
</div>
<button type="submit" class="btn btn-default">提交</button>
</form>
</div>
required 屬性設置的該字段為必需字段,如果沒有設置則是可選。
在 angular-forms 目錄下輸入以下命令:
cnpm install bootstrap --save
打開 index.html 檔,把以下樣式鏈接添加到 <head> 中:
<link rel="stylesheet" href="node_modules/bootstrap/dist/css/bootstrap.min.css">
執行 npm start 後,訪問:http://localhost:3000/,輸出效果如下:

使用 ngModel 進行雙向數據綁定
接下來我們使用 ngModel 進行雙向數據綁定,通過監聽 DOM 事件,來實現更新組件的屬性。
修改 app/site-form.component.html ,使用 ngModel 把我們的表單綁定到模型。代碼如下所示:
app/site-form.component.html 檔:
<div class="container">
<h1>網站表單</h1>
<form>
{{diagnostic}}
<div class="form-group">
<label for="name">網站名</label>
<input type="text" class="form-control" id="name"
required
[(ngModel)]="model.name" name="name">
</div>
<div class="form-group">
<label for="alexa">alexa 排名</label>
<input type="text" class="form-control" id="alexa"
[(ngModel)]="model.alexa" name="alexa">
</div>
<div class="form-group">
<label for="url">網站 URL </label>
<select class="form-control" id="url"
required
[(ngModel)]="model.url" name="url">
<option *ngFor="let p of urls" [value]="p">{{p}}</option>
</select>
</div>
<button type="submit" class="btn btn-default">提交</button>
</form>
</div>
運行以上實例輸出結果如下:

{{diagnostic}} 只是用於測試時候輸出數據使用。
我們還可以通過 ngModel 跟蹤修改狀態與有效性驗證,它使用了三個 CSS 類來更新控件,以便反映當前狀態。
狀態
|
為 true 時的類
|
為 false 時的類
|
控件已經被訪問過
|
ng-touched
|
ng-untouched
|
控件值已經變化
|
ng-dirty
|
ng-pristine
|
控件值是有效的
|
ng-valid
|
ng-invalid
|
這樣我們就可以添加自定義 CSS 來反應表單的狀態。
在 angular-forms 目錄下創建 forms.css 檔,代碼如下:
forms.css 檔:
.ng-valid[required], .ng-valid.required {
border-left: 5px solid #42A948;
}
.ng-invalid:not(form) {
border-left: 5px solid #a94442;
}
打開 index.html 檔,把以下樣式鏈接添加到 <head> 中:
<link rel="stylesheet" href="forms.css">
修改 app/site-form.component.html ,代碼如下所示:
app/site-form.component.html 檔:
<div class="container">
<h1>網站表單</h1>
<form>
{{diagnostic}}
<div class="form-group">
<label for="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">
網站名是必需的
</div>
</div>
<div class="form-group">
<label for="alexa">alexa 排名</label>
<input type="text" class="form-control" id="alexa"
[(ngModel)]="model.alexa" name="alexa">
</div>
<div class="form-group">
<label for="url">網站 URL </label>
<select class="form-control" id="url"
required
[(ngModel)]="model.url" name="url">
<option *ngFor="let p of urls" [value]="p">{{p}}</option>
</select>
</div>
<button type="submit" class="btn btn-default">提交</button>
</form>
</div>
範本中通過把 div 元素的 hidden 屬性綁定到 name 控件的屬性,我們就可以控制"name"字段錯誤資訊的可見性了。
刪除掉 name 字段的數據,顯示結果如下所示:

添加一個網站
接下來我們創建一個用於添加網站的表單,在 app/site-form.component.html 添加一個按鈕:
app/site-form.component.html 檔:
<button type="button" class="btn btn-default" (click)="newSite()">添加網站</button>
將以上按鈕事件綁定到組件方法上:
app/site-form.component.ts 檔:
active = true;
newSite() {
this.model = new Site(5, '', '');
this.active = false;
setTimeout(() => this.active = true, 0);
}
我們給組件添加一個 active 標記,把它初始化為 true 。當我們添加一個新的網站時,它把 active 標記設置為 false , 然後通過一個快速的 setTimeout 函數迅速把它設置回 true 。
通過 ngSubmit 來提交表單
我們可以使用 Angular 的指令 NgSubmit 來提交表單, 並且通過事件綁定機制把它綁定到 SiteFormComponent.submit() 方法上。
<form *ngIf="active" (ngSubmit)="onSubmit()" #siteForm="ngForm">
我們定義了一個範本引用變數 #siteForm ,並且把它初始化為 "ngForm" 。
這個 siteForm 變數現在引用的是 NgForm 指令,它代表的是表單的整體。
site-form.component.ts 檔完整代碼如下:
app/site-form.component.ts 檔:
import { Component } from '@angular/core';
import { Site } from './site';
@Component({
moduleId: module.id,
selector: 'site-form',
templateUrl: 'site-form.component.html'
})
export class SiteFormComponent {
urls = ['www.xuhuhu.com', 'www.google.com',
'www.taobao.com', 'www.facebook.com'];
model = new Site(1, 'IT研修', this.urls[0], 10000);
submitted = false;
onSubmit() { this.submitted = true; }
get diagnostic() { return JSON.stringify(this.model); }
active = true;
newSite() {
this.model = new Site(5, '', '');
this.active = false;
setTimeout(() => this.active = true, 0);
}
}
app/site-form.component.html 完整代碼如下:
app/site-form.component.html 檔:
<div class="container">
<div [hidden]="submitted">
<h1>網站表單</h1>
<form *ngIf="active" (ngSubmit)="onSubmit()" #siteForm="ngForm">
{{diagnostic}}
<div class="form-group">
<label for="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">
網站名是必需的
</div>
</div>
<div class="form-group">
<label for="alexa">alexa 排名</label>
<input type="text" class="form-control" id="alexa"
[(ngModel)]="model.alexa" name="alexa">
</div>
<div class="form-group">
<label for="url">網站 URL </label>
<select class="form-control" id="url"
required
[(ngModel)]="model.url" name="url">
<option *ngFor="let p of urls" [value]="p">{{p}}</option>
</select>
</div>
<button type="submit" class="btn btn-default" [disabled]="!siteForm.form.valid">提交</button>
<button type="button" class="btn btn-default" (click)="newSite()">新增網站</button>
</form>
</div>
<div [hidden]="!submitted">
<h2>你提交的資訊如下:</h2>
<div class="row">
<div class="col-xs-3">網站名</div>
<div class="col-xs-9 pull-left">{{ model.name }}</div>
</div>
<div class="row">
<div class="col-xs-3">網站 alexa 排名</div>
<div class="col-xs-9 pull-left">{{ model.alexa }}</div>
</div>
<div class="row">
<div class="col-xs-3">網站 URL </div>
<div class="col-xs-9 pull-left">{{ model.url }}</div>
</div>
<br>
<button class="btn btn-default" (click)="submitted=false">編輯</button>
</div>
</div>
範本中我們把 hidden 屬性綁定到 SiteFormComponent.submitted 屬性上。
主表單從一開始就是可見的,因為 submitted 屬性是 false ,當我們提交了這個表單則隱藏,submitted 屬性是 true:
submitted = false;
onSubmit() { this.submitted = true; }
最終的目錄結構為:

本文所使用的源碼可以通過以下方式下載,不包含 node_modules 和 typings 目錄。
源代碼下載
完整實例演示 GIf 如下:
