Web
開發中,表單一直是一個重要的話題。html
在AngularJS
中,咱們可使用雙向數據綁定很簡單地完成表單的開發,可是會帶來嚴重的性能問題,而Angular
對於表單的設計,讓咱們的表單在保持性能的同時更優雅。程序員
咱們以一個最簡單的登陸表單爲例來學習Angular
中的表單:typescript
這就是Angular
的表單思想,一個FormGroup
管理整個表單,同時FormControl
管理表單內的各個元素。小程序
導入表單模塊:api
基礎的HTML
表單代碼:框架
<div class="container"> <div class="row"> <div class="col-md-4 col-md-offset-4"> <h2 class="text-center">Angular Form</h2> <form> <div class="form-group"> <label>Email address</label> <input type="email" class="form-control" placeholder="Email" /> </div> <div class="form-group"> <label>Password</label> <input type="password" class="form-control"placeholder="Password" /> </div> <button type="submit" class="btn btn-default">Submit</button> </form> </div> </div> </div>
略加修改:函數
<div class="container"> <div class="row"> <div class="col-md-4 col-md-offset-4"> <h2 class="text-center">Angular Form</h2> <form #myForm="ngForm" (ngSubmit)="onSubmit(myForm)"> <div class="form-group"> <label>Email address</label> <input type="email" class="form-control" placeholder="Email" ngModel /> </div> <div class="form-group"> <label>Password</label> <input type="password" class="form-control"placeholder="Password" ngModel /> </div> <button type="submit" class="btn btn-default">Submit</button> </form> </div> </div> </div>
當咱們的應用導入FormsModule
時,form
就再也不是原生的form
了,而是Angular
重寫過的NgForm
組件,就像在AngularJS
中使用的form
實際上是被框架擴展的指令。性能
因此咱們能夠爲form
添加NgForm
組件定義的輸入輸出。學習
這是NgForm
的官方api
文檔描述,導出ngForm
,而後輸出ngSubmit
事件。測試
<form #myForm="ngForm" (ngSubmit)="onSubmit(myForm)"> </form>
這裏用到了導出的ngForm
,併爲其取名爲myForm
,因此傳給onSubmit
的myForm
其實就是導出的ngForm
,當業務邏輯很是簡單的狀況下能夠這樣寫,直接用導出的ngForm
,就至關於使用一個默認配置好的對象。
<input type="email" class="form-control" name="email" placeholder="Email" ngModel /> <input type="password" class="form-control" name="password" placeholder="Password" ngModel />
兩個input
用到了ngModel
指令,該指令會爲該元素建立一個默認的FormControl
。
onSubmit(myForm: NgForm): void { console.log(myForm); console.log(myForm.value); }
提交表單,打印,能夠查看myForm
中的許多屬性,同時它的value
屬性就是表單內容。
點開NgForm
,其實除了表單的值外,還有dirty
、error
、invalid
等屬性方便咱們對錶單進行驗證。
點開controls
屬性,咱們能夠看到該表單中的FormControl
:
<input type="email" class="form-control" name="email" placeholder="Email" /> <input type="password" class="form-control" name="password" placeholder="Password" />
咱們嘗試將input
中原來添加的ngModel
指令刪除,再打印。能夠看到該表單中沒有FormControl
。
這就驗證了咱們以前的猜測,ngModel
指令默認的單向數據綁定,其實就是爲咱們建立了一個默認的FormControl
用於控制該元素的值。
在不考慮表單驗證的前提下,這個基本的新增表單應該就算完成了,在onSubmit
中獲取表單的值,而後包裝對象調用Service
請求api
。
新增時由於沒有初始的數據,因此直接使用默認建立的FormGroup
和FormControl
就好了,可是編輯時是有初始化的數據的,因此咱們就須要建立自定義的FormGroup
、FormControl
。
這裏是Angular權威指南
中推薦初始化表單的方式,固然也能夠去new
。
仍是規範,構造和初始化分開,constructor
中使用formBuilder
構造FormGroup
、FormControl
。
myForm: FormGroup; constructor(formBuilder: FormBuilder) { this.myForm = formBuilder.group({ email: '', password: '' }); }
初始化,爲FormControl
設置數據,實際開發應該是從後臺獲取數據而後設置,這裏爲了演示方便,直接setValue
。
ngOnInit() { this.getOriginData(); } getOriginData(): void { this.myForm.setValue({ email: 'zhangxishuo1998@gmail.com', password: 'this is password' }); }
數據有了,接下來就是將數據綁定到組件上。將myForm
做爲參數傳給組件,ngSubmit
不變。
<form [formGroup]="myForm" (ngSubmit)="onSubmit(myForm)"> <div class="form-group"> <label>Email address</label> <input type="email" class="form-control" name="email" placeholder="Email" [formControl]="myForm.controls['email']" /> </div> <div class="form-group"> <label>Password</label> <input type="text" class="form-control" name="password" placeholder="Password" [formControl]="myForm.controls['password']" /> </div> <button type="submit" class="btn btn-default">Submit</button> </form>
綁定成功!
修改代碼,咱們刪除郵箱與密碼的初始化代碼,讓其爲默認的空值。
縱使風雲變幻,始終不離其宗。
<form [formGroup]="myForm" (ngSubmit)="onSubmit(myForm)"> <div class="form-group"> <label>Email address</label> <input type="email" class="form-control" name="email" placeholder="Email" [formControl]="myForm.controls['email']" /> </div> <pre>Valid: {{ myForm.controls['email'].valid }}</pre> <pre>Touch: {{ myForm.controls['email'].touched }}</pre> <div class="form-group"> <label>Password</label> <input type="text" class="form-control" name="password" placeholder="Password" [formControl]="myForm.controls['password']" /> </div> <pre>Valid: {{ myForm.controls['password'].valid }}</pre> <pre>Touch: {{ myForm.controls['password'].touched }}</pre> <button type="submit" class="btn btn-default">Submit</button> </form>
咱們想對這兩個輸入框進行驗證,直接在初始化時設置驗證條件:
constructor(formBuilder: FormBuilder) { this.myForm = formBuilder.group({ email: ['', Validators.compose([ Validators.required, Validators.email ])], password: ['', Validators.required] }); }
實現驗證:郵箱的空驗證與郵箱格式驗證,密碼的空驗證。
而後符合咱們以往的開發規範,用一個ngIf
的p
標籤,而後當不合法且觸碰過期,顯示提示信息。
在以往的AngularJS
項目裏,咱們只能用已有的驗證規則,可是如今更強大了!
其實,咱們上面用到的required
、email
等的驗證規則都是框架爲咱們提供的已有的驗證函數,翻開ValidatorFn - Angular,有ValidatorFn
接口,實現該接口,便可實現自定義的驗證方法!
雙向數據綁定的思考:
既然表單都設計得如此強大,咱們又何須拘於雙向數據綁定,雙向數據綁定是咱們實現軟件功能的一種方式,但不是惟一方式。
若是使用雙向數據綁定,那確定比我上面說的簡單許多,可是自從學習了軟件測試,漸漸明白了,其實咱們在作軟件開發時,與咱們日常在學校寫代碼是不同的。
就像今天吳老師講的例子:求e
的50
次方。若是在學校,咱們可能直接一個for
循環50
次而後一次一次去乘。
可是若是在公司,咱們可能就會先算e的平方
,而後再算出e的四次方
,e的八次方
,而後根據幾個已有的去組合須要的結果,這會讓性能大幅提高。
這是美團點評團隊優化小程序的一篇博客:
或許,以前的咱們學習了不少知識,學會了很多框架,也寫過許多代碼,可是我對本身的評價仍是程序員。今天,我才明白,何爲軟件工程師?!
立個小目標:之後寫代碼時多考慮一點,優秀的軟件工程師寫出的代碼是可以直接上線的。