JavaScript >> Javascript 文檔 >  >> JavaScript

角度表單驗證

簡介

任何 Web 應用程序中最常見的功能之一是為用戶提供一個表單來輸入一些數據。您每天都使用表單來登錄、註冊、下訂單等。

在驗證之前處理用戶輸入可能會產生嚴重後果。您最終可能會存儲無效數據,例如不正確的日期、電子郵件、年齡等。由於跨站點腳本 (XSS) 等攻擊,這也可能是一個安全問題。

驗證 HTML 表單的傳統方法是使用 JavaScript 或 JQuery。不幸的是,這種方法需要一堆代碼。

Angular 作為一個成熟的框架,為驗證用戶輸入和顯示驗證消息提供了出色的支持。它有很多常用的內置驗證器,您可以利用它們,甚至可以編寫自定義驗證器。

Angular 中的表單

Angular 表單是一種常規的 HTML 表單,幾乎沒有附加功能。對於表單中的每個字段(輸入、單選、選擇等),我們需要一個 FormControl 的對象 班級。 FormControl 對象提供有關該字段的信息。它的 value , 如果值為 valid ,如果它是無效的驗證 errors 等。

它還提供了字段的狀態,例如 touched , untouched , dirty , pristine 等。

同樣,一個 FormGroupFormControl 的集合 對象。每個 Angular 表單至少有一個 FormGroup .您可能決定擁有多個 FormGroup s 在用例中,例如分離用戶註冊表單的個人詳細信息和專業詳細信息部分的處理。

FormGroup 的所有屬性 (valid , error 等)也可用於 FormControl .例如,valid FormControl 的屬性 將返回 true 如果所有 FormControl 實例是有效的。

因此,要向 Angular 表單添加驗證,我們需要做兩件事:

  • 至少一個FormGroup 表單對象
  • 一個FormControl 表單中每個字段的對象

有兩種不同的方式 這些控制對象 可以創建。我們可以提供一些指令模板中 表單和 Angular 可以創建這樣的 控件 在我們的引擎蓋下。通過這種方式創建的表單稱為模板驅動表單 .

如果我們有一些特殊的用例,並且我們想要更多地控製表單,我們可以顯式地創建這樣的 控制對象 .以這種方式創建的表單稱為反應式表單 .

模板驅動表單

在模板驅動的表單中,我們應用 ngModel 模板中每個字段的指令。 Angular 創建一個 FormControl 每個此類字段的引擎蓋下的對象並將其與相應的字段相關聯:

<div class="form-group">
  <label for="name">Name</label>
  <input type="text" class="form-control" id="name"
         ngModel name="name">
</div>

<div class="form-group">
  <label for="username">Username</label>
  <input type="text" class="form-control" id="username"
         ngModel name="username">
</div>

注意 :使用 ngModel , 需要提供 name 屬性或定義 FormControl 作為 ngModelOptions 中的“獨立” , 否則 Angular 會拋出錯誤。

另外,在 app.module.ts 你需要添加 FormsModule 導入數組:

import { FormsModule } from '@angular/forms';
// ...some other imports

imports: [
    //...some other imports
    FormsModule
]

模板驅動表單中的驗證

Angular 提供了一些內置驗證器 驗證常見用例。為了使用內置驗證器,您需要將驗證屬性應用於您想要進行驗證的每個表單字段。這些驗證屬性與 required 等常規 HTML5 驗證屬性相同 , minlength , maxlength 等等。在底層,Angular 提供了指令來將這些屬性與 Angular 框架中定義的驗證器函數相匹配。

每當 FormControl 的值發生變化時,Angular 通過運行驗證生成驗證錯誤列表。如果列表為空,則為有效狀態,否則為無效狀態。

假設我們要在其中加入以下驗證:

  • 作為字段名稱用戶名required 屬性,如果該字段為空,我們希望顯示驗證消息。
  • 名字 字段應該有一個 minlegth 的值 和 maxlength 應分別為 2 和 30 個字符。
  • 如果用戶名有空格,則顯示無效的用戶名消息。

對於我們要添加驗證的每個表單控件,我們需要添加適當的驗證屬性並導出 ngModel 到本地模板變量

<input type="text" class="form-control" id="name"
    required maxlength="30" minlength="2"
    ngModel name="name" #name="ngModel">

在上面的示例中,我們使用了以下內置驗證器 - required , minlength , 和 maxlength .

我們可以使用模板變量name 在模板中檢查所用驗證器的驗證狀態:

<div *ngIf="name.invalid && (name.dirty || name.touched)"
    class="alert alert-danger">
  <div *ngIf="name.errors.required">
    Name is required.
  </div>
  <div *ngIf="name.errors.minlength">
    Name cannot be more than 30 characters long.
  </div>
  <div *ngIf="name.errors.minlength">
    Name must be at least 2 characters long.
  </div>
</div>

因為我們使用條件語句來呈現第一個 div , 只有當內置驗證器的狀態為 invalid 時才會顯示 .我們已經在本節的開頭解釋瞭如何將狀態確定為 validinvalid .

同樣,內部 div's 僅當模板變量 name 時才會顯示 有一個屬性 errorserrors 屬性具有以下屬性之一 - required , minlengthmaxlength 和屬性值 id true .我們已經討論過模板變量如何綁定到 ngModel 指令,並且每當表單控件發生任何變化以及 Angular 對該字段運行驗證後,它都會接收這些屬性。

注意 :檢查 dirty 很重要 和 touched 狀態,否則將在頁面第一次加載時顯示錯誤消息,這對用戶體驗不利。我們需要驗證消息在以下情況之一顯示:

  • 用戶更改了一些值,即該字段是臟的(formControlObject.dirty )
  • 用戶使用選項卡或單擊將焦點切換到其他元素,即該字段被觸摸(formControlObject.touched )

如果你想參考 Angular 內置驗證器的完整列表,你可以關注 Validators API。

編寫自定義驗證器

有時,內置驗證器可能無法涵蓋您的確切用例。在這種情況下,您可能需要創建自定義驗證器函數。

驗證器函數實現 ValidatorFn 接口,這意味著它應該有簽名:

interface ValidatorFn {
    (control: AbstractControl): ValidationErrors | null
}

ValidationErrors 應該是具有一個或多個鍵值對的對象:

免費電子書:Git Essentials

查看我們的 Git 學習實踐指南,其中包含最佳實踐、行業認可的標準以及隨附的備忘單。停止谷歌搜索 Git 命令並真正學習 它!

type ValidationErrors = {
    [key: string]: any;
};

鍵應該是一個字符串,用於表示驗證錯誤的類型,如 invalidEmail , required 等。該值可以是任何值,用於提供有關驗證錯誤的更多信息。

對於上面的例子,我們想編寫一個自定義驗證函數來驗證 username 中是否沒有空格 .

雖然從技術上講,我們可以在應用程序的任何地方編寫此函數,但將所有相關的驗證器函數放在一個單獨的類中始終是一種好習慣:

import { ValidationErrors, AbstractControl } from '@angular/forms';

export class UserRegistrationFormValidators {
    static usernameShouldBeValid(control: AbstractControl): ValidationErrors | null {
        if ((control.value as string).indexOf(' ') >= 0) {
            return { shouldNotHaveSpaces: true }
        }

        // If there is no validation failure, return null
        return null;
    }
}

注意 :在這個例子中,我們返回了 true 作為鍵 shouldNotHaveSpaces 的值 因為我們不需要提供任何細節。在某些情況下,您可能需要提供詳細信息,例如:

return { maxlengthExceeded: {
        maxLength: 20,
        actual: control.value.length
    }
}

接下來,我們可以使用這個驗證器函數UserRegistrationFormValidators.usernameShouldBeValid 對於 username 模板驅動表單中的表單控件:

<div class="form-group">
  <label for="username">Username</label>
  <input type="text" class="form-control" id="username"
         required
         UserRegistrationFormValidators.usernameShouldBeValid
         [(ngModel)]="person.username" name="username">
</div>

反應式表單

在響應式表單中,我們創建 FormControl 組件中明確的對象 那個模板。這是沒有任何 ngModel 的常規 HTML 表單 指令或驗證:

<div class="form-group">
  <label for="name">Name</label>
  <input type="text" class="form-control" id="name">
</div>

<div class="form-group">
  <label for="username">Username</label>
  <input type="text" class="form-control" id="username">
</div>

讓我們假設我們想要將前面示例中的模板驅動表單轉換為響應式表單。

為此,首先,我們需要顯式創建 FormGroupFormControls 組件中的每個字段 模板:

form = new FormGroup({
    'name': new FormControl(),
    'username': new FormControl(),
})

注意 :如前所述,一個表單可以有多個 FormGroup .在這種情況下,我們可以有一個嵌套結構:

registrationForm = new FormGroup({
    'personalDetailsForm': new FormGroup({
        'name': new FormControl()
    })
})

你可以閱讀更多關於 FormGroup 在 Angular 文檔中。

讓我把你的注意力帶回到我們的用例上。

接下來,我們需要關聯這些FormControl 對象添加到 HTML 表單中的字段。

<form [formGroup]="registrationForm">
<div class="form-group">
  <label for="name">Name</label>
  <input type="text" class="form-control" id="name"
         [formControlName]="name">
</div>

<div class="form-group">
  <label for="username">Username</label>
  <input type="text" class="form-control" id="username"
         [formControlName]="username">
</div>
<form>

這裡我們應用了 formGroup 指令並將其與 FormGroup 關聯 對象 registrationForm 我們在 component 中創建的 .我們還關聯了 formControlName 帶有相應 FormControl 的指令 對象 nameusername .

注意 :構建響應式表單的指令 在 ReactiveFormsModule 中定義 .所以如果你得到一個錯誤,比如:

Can't bind to formGroup

...那麼您應該檢查您是否已導入該 ReactiveFormsModule 在你的主模塊 app.module.ts .

反應形式的驗證

在反應形式中,我們不傳遞 ngModel 指令,我們也不使用 HTML5 驗證屬性。我們在創建 FormControl 的對象時指定驗證器 在組件本身中。

這是 FormControl 的簽名 類:

class FormControl extends AbstractControl {
    constructor(formState: any = null, validatorOrOpts?: ValidatorFn | AbstractControlOptions | ValidatorFn[], asyncValidator?: AsyncValidatorFn | AsyncValidatorFn[])

    // ...
}

我們可以看到第一個參數是控件的初始狀態,可以保持為空,即 '' .第二個參數是ValidatorFn .

FormControl 添加內置驗證器函數 我們可以傳遞給它適當的 ValidatorFn .對於以下示例,我們使用了以下內置驗證器 required , minLength , 和 maxLength - :

registrationForm = new FormGroup({
    'name': new FormControl('Enter your name', [
        Validators.required,
        Validators.minLength(2),
        Validators.maxLength(30)
    ]),
    'username': new FormControl('', Validators.required),
})

注意 :您需要導入 Validators 在組件中。

另請注意,與模板驅動的表單不同,我們不使用驗證屬性 .我們使用各自的 ValidatorFnValidators.required , Validators.minLength(2) 等。您的代碼編輯器可能會為所有 ValidatorFn 提供自動完成功能 輸入 Validators 的那一刻 後跟一個點 . .

我們可以回到模板 並編寫驗證消息:

<form [formGroup]="registrationForm">
<div class="form-group">
  <label for="name">Name</label>
  <input type="text" class="form-control" id="name"
         [formControlName]="name">
  <div *ngIf="registrationForm.get('name').invalid && (registrationForm.get('name').dirty || registrationForm.get('name').touched)"
    class="alert alert-danger">
    <div *ngIf="registrationForm.get('name').errors.required">
       Name is required.
    </div>
    <div *ngIf="registrationForm.get('name').errors.minlength">
       Name cannot be more than 30 characters long.
    </div>
    <div *ngIf="registrationForm.get('name').errors.minlength">
       Name must be at least 2 characters long.
    </div>
  </div>
</div>

<div class="form-group">
  <label for="username">Username</label>
  <input type="text" class="form-control" id="username"
         [formControlName]="username">
</div>
<form>

響應式表單的自定義驗證器

我們需要編寫自定義驗證器函數 與我們為 模板驅動 所做的相同 表格部分。我們可以使用相同的自定義驗證器函數 UserRegistrationFormValidators.usernameShouldBeValid響應式表單的組件中

registrationForm = new FormGroup({
    'name': new FormControl('Enter your name', [
        Validators.required,
        Validators.minLength(2),
        Validators.maxLength(30)
    ]),
    'username': new FormControl('', [
        Validators.required,
        UserRegistrationFormValidators.usernameShouldBeValid
    ]),
})

結論

在本教程中,我們探討了處理用戶輸入的兩種不同方式——模板驅動和反應式表單。我們學習瞭如何對兩種類型的表單進行驗證。最後,我們還編寫了自定義驗證器函數並將其包含在內置驗證器中。

正如我們所見,Angular 對錶單有很好的支持,並提供了一些底層有用的特性來驗證表單。使用 Angular 表單提供每一個功能超出了本教程的範圍。您可以閱讀 Angular 文檔以獲取完整信息。


Tutorial JavaScript 教程
  1. 我如何免費託管我的流行語驅動的博客

  2. 反轉二叉樹 - 谷歌面試問題

  3. no-data 部分首先加載,然後顯示 v-data-table 中的數據

  4. Node.js 和 Jest:測試 promise 循環,計算函數被調用的次數

  5. 採訪 bugtrackers.io

  6. 使用 github 操作發布無服務器應用程序

  7. 使用現代云進行現代 Web 開發

  1. JavaScript 中的類型、值和變量

  2. 我在項目中使用的所有 useState 用例。

  3. 如何使用 RxJS 正確地滾動到底部行為

  4. 解析我的 json 以獲取值 - 從 Xcode 發送到 JS 前端的 json

  5. 通過重構 React 組件學習公共類字段語法

  6. Python VS Javascript 中的類

  7. 按名稱而不是索引獲取document.styleSheets?

  1. 使用 cypress JS 從一系列元素中獲取文本到數組

  2. 更多網絡開發片段

  3. Node.js 與 Golang:哪個最適合您的項目?

  4. 使用 Cypress 進行 API 測試:第 1 部分 - 設置