1. 程式人生 > >部落格轉至https://chengyanzhao.github.io,CSDN不再更新。

部落格轉至https://chengyanzhao.github.io,CSDN不再更新。

寫在前面

1表單型別

  1. 模板驅動型表單:使用模板表單內建指令、內建校驗的方式來構建表單。也就是將程式碼、邏輯放在模版(HTML)裡。
  2. 響應式表單:將功能性的內容移到程式碼裡。
  3. 動態表單:用程式碼生成表單DOM。

2模板驅動表單

2.1表單指令

指令是對DOM的擴充套件,Angular內建了表單指令來擴充套件表單功能,如資料繫結、校驗規則、顯示校驗錯誤資訊等。

2.1.1NgForm指令

  1. NgForm指令是表單的控制中心,所有表單指令都需要在NgForm指令內部才能正常執行。
  2. NgForm需要在模組中引入。
  3. 在模版中,不需要在標籤手動掛接NgForm指令,如果在模組中引入了FormsModule模組,Angular 自動建立NgForm指令,並把它附加到標籤。
  4. NgForm指令控制了通過NgModule指令和name屬性建立的控制元件類,並且會跟蹤控制元件類的屬性變化,包括有效性屬性(valid)。

2.1.2NgModel指令

  1. 是ngModel,不是ngModule!我就犯了這個2b錯誤!
  2. NgModel指令是表單資料繫結的核心所在,幾乎所有的表單特性都依賴NgModule指令實現。
  3. NgModel指令實現了表單控制元件的資料繫結,提供了控制元件狀態跟蹤及校驗功能。
  4. 在控制元件中使用NgModel屬性繫結,必須給該控制元件一個name屬性,否則會報錯。因為NgForm指令會為表單建立一個控制元件物件FormControl的集合,以此來作為表單控制元件的容器。控制元件的NgModel屬性繫結會以name作為唯一識別符號來註冊並生成一個FormControl,將其加入到FormControl的集合中。

3常用表單控制元件

3.1單選框

單選框控制元件(Radio)實現雙向資料繫結,同一組單選框控制元件的所有[(ngModel)]屬性必須繫結同一個模型資料,且name屬性名也必須相同:

<input type="radio" name="sex" [(ngModel)]="curContact.sex" value="female" /><input type="radio" name="sex" [(ngModel)]="curContact.sex" value="male" />

3.2複選框

複選框控制元件(CheckBox)用來表示該表單複選框是否被選中,其中[(ngModel)]屬性繫結的是一個布林值:

<input type="checkbox" name="lock" [(ngModel)]="curContact.lock" />禁用

3.3單選下拉框

單選下拉框控制元件(Select)的雙向資料繫結,需結合option元素繫結的值來實現。option選項的元素屬性的繫結目標有兩種,分別為value和ngVlue。當在option元素中使用value繫結資料時,其返回值型別是基本資料型別;當使用ngValue繫結資料時,其返回值型別是物件資料型別。

在構建下拉框前,需要先定義下拉框列表所需的資料:

export class FormComponent {
    interests: any[] = [
        { value: 'reading', display: '閱讀' },
        { value: 'traveling', display: '旅遊'},
        { value: 'sport', display: '運動'}
    ];
}
<!-- 返回基本資料型別 -->
<select name="interestValue" [(ngModel)]="curContact.interestValue">
    <option *ngFor="let interest of interests" [value]="interest.value">{{interest.display}}
    </option>
</select>
<!-- 返回物件資料型別 -->
<select name="interestObj" [(ngModel)]="curContact.interestObj">
    <option *ngFor="let interest of interests" [ngValue]="interest">{{interest.display}}</option>
</select>

3.4多選下拉框

多選下拉框控制元件(Multiple Select)實現了下拉選擇多個選項的功能。多選下拉框的用法與單選下拉框類似,不同的是多選下拉框返回的資料是一個由所有被選項組資料組成的陣列。
下面實現一個多選下拉框,返回一個成員為字串的陣列:

<select multiple name="interestMul" [(ngModel)]="curContact.interestMul">
    <option *ngFor="let interest of interests" [value]="interest.value">
        {{interest.display}}
    </option>
</select>

當然,多選下拉框也可以繫結物件型別的資料,使用ngValue,與單選下拉框類似。

4模版區域性變數(區域性變數)

區域性變數是模版中對DOM元素、指令、元件*引用*,可以使用在當前元素、兄弟元素或任何子元素中。

4.1DOM元素區域性變數

  1. DOM元素區域性變數指向DOM元素。
  2. DOM元素區域性變數不需要手動設定值,只需要在元素中新增屬性即可。

在標籤元素中定義DOM元素區域性變數方式:
1. #區域性變數名
2. ref-變數名

<li>
    <label for="name">姓名:</label>
    <input type="text" #contactName name="contactName" id="contactName">
    <input type="text" ref-relNum name="telNum" id="telNum">
    <p>{{contactName.value}} == {{telNum.value}}</p>
</li>

在模版的其他元素中可以直接使用該元素的DOM屬性。

4.2表單指令區域性變數

  1. 表單指令區域性變數指向表單指令例項物件。
  2. 表單指令區域性變數需要在定義時手動初始化特定指令的代表值。

4.2.1NgForm 表單區域性變數

下面的例子,在表單中定義區域性變數contactForm,將contactForm變數初始化為ngForm,並在表單控制元件加入ngModule及contactName屬性:

<form #contactForm="ngForm">
    <ul>
        <li>
            <label for="contactName">姓名:</label>
            <input type="text" name="contactName" [(ngModel)]="curContact.name" />
        </li>
        <li>
            <label for="telNum">電話:</label>
            <input type="text" name="telNuM" [(ngModel)]="curContact.telNum" />
        </li>
    </ul>
</form>

區域性變數contactForm為NgForm指令例項物件的引用,可以在模版中讀取NgForm例項物件的屬性值,如追蹤表單的valid屬性狀態。當被包含的所有控制元件都有效時,contactForm.valid的值為true,否則為false。在控制元件中新增ngModel和name屬性後,若往姓名控制元件中輸入”李四”,電話控制元件中輸入”123456789”,則contactForm.value的值為

{
    name: '李四',
    telNum: '123456789'
}

contactForm.value是一個簡單的JSON物件,該物件是的鍵是對應控制元件元素的name屬性值,而其值對應控制元件元素的value值。

NgModel控制元件區域性變數

下面的例子是一個文字控制元件,將[{ngModel}]初始化為聯絡人姓名,並新增控制元件區域性變數name:

<input type="text" name="contactName" [(ngModel)]="curContact.name" #contactName="ngModule" />
<p>{{contactName.valid}}</p>

區域性變數contactName是對NgModel指令例項物件的引用,可以在模版中讀取NgModel例項物件的屬性值,如通過contactName.valid可以追蹤控制元件狀態、表單校驗不通過時提示錯誤資訊等。

Angular提供NgForm表單區域性變數和NgModel控制元件區域性變數,在模版中為追蹤表單狀態及表單的資料校驗提供了便利。

表單狀態

  1. NgForm和NgModel指令都可以用於追蹤表單狀態來實現資料校驗。
  2. NgForm和NgModel都有五個表示狀態的屬性,值為布林型,可以通過對應的區域性變數獲取。
  3. NgForm追蹤的是整個表單控制元件的狀態。
  4. NgModel追蹤的是其所在表單控制元件的狀態。

表單狀態的屬性語義如下:

狀態 true/false
valid 表單值是否有效
pristine 表單值是否未改變
dirty 表單值是否已改變
touched 表單是否已被訪問過
untouched 表單是否未被訪問過

NgModelGroup指令

NgModelGroup指令可以對錶單輸入內容進行分組,方便我們在語義上區分不同型別的輸入。例如聯絡人的資訊包括姓名及住址,對這兩者還可以進行更精細化的資訊收集,如姓名可分為姓和名字,地址可分為城市、區、街等。通過NgModelGroup可以將姓名及住址進行分組收集:

<form #contactForm="ngForm">
    <fieldset ngModelGroup="nameGroup" #nameGroup="ngModelGroup">
        <label>姓:</label>
        <input type="text" name="firstname" [(ngModel)]="curContact.firstname" required />
        <label>名字:</label>
        <input type="text" name="lastname" [(ngModel)]="curContact.lastname" required />
    </fieldset>
    <fieldset ngModelGroup="addressGroup" #addressGroup="ngModelGroup">
        <label>街:</label>
        <input type="text" name="street" [(ngModel)]="curContact.street" required />
        <label>區:</label>
        <input type="text" name="zip" [(ngModel)]="curContact.zip" required />
        <label>城市:</label>
        <input type="text" name="city" [(ngModel)]="curContact.city" required />
    </fieldset>
</form>

上面例子中分別對聯絡人的姓名和住址進行了分組,通過ngModelGroup指令,將姓和名字的表單內容包裹成姓名分組,用nameGroup表示;將城市、區和街道的表單內容包過程住址分組,用addressGroup表示。此時contactForm.value的值為:

{
    nameGroup:{
        firstname: '',
        lastname: ''
    },
    addressGroup:{
        street: '',
        zip: '',
        city: ''
    }
}

除此之外,NgModelGroup例項物件的valid屬性可以單獨校驗其所在分組控制元件的輸入是否有效。例如在上例的姓名分組中,只有當curContact.firstname、curContact.lasename輸入都有效時,區域性變數nameGroup.valid才會變為true,否則為false。

ngSubmit事件

ngSubmit事件可以相應表單裡型別為submit的按鈕操作,並負責表單的提交流程。
閒話少敘看程式碼:

<form #contactForm="ngForm" (ngSubmit)="doSubmit(contactForm.value)">
    <!-- ... -->
    <li class="form-group">
        <button type="submit" class="btn btn-default" [disabled]="!contactForm.valid">新增</button>
        <button type="reset" class="btn btn-default">重置</button>
    </li>
</form>

提交按鈕的處理邏輯:

export class FormComponent {
    doSubmit(formValue: any){
        //處理表單資料並提交
    }
}

上面例子中,綁定了ngSubmit事件,ngSubmit事件的型別是EventEmitter。當提交按鈕被點選後,首先執行表單原生的onSubmit事件,接著執行FormComponent元件中定義的doSubmit()方法。

自定義表單樣式

NgModel指令不僅僅能夠追蹤表單控制元件的狀態,還會根據表單控制元件的狀態使用對應的CSS狀態類來更新表單控制元件的類名。表單控制元件包括六個CSS狀態類:

狀態 為true時的css類 為false時的css類
控制元件是否已經被訪問過 ng-touched ng-untouched
控制元件值是否已經變化 ng-dirty ng-pristine
控制元件值是否有效 ng-valid ng-invalid

表單控制元件的CSS類名會根據表單控制元件的狀態變化而變化。可以方便寫CSS來控制表單控制元件在不同狀態使用不同的樣式。

表單校驗

表單校驗是用來檢查表單的輸入值是否符合規則。HTML5表單內建了相關的基礎校驗,但能力有限。Angular封裝了相關表單校驗規則,並提供介面,以方便完成表單校驗。

表單內建校驗

Angular支援的表單內建校驗包括:
- required:判斷表單控制元件值是否為空。
- minlength:判斷表單控制元件值的最小長度。
- maxlength:判斷表單控制元件值的最大長度。
- pattern:判斷表單控制元件值的匹配規則。

使用Angular表單內建校驗與使用普通HTML校驗一致,直接在表單控制元件中新增對應的校驗屬性即可。

<input type="text" minlength=3 maxlength=10 name="contactName" [(ngModel)]="curContact.name" required />

tips
HTML支援簡單的攔截校驗,但是其提示樣式及文字是固定且不可控的,開發者可以在標籤中新增novalidate屬性來遮蔽HTML的攔截校驗

表單自定義校驗

當Angular表單內建校驗無法滿足需求的時候,就必須自己寫校驗規則了,也就是表單自定義校驗。下面學習一下如何建立自定義校驗。

建立自定義校驗

下面自定義一個使用者名稱的校驗器,校驗規則為:使用者名稱必須是郵箱、手機號碼的格式。

// validate-username.ts
import { FormComtrol } from '@angular/forms';

const EMAIL_REGEXP = new RegExp("[0-z0-9][email protected][a-z0-9]+.com");
const TEL_REGEXP = new RegExp("1[0-9]{10}");

export function validateUserName(c: FormControl){
    return (ENAIL_REGEXP.test(c.value) || TEL_REGEXP.test(c.value)) ? null : {
        userName:{
            valid: false,
            errorMsg: '使用者名稱必須是手機號或郵箱帳號'
        }
    };
}

使用自定義校驗

  1. 這裡只介紹在模型驅動方式構建的表單中如何使用自定義校驗。
  2. 在模組中匯入ReactiveFormsModule。

這裡需要仔細學習一下再整理

import { Component } from '@angular.core';
import { FormGroup, FormControl } from '@angular.forms';
import { validateUserName } from './validate-username';

@Component({
    selector: 'add-contact',
    template: `
        <form [formGroup]="customForm">
            <label>姓名:</label>
            <input type="text" formControlName="customName">
        </form>
    `
})
export class FormComponent {
    customForm = new FormGroup({
        customName: new FormControl('',validateUserName)
    });
}

該例子定義了customForm和customName。在構建FormControl例項物件customName時傳入的引數中,第一個引數為控制元件返回值的初始值,第二個引數為該控制元件的檢驗配置方法。

此外,檢驗配置可以使用Validators的內建校驗,如Validators.required()、Validators.minLength()等,這與直接在表單控制元件元素上新增required、minlength屬性效果一樣。

使用Validators內建校驗,需要先從@angular/forms匯入Validators。

import { Validators } from '@angular/forms';

//...
customForm = new FormGroup({
    customName: new FormControl('',Validators.minLength(4))
});
//...

如果需要在一個表單中新增多個校驗器,可以在校驗配置引數中使用陣列,陣列元素為對應的校驗方法:

customForm = new FormGroup({
    customName: new FormControl('',[Validators.minLength(4), ValidateUserName])
});

注意
如果你按照以上程式碼無法跑通,控制檯報錯

Can't bind to 'formGroup' since it isn't a known property of 'form'.

這是因為你沒有在元件所屬跟模組匯入import { ReactiveFormsModule } from '@angular/forms'

我也腦抽了出現這個問題,研究了一下午為啥不對,最後發現,雖然模組裡面import了,但是沒有放在imports元資料中。白白浪費了一下午時間啊!!!

版權說明

本部落格內所有揭祕angular2學習的文章都是學習《揭祕Angular2》—廣發證券網際網路金融技術團隊著作這本書的學習總結及部分內容摘抄,若有侵權請與本人聯絡刪除侵權內容。
qq:451354
郵箱:[email protected]