亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > JavaScript > 正文

詳解Angular2表單-模板驅動的表單(Template-Driven Forms)

2019-11-19 15:54:12
字體:
來源:轉載
供稿:網友

在網頁開發中,表單估計是最常用的一個,同時也是最麻煩、最容易出問題的。在一個稍微復雜一點的應用中,我們除了用表單元素收集數據,還需要驗證,幾個數據之間可能還會相互關聯,然后根據不同的數據值調用不同的業務邏輯等。

使用Angular提供的數據綁定的功能,我們可以很容易就在組件中獲得用戶輸入的數據,Angular也提供了幾種驗證方式方便我們進行數據的校驗。但是,一些自定義的數據驗證、數據交互和業務邏輯還是需要自己處理。

在Angular2中,提供了2種表單實現方式,分別是'template-driven'(模板驅動的表單)和'model-driven'(模型驅動表單)。在這篇文章中,我們先來看看模板驅動的表單。顧名思義,模板驅動的表單就是大部分表單相關代碼都在模板里,通過在模板里面添加ngForm, ngModel和ngModelGroup等屬性來定義模板和驗證信息,以及它跟組件之間的數據交互。

實例

下圖是這篇文章使用的實例的界面:


它是一個用戶信息輸入的表單,包括4個字段,用戶名、電話、城市和街道,演示了如何使用表單,給各個字段添加驗證并顯示驗證結果,以及如何在組件中判斷是否出錯并獲取出錯信息。

項目源碼可以從github獲取,這個項目包含了幾個Angular2表單相關的實例,可以使用下面的命令獲取本文所對應的代碼:

git clone https://github.com/Mavlarn/angular2-forms-tutorial

然后進入項目目錄,運行下面的命令安裝依賴然后運行測試服務器:

cd angular2-forms-tutorialgit checkout template-driven # 檢出該文所使用的tagnpm installnpm start

該項目是基于之前的Angular2-basic模板,這個教程相關的代碼都在'template-forms'目錄里面。

引入FormsModule

首先,我們需要在app.module.ts里引入FormsModule。

import { FormsModule } from '@angular/forms';//省略其他@NgModule({ imports: [ BrowserModule, FormsModule ], //省略其他})

初始表單

然后,我們從一個基本的html表單開始:

<form> <label>姓名:</label> <input type="text"> <label>電話:</label> <input type="text"> <label>城市:</label> <input type="text"> <label>街道:</label> <input type="text"> <button type="submit">保存</button></form>

在實際的實例中,使用了bootstrap的表單樣式,一組輸入框應該是下面這個樣子,但是在本文中,為了節省頁面顯示的篇幅,我省略了div, form-group等,我們只需要關心如何在Angular2中使用模板驅動的表單。如果想查看完整的帶樣式的代碼,請查看源文件。

<div class="form-group">  <label class="col-sm-2 control-label">姓名:</label>  <div class="col-sm-10">    <input class="form-control" type="text">  </div></div>

ngForm

在上面的表單里,我們沒有使用Angular2的任何功能,如數據綁定,也沒有使用其他指令。但是,Angular2在<form>上實現了一個指令'ngForm',這樣,對于所有的html的form表單,都會使用ngForm組件去初始化該表單。

使用ngForm對象

接下來,我們需要在模板里面訪問這個ngForm的實例,這樣我們就能夠從這個實例里面獲取數據,或者獲取數據驗證狀態。
在Angular2里,都提供了一個模板引用變量的功能,通過#加變量實現。通過這個功能,我們可以在同一元素、兄弟元素或任何子元素中引用模板引用變量。這樣聽著還是不好理解,我們看一個例子:

<input #phone placeholder="phone number"><button (click)="callPhone(phone.value)">Call</button>

在這個例子中,我們通過#phone定義了一個變量,它所指的就是這個input元素,phone.value也就是這個輸入框輸入的值。

除了使用#,也可以使用ref-,例如ref-phone形式的定義跟#phone是一樣的。

我們可以對任何的DOM元素使用這種方式獲取當前引用,也可以對任何的Angular2的指令使用。在這個表單的例子中,我們這樣來獲取這個ngFrom的引用:

<form #userForm="ngForm">

其中'ngForm'就是當前這個指令,這樣在這個模板里面,我們可以用userForm獲得表單的所有數據。

提交表單

在html中,我們要提交一個form,會在form里寫一個action的屬性,然后,用一個類型為'submit'的按鈕來提交。但是,在Angular2中,我們需要使用ngSubmit事件:

<form #userForm="ngForm" (ngSubmit)="logForm(userForm)">  <button type="submit">保存</button></form>

這樣,當用戶點擊保存按鈕的時候,Angular2會使用自己的驗證機制,驗證所有的數據,然后在調用'logForm(userForm)'方法。

在我們的組件中,實現這個方法:

logForm(theForm: NgForm) {  console.log(theForm.value);  if (theForm.invalid) {    // handle error.  }}

在這個方法里,我們使用theForm.invalid就可以獲得這個表單是否驗證成功的狀態,也可以用'theForm.value'獲得所有的表單數據。在這里,我們把表單數據打印到控制臺來檢查數據。至于如何從這個表單引用中獲取控件數據和狀態,會在接下來再講。

使用ngModel綁定數據

接下來,我們需要綁定數據。假設我們的業務是打開這個頁面的時候獲取用戶數據,然后顯示到頁面表單上。我們在組件的構造方法中創建一個模擬的用戶數據:

export class TemplateFormsComponent {  user: any;  constructor() {    this.user = {      name: '張三',      mobile: 13800138001,      city: '北京',      street: '朝陽望京...'    };  }}

然后在模板中將這個組件中的數據綁定到模板頁面上:

<input type="text" name="name" [(ngModel)]="user.name"><input type="text" name="mobile" [ngModel]="user.mobile"><input type="text" name="city" [ngModel]="user.city"><input type="text" name="street" [ngModel]="user.street"><!-- 其他的輸入框都類似 -->

在這里,我們使用[(ngModel)]="user.name",這是雙向綁定的方式,這樣,當我們修改頁面上的數據的時候,在組件中也能獲得更新后的數據;同時,如果在組件中更新了數據,在頁面上也能更新。

為了演示這個雙向綁定跟單向綁定的區別,我們只對姓名使用雙向綁定,對其他的都是用單向綁定,也就是[ngModel]="user.mobile"。使用[]的單向綁定是從模板到組件的綁定,也就是頁面中的輸入的數據改變,組件中的數據也會改變。但是組件中的數據更新不會引起頁面上該數據的更新。

使用單向綁定可以減少數據的更新檢查,從來可以提高性能。

如果不需要數據的初始化,我們其實可以只用ngModel,例如:

<input type="text" name="city" ngModel>

這樣,我們在組件中創建的用戶數據就無法顯示到頁面上,但是,他還是能夠將頁面上輸入的數據綁定到組件中的數據上。

在Angular2中,使用ngModel結合name屬性來創建一個表單控件FormControls。例如上面的<input name="city" ngModel>就對應一個userForm里面的控件city。由于我們在提交方法里面將這個userForm作為參數傳到方法里,我們可以在方法里面獲得所有的表單控件theForm.controls,它是一個Map類型的對象,key是所有的表單元素的name,值就是一個FormControl對象,里面保存著數據、和驗證結果、是否修改等狀態。也正是因為這些FormControls,我們才能夠使用theForm.value的方式獲取表單里的數據。當我們點擊保存按鈕的時候,就能在日志里面看到表單的數據:

{  name: "張三",  mobile: 13800138001,  city: "北京",  street: "朝陽望京..."}

使用ngModelGroup分組顯示

一般情況下,我們的model數據有可能是嵌套的,比如對于用戶信息來說,城市和街道可能在一個地址對象address里,例如:

{  name: "張三",  mobile: 13800138001,  address: {    city: "北京",    street: "朝陽望京..."  }}

對于這樣的數據,我們就可以使用ngModelGroup來分組。模板就是這樣:

<form #userForm="ngForm" (ngSubmit)="logForm(userForm)"> <label>姓名:</label> <input type="text" name="name" [(ngModel)]="user.name"> <label>電話:</label> <input type="text" name="mobile" [ngModel]="user.mobile"> <fieldset ngModelGroup="address">  <label>城市:</label>  <input type="text" name="city" [ngModel]="user.address.city">  <label>街道:</label>  <input type="text" name="street" [ngModel]="user.address.street">  <button type="submit">保存</button> </fieldset></form>

這樣我們就把地址信息都封裝到一個address對象里面。注意我們綁定的數據的結構也發生改變,這樣,我們也需要修改我們的組件里面的用戶數據:

export class TemplateFormsComponent {  user: any;  constructor() {    this.user = {      name: '張三',      mobile: 13800138001,      address: {        city: '北京',        street: '朝陽望京...'      }    };  }}

至此,我們的表單的基本功能就算完成了。我們在面板中創建了表單,在組件中初始化了用戶數據,并顯示到頁面上,在頁面上用ngModel,將頁面上的數據更改綁定到組件上。同時,使用name屬性,使得表單里面的所有數據都成為FormControl對象。在提交所調用的方法里,獲得了表單的驗證狀態和數據。

表單控件的驗證和狀態

下一步,我們來添加數據驗證,Angular2為我們提供了幾種最基本的驗證:

  • required:表明該數據是必須的。
  • minlength:設置該字段的長度的最小值,即使輸入的是數字,也按照字符串來判斷長度。
  • maxlength:設置該字段的長度的最大值。
  • pattern:使用正則表達式驗證

在使用Angular的驗證之前,我們首先需要關閉瀏覽器默認的驗證,不然,如果某一個輸入不合法,提交按鈕就無法提交。我們在form里添加novalidate:

<form #userForm="ngForm" (ngSubmit)="logForm(userForm)" novalidate>

然后,我們對姓名輸入框添加驗證,并根據驗證的結果顯示不同的提示,同時,為了演示Angular2表單控件的特性,再添加幾個提示,來顯示該值的狀態,代碼如下:

<input type="text" name="name" [(ngModel)]="user.name" #name="ngModel" required minlength="3"><span *ngIf="name.pristine" class="label label-primary">未修改</span><span *ngIf="name.dirty" class="label label-warning">已修改</span><span *ngIf="name.valid" class="label label-success">有效</span><div [hidden]="name.valid || name.pristine" class="alert alert-danger">  <p *ngIf="name.errors?.minlength">姓名最小長度為3</p>  <p *ngIf="name.errors?.required">必須輸入姓名</p></div>

首先,我們在input上添加了2個驗證,required和minlength="3"。

其次,我們使用#name="ngModel"創建了一個模板引用變量,這樣我們在下面就可以使用name來獲取這個表單控件(FormControl)的引用。表單控件有一些屬性,如pristine, dirty, valid, touched,這幾個都是狀態類型,表示某一種狀態是否為真。除此以外還有控件的值可以用name.value獲取。最后,還有驗證的錯誤信息結果,會放在name.errors里。

在上面的代碼里,我們用<span *ngIf="name.pristine" class="label label-primary">未修改</span>,在控件值未被修改的時候,顯示一個lebel。同樣,在被修改、驗證有效的時候顯示相應的標簽。

最后,所有的驗證結果的錯誤信息會保存在name.errors里,如果沒有數據驗證錯誤,這個errors值就是null,所以,在上面的代碼里,我們用name.errors?.minlength,這表示,如果errors不為null,而且errors.minlength也不為空的時候,才顯示里面的信息。

我們可以看到,表單控件的驗證會將驗證器的名字作為key放在errors里面,對應的值是true。我們就是用這個特性,來根據控件驗證的不同結果,來顯示友好的錯誤信息。

如果運行我們的實例,可以發現,對于姓名,如果清空它的值,發現只有一個錯誤信息,就是必須輸入姓名。你可能會覺得,這時候,值為空,那他的長度也小于3,那么minlength這個錯誤也應該被檢測到才對,但是實際上,遇到第一個錯誤以后,就沒有其他的驗證。

在上面姓名輸入框上,我們使用#name="ngModel"創建了一個模板引用變量,然后在接下來的模板里面使用它獲得表單控件。實際上,我們也可以直接使用之前定義的對ngForm的引用,來獲得這個表單里所有控件的狀態。例如,對電話,我們使用下面的方式:

<input type="text" name="mobile" [ngModel]="user.mobile" required minlength="11" maxlength="11"><span *ngIf="userForm.controls.mobile?.pristine" class="label label-primary">未修改</span><span *ngIf="userForm.controls.mobile?.dirty" class="label label-warning">已修改</span><span *ngIf="userForm.controls.mobile?.valid" class="label label-success">有效</span><div [hidden]="userForm.controls.mobile?.valid || userForm.controls.mobile?.pristine" class="alert alert-danger">  <p *ngIf="userForm.controls.mobile?.errors?.minlength">電話長度必須為11</p>  <p *ngIf="userForm.controls.mobile?.errors?.required">必須輸入電話</p></div>

在這里,我們沒有獲取對mobile的模板引用,而是用ngForm的引用獲得:

userForm.controls.mobile?.pristine

當獲取驗證錯誤結果時:

userForm.controls.mobile?.errors?.minlength

注意這里在mobile上就使用?是因為,在使用ngIf渲染頁面上的元素的時候,這個表單控件還沒有初始化完成,如果不加這個?,就會出現錯誤。

根據驗證狀態定義樣式

Angular的表單驗證,除了在控件上的數據以外,它還會根據狀態在控件所在的html元素上添加css樣式:

所以,我們只需要定義相關的css,就可以實現根據狀態顯示不同的效果。

.ng-valid[required], .ng-valid.required { border-left: 5px solid #42A948; /* green */}.ng-invalid:not(form).ng-invalid:not(fieldset) { border-left: 5px solid #a94442; /* red */}

結合各種css的選擇器,我們就可以根據表單控件的狀態實現各種顯示的樣式。

在組件中獲取表單控件數據

最后,我們再看看怎樣在組件中獲取這些控件的狀態和結果,在上面,我們給ngForm添加了一個提交方法:

<form #userForm="ngForm" (ngSubmit)="logForm(userForm)" novalidate>

然后在組件中,這個logForm(userForm)方法如下:

logForm(theForm: NgForm) {  if (theForm.invalid) {    if (theForm.controls['name'].errors) {      this.nameErrorMsg = 'name error:' + JSON.stringify(theForm.controls['name'].errors);    } else {      this.nameErrorMsg = null;    }  }  console.log(theForm.value);}

在這個方法里,theForm就是ngForm的模板引用實例,類型是NgForm的。

如果表單驗證有失敗,theForm.invalid就是false。

theForm.controls就是這個表單里的所有控件,如果想獲取姓名的驗證結果,就是theForm.controls['name'].errors。

用這種方式,我們就可以在組件中獲取所有表單控件的數據、驗證狀態、錯誤信息等。

重置表單

一般情況下,如果是新建用戶信息,我們需要在保存成功以后,清空當前數據,重置表單的狀態,等待用戶重新輸入。如果我們只是清空數據,這時候那些驗證錯誤就會被檢測到,我們我們需要將表單控件也都重置成未修改狀態。這在Angular2里很簡單,它提供了一個reset方法。

我們在里面添加一個重置按鈕:

<button (click)="reset(userForm)">重置</button>

然后在組件里:

reset(theForm: NgForm) {  theForm.reset();  return false;}

注意我們需要讓這個方法返回false,這樣他就不會觸發submit的方法。

在官方的文檔中,還提供了另一種技巧來實現這種重置,就是在form上使用ngIf:

<form #userForm="ngForm" (ngSubmit)="logForm(userForm)" novalidate *ngIf="active">

只有在active為true時這個表單才會創建。

然后在重置的時候,設置這個active為false,這樣這個表單就會被銷毀,然后用setTimeout的方式再設置它為true,這個表單就會重新創建,這樣就實現了重置的效果。

reset() {  this.user = { // 重置用戶數據    address: {}  };  this.active = false;  setTimeout(() => this.active = true, 0);  return false;}

這也是一種小竅門,可以在某些情況下使用。

總結

至此,有關模板驅動的表單的基本用法大致完成,再總結一下模板驅動的表單的基本特性:

  1. 所有的表單控件的定義都在模板里
  2. 所有的驗證器都在模板里面添加
  3. 表單數據的狀態、驗證結果都在模板上通過判斷表單里面控件數據的狀態來顯示
  4. 如果需要測試這部分的代碼,需要使用e2e(端到端)測試,也就是在瀏覽器里面

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲福利视频专区| 亚洲精品视频网上网址在线观看| 自拍偷拍亚洲在线| 欧美日韩免费网站| 激情亚洲一区二区三区四区| 久久精品久久久久电影| 日韩美女写真福利在线观看| 久久人人爽人人爽人人片av高请| 国产午夜精品一区二区三区| 日韩精品久久久久| 国产精品∨欧美精品v日韩精品| 日韩在线视频网站| 91精品久久久久久久久青青| 精品亚洲国产成av人片传媒| 久久精品国产清自在天天线| 尤物yw午夜国产精品视频明星| 92看片淫黄大片欧美看国产片| 美日韩精品免费观看视频| 成人欧美一区二区三区在线| 在线播放国产精品| 一区二区三区视频免费在线观看| 国产一区二区黄| 欧美激情极品视频| 国产精品扒开腿做爽爽爽的视频| 美女视频久久黄| 久久久久久久影院| 精品国产91久久久久久| 国产精品99一区| 日韩欧美成人区| 欧美成人一区二区三区电影| 日韩av在线一区二区| 亚洲精品美女免费| 欧美夫妻性生活视频| 国产一区二区日韩精品欧美精品| 久久久久成人精品| 欧美性猛交xxxx黑人猛交| 日本不卡免费高清视频| 欧美黑人一区二区三区| 色婷婷成人综合| 国产精品一区=区| 日韩av一卡二卡| 神马国产精品影院av| 久久国产精品久久久久| 91免费的视频在线播放| 一本一道久久a久久精品逆3p| 精品久久久久久亚洲国产300| 91久久综合亚洲鲁鲁五月天| 国产欧美日韩综合精品| 久久99久久久久久久噜噜| 国产99久久精品一区二区 夜夜躁日日躁| 国模视频一区二区三区| 亚洲91精品在线| 色与欲影视天天看综合网| 亚洲午夜色婷婷在线| 热久久这里只有精品| 日韩性生活视频| 日韩a**站在线观看| 日韩电影中文 亚洲精品乱码| 亚洲欧美激情视频| 日韩在线国产精品| 日韩精品中文字幕有码专区| 国产免费一区二区三区在线能观看| 国自产精品手机在线观看视频| 国产欧美日韩精品专区| 欧美亚洲国产日韩2020| 日韩精品在线视频美女| 日韩精品在线观看一区二区| 日韩www在线| 国产精品一二三在线| 精品福利一区二区| 精品女同一区二区三区在线播放| 97香蕉久久夜色精品国产| 欧美日韩亚洲国产一区| 国内精品久久久久| 26uuu另类亚洲欧美日本一| 久久成人18免费网站| 日本精品在线视频| 久久97精品久久久久久久不卡| 78m国产成人精品视频| 亚洲欧美激情视频| 久久精品视频亚洲| 亚洲永久在线观看| 日韩欧美国产成人| 亚洲www在线观看| 欧美激情视频在线免费观看 欧美视频免费一| 欧美日韩午夜视频在线观看| 久久久久久国产精品三级玉女聊斋| 国产精品久久久久免费a∨大胸| 日韩国产欧美精品在线| 国产精品中文字幕在线观看| 久久这里有精品| 国产精品日韩av| 日韩在线视频观看正片免费网站| 欧美激情视频一区二区| 国产一区二区三区日韩欧美| 清纯唯美亚洲综合| 亚洲白拍色综合图区| 欧美孕妇毛茸茸xxxx| 久久久久久综合网天天| 国产精品久久久久久久久借妻| 美女福利精品视频| 国产精品久久久久久影视| 国产精品网址在线| 日韩一级裸体免费视频| 国产精品视频专区| 亚洲iv一区二区三区| 国产精品久久久久久av福利| 亚洲欧美综合图区| 成人写真视频福利网| 亚洲九九九在线观看| 中文字幕9999| 国产亚洲欧美日韩美女| 成人亚洲激情网| 国产精品久久久久一区二区| 一道本无吗dⅴd在线播放一区| 欧美日韩激情网| 欧美成人精品一区二区| 亚洲欧美精品suv| 国产黑人绿帽在线第一区| 神马国产精品影院av| 中文字幕精品网| 成人网在线免费看| 国模吧一区二区| 国产精自产拍久久久久久| 国产成人啪精品视频免费网| 久久影院免费观看| 成人精品福利视频| 欧美日韩成人在线视频| 夜夜嗨av一区二区三区四区| 久久久av亚洲男天堂| 国产啪精品视频网站| 亚洲性无码av在线| 久久99精品久久久久久琪琪| 亚洲成人在线网| 91久久精品美女高潮| 日韩成人激情在线| 日韩av在线免费看| 国产精自产拍久久久久久| 国产精品视频男人的天堂| 97超级碰在线看视频免费在线看| 国产精品劲爆视频| 91网站免费看| 夜夜嗨av色综合久久久综合网| 一区二区欧美日韩视频| 精品国产老师黑色丝袜高跟鞋| 亚洲美女在线视频| 久久精品国产亚洲精品2020| 欧美日韩一区二区在线播放| 欧美多人乱p欧美4p久久| 国模吧一区二区三区| 欧美日韩福利在线观看| 成人h视频在线观看播放| 久久手机精品视频| 国产精品自拍视频| 97人人模人人爽人人喊中文字| 日韩电影免费在线观看| 一区二区亚洲欧洲国产日韩| 欧美激情在线一区| 九九热视频这里只有精品| 国产精品久久久久久av福利| 日韩欧美一区视频| 午夜精品福利视频| 国产精品欧美一区二区| 欧美精品精品精品精品免费|