本章節我們将為大家介紹如何使用元件和模闆建構一個 Angular 表單。
利用 Angular 模闆,我們可以建立各種類型表單,例如:登入表單,聯系人表單,商品詳情表單等,而且我們也為這些表單的字段添加資料校驗。
接下來我們一步步來實作表單的功能。
導入初始化項目。
完整的項目建立可以參考:Angular 2 TypeScript 環境配置
或者直接下載下傳源代碼:點我下載下傳
解壓後,修改目錄名為angular-forms,修改 angular-forms/package.json 檔案中的 <b>"name": "angular-quickstart"</b> 為 <b>"name": "angular-forms"</b>。
完成後,我們執行 <b>cnpm install</b> 來載入依賴包。
以下建立了一個簡單的模型類 Site,包含了三個必需字段:id,name,url,一個可選字段:alexa。
在 angular-forms/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 檔案,代碼如下:
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.runoob.com', 'www.google.com',
'www.taobao.com', 'www.facebook.com'];
model = new Site(1, '菜鳥教程', this.urls[0], 10000);
submitted = false;
onSubmit() { this.submitted = true; }
// TODO: 完成後移除
get diagnostic() { return JSON.stringify(this.model); }
執行個體中導入了 Component 裝飾器和 Site 模型。
@Component 選擇器 "site-form" 表示我們可以通過一個 <b><site-form></b> 标簽,把此表單扔進父模闆中。
templateUrl 屬性指向一個獨立的HTML模闆檔案,名叫 site-form.component.html。
diagnostic 屬性用于傳回這個模型的JSON形式。
修改 app.module.ts 來定義應用的根子產品,子產品中指定了引用到的外部及聲明屬于本子產品中的元件,比如 SiteFormComponent。
因為模闆驅動的表單有它們自己的子產品,是以我們得把 FormsModule 添加到本應用的 imports 數組中,這樣我們才能使用表單。
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 放在其中。
selector: 'my-app',
template: '<site-form></site-form>'
export class AppComponent { }
建立模闆檔案 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>
<label for="alexa">alexa 排名</label>
<input type="text" class="form-control" id="alexa">
<button type="submit" class="btn btn-default">送出</button>
</form>
required 屬性設定的該字段為必需字段,如果沒有設定則是可選。
在 angular-forms 目錄下輸入以下指令:
打開 index.html 檔案,把以下樣式連結添加到 <head> 中:
<link rel="stylesheet" href="node_modules/bootstrap/dist/css/bootstrap.min.css">
執行 <b>npm start</b> 後,通路:http://localhost:3000/,輸出效果如下:

接下來我們使用 ngModel 進行雙向資料綁定,通過監聽 DOM 事件,來實作更新元件的屬性。
修改 app/site-form.component.html ,使用 ngModel 把我們的表單綁定到模型。代碼如下所示:
{{diagnostic}}
<input type="text" class="form-control" id="name"
required
[(ngModel)]="model.name" name="name">
<input type="text" class="form-control" id="alexa"
[(ngModel)]="model.alexa" name="alexa">
<label for="url">網站 URL </label>
<select class="form-control" id="url"
[(ngModel)]="model.url" name="url">
<option *ngFor="let p of urls" [value]="p">{{p}}</option>
</select>
每一個 input 元素都有一個 id 屬性,它被 label 元素的 for 屬性用來把标簽比對到對應的 input 。
每一個 input 元素都有一個 name 屬性, Angular 的表單子產品需要使用它為表單注冊控制器。
運作以上執行個體輸出結果如下:
<b>{{diagnostic}} </b> 隻是用于測試時候輸出資料使用。
我們還可以通過 ngModel 跟蹤修改狀态與有效性驗證,它使用了三個 CSS 類來更新控件,以便反映目前狀态。
狀态
為 true 時的類
為 false 時的類
控件已經被通路過
<code>ng-touched</code>
<code>ng-untouched</code>
控件值已經變化
<code>ng-dirty</code>
<code>ng-pristine</code>
控件值是有效的
<code>ng-valid</code>
<code>ng-invalid</code>
這樣我們就可以添加自定義 CSS 來反應表單的狀态。
在 angular-forms 目錄下建立 forms.css 檔案,代碼如下:
.ng-valid[required], .ng-valid.required {
border-left: 5px solid #42A948; /* green */
.ng-invalid:not(form) {
border-left: 5px solid #a94442; /* red */
<link rel="stylesheet" href="forms.css">
修改 app/site-form.component.html ,代碼如下所示:
[(ngModel)]="model.name" name="name"
#name="ngModel" >
<div [hidden]="name.valid || name.pristine"
class="alert alert-danger">
網站名是必需的
模闆中通過把 div 元素的 hidden 屬性綁定到 name 控件的屬性,我們就可以控制"name"字段錯誤資訊的可見性了。
删除掉 name 字段的資料,顯示結果如下所示:
接下來我們建立一個用于添加網站的表單,在 app/site-form.component.html 添加一個按鈕:
<button type="button" class="btn btn-default" (click)="newSite()">添加網站</button>
将以上按鈕事件綁定到元件方法上:
active = true;
newSite() {
this.model = new Site(5, '', '');
this.active = false;
setTimeout(() => this.active = true, 0);
我們給元件添加一個 active 标記,把它初始化為 true 。當我們添加一個新的網站時,它把 active 标記設定為 false , 然後通過一個快速的 setTimeout 函數迅速把它設定回 true 。
我們可以使用 Angular 的指令 NgSubmit 來送出表單, 并且通過事件綁定機制把它綁定到 SiteFormComponent.submit() 方法上。
<form *ngIf="active" (ngSubmit)="onSubmit()" #siteForm="ngForm">
我們定義了一個模闆引用變量 #siteForm ,并且把它初始化為 "ngForm" 。
這個 siteForm 變量現在引用的是 NgForm 指令,它代表的是表單的整體。
site-form.component.ts 檔案完整代碼如下:
app/site-form.component.html 完整代碼如下:
<div [hidden]="submitted">
<button type="submit" class="btn btn-default" [disabled]="!siteForm.form.valid">送出</button>
<button type="button" class="btn btn-default" (click)="newSite()">新增網站</button>
<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 class="col-xs-3">網站 alexa 排名</div>
<div class="col-xs-9 pull-left">{{ model.alexa }}</div>
<div class="col-xs-3">網站 URL </div>
<div class="col-xs-9 pull-left">{{ model.url }}</div>
<br>
<button class="btn btn-default" (click)="submitted=false">編輯</button>
模闆中我們把 hidden 屬性綁定到 SiteFormComponent.submitted 屬性上。
主表單從一開始就是可見的,因為 submitted 屬性是 false ,當我們送出了這個表單則隐藏,submitted 屬性是 true:
最終的目錄結構為:
本文所使用的源碼可以通過以下方式下載下傳,不包含 node_modules 和 typings 目錄。
源代碼下載下傳
完整執行個體示範 GIf 如下: