您好,登錄后才能下訂單哦!
這篇文章給大家分享的是有關Angular2如何實現模板驅動的表單的內容。小編覺得挺實用的,因此分享給大家做個參考,一起跟隨小編過來看看吧。
在網頁開發中,表單估計是最常用的一個,同時也是最麻煩、最容易出問題的。在一個稍微復雜一點的應用中,我們除了用表單元素收集數據,還需要驗證,幾個數據之間可能還會相互關聯,然后根據不同的數據值調用不同的業務邏輯等。
使用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-tutorial git checkout template-driven # 檢出該文所使用的tag npm install npm 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; }
感謝各位的閱讀!關于“Angular2如何實現模板驅動的表單”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,讓大家可以學到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。