Angular 表單

問題描述

Web開發中,表單一直是一個重要的話題。html

AngularJS中,咱們可使用雙向數據綁定很簡單地完成表單的開發,可是會帶來嚴重的性能問題,而Angular對於表單的設計,讓咱們的表單在保持性能的同時更優雅。程序員

實例

咱們以一個最簡單的登陸表單爲例來學習Angular中的表單:typescript

clipboard.png

思想

clipboard.png

這就是Angular的表單思想,一個FormGroup管理整個表單,同時FormControl管理表單內的各個元素。小程序

Create

導入表單模塊:api

clipboard.png

基礎的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事件。測試

clipboard.png

<form #myForm="ngForm" (ngSubmit)="onSubmit(myForm)">
</form>

這裏用到了導出的ngForm,併爲其取名爲myForm,因此傳給onSubmitmyForm其實就是導出的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);
}

clipboard.png

提交表單,打印,能夠查看myForm中的許多屬性,同時它的value屬性就是表單內容。

點開NgForm,其實除了表單的值外,還有dirtyerrorinvalid等屬性方便咱們對錶單進行驗證。

clipboard.png

點開controls屬性,咱們能夠看到該表單中的FormControl

clipboard.png

<input type="email" class="form-control" name="email" placeholder="Email" />
<input type="password" class="form-control" name="password" placeholder="Password" />

咱們嘗試將input中原來添加的ngModel指令刪除,再打印。能夠看到該表單中沒有FormControl

clipboard.png

這就驗證了咱們以前的猜測,ngModel指令默認的單向數據綁定,其實就是爲咱們建立了一個默認的FormControl用於控制該元素的值。

在不考慮表單驗證的前提下,這個基本的新增表單應該就算完成了,在onSubmit中獲取表單的值,而後包裝對象調用Service請求api

Update

新增時由於沒有初始的數據,因此直接使用默認建立的FormGroupFormControl就好了,可是編輯時是有初始化的數據的,因此咱們就須要建立自定義的FormGroupFormControl

這裏是Angular權威指南中推薦初始化表單的方式,固然也能夠去new

仍是規範,構造和初始化分開,constructor中使用formBuilder構造FormGroupFormControl

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>

綁定成功!

clipboard.png

Validate

修改代碼,咱們刪除郵箱與密碼的初始化代碼,讓其爲默認的空值。

縱使風雲變幻,始終不離其宗。

<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>

clipboard.png

咱們想對這兩個輸入框進行驗證,直接在初始化時設置驗證條件:

constructor(formBuilder: FormBuilder) {
    this.myForm = formBuilder.group({
        email: ['', Validators.compose([
            Validators.required,
            Validators.email
        ])],
        password: ['', Validators.required]
    });
}

實現驗證:郵箱的空驗證與郵箱格式驗證,密碼的空驗證。

clipboard.png

而後符合咱們以往的開發規範,用一個ngIfp標籤,而後當不合法且觸碰過期,顯示提示信息。

擴展驗證

在以往的AngularJS項目裏,咱們只能用已有的驗證規則,可是如今更強大了!

clipboard.png

clipboard.png

其實,咱們上面用到的requiredemail等的驗證規則都是框架爲咱們提供的已有的驗證函數,翻開ValidatorFn - Angular,有ValidatorFn接口,實現該接口,便可實現自定義的驗證方法!

clipboard.png

總結

雙向數據綁定的思考:

既然表單都設計得如此強大,咱們又何須拘於雙向數據綁定,雙向數據綁定是咱們實現軟件功能的一種方式,但不是惟一方式。

若是使用雙向數據綁定,那確定比我上面說的簡單許多,可是自從學習了軟件測試,漸漸明白了,其實咱們在作軟件開發時,與咱們日常在學校寫代碼是不同的。

就像今天吳老師講的例子:求e50次方。若是在學校,咱們可能直接一個for循環50次而後一次一次去乘。

可是若是在公司,咱們可能就會先算e的平方,而後再算出e的四次方e的八次方,而後根據幾個已有的去組合須要的結果,這會讓性能大幅提高。

這是美團點評團隊優化小程序的一篇博客:

clipboard.png

或許,以前的咱們學習了不少知識,學會了很多框架,也寫過許多代碼,可是我對本身的評價仍是程序員。今天,我才明白,何爲軟件工程師?!

立個小目標:之後寫代碼時多考慮一點,優秀的軟件工程師寫出的代碼是可以直接上線的。
相關文章
相關標籤/搜索