top
Loading...
Angular 2 表單

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.sharebody.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" 表示我們可以通過一個 <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="alterEgo">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>
  • 每一個 input 元素都有一個 id 屬性,它被 label 元素的 for 屬性用來把標籤匹配到對應的 input 。

  • 每一個 input 元素都有一個 name 屬性, Angular 的表單模塊需要使用它為表單注冊控製器。

運行以上實例輸出結果如下:

{{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; /* green */ } .ng-invalid:not(form) { border-left: 5px solid #a94442; /* red */ }

打開 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"字段錯誤信息的可見性了。

添加一個網站

接下來我們創建一個用於添加網站的表單,在 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.sharebody.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); } 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 如下:

北斗有巢氏 有巢氏北斗