2018 年 3 月

第 33 卷,第 3 期

本文章是由機器翻譯。

程式設計師雜談 - 如何使用 MEAN:驗證 Angular

Ted Neward |2018 年 3 月

Ted Neward歡迎回來,MEANers。

在前一個資料行,我啟動查看 Angular 的表單和輸入的支援。雙向繫結所花費的最上層的計費,但如何驗證輸入的任何意義,請確定喇叭有第一個和最後一個名稱,例如,而不只是空字串-留下。本月份的資料行中,我們需要修正,因為不需要驗證的資料輸入基本上只會造成使用者灌注記憶體回收,到您的系統,讓您找出。

因此,我們大多數都知道,會不正確。Like、 Really Really Bad™ 商標層級。

SpeakerUI Redux

最後一個資料行,我 ditched SpeakerEdit 元件,以利於 SpeakerUI 環繞喇叭的模型執行個體,並知道 — 根據什麼傳遞到它,是否處於唯讀狀態檢視喇叭或可編輯狀態。它會使用兩個 < d i v > 區段 (其中隱藏視中元件的狀態而定) UI 繼續相異 (請參閱圖 1)。[唯讀] 區段不需驗證,當然,因為沒有使用者輸入。它是可編輯的區段我們這裡的顧慮。

圖 1 SpeakerUI 元件

<form #speakerForm="ngForm">
  <div [hidden]="readonly">
    FirstName: <input name="firstName" type="text"
      [(ngModel)]="model.firstName"><br>
    LastName:  <input name="lastName" type="text"
      [(ngModel)]="model.lastName"><br>
      Subjects: {{model.subjects}}<br>
    <button (click)="save()"
      [disabled]="!speakerForm.form.dirty">Save</button>
    <button (click)="cancel()"
      [disabled]="!cancellable(speakerForm)">Cancel</button>
    <br><span>{{diagnostic}}</span>
  </div>
  ...
</form>

請注意第一件事是,過去一個月的資料行,這之間移動了邏輯來判斷是否編輯模式可以取消 (請注意 [取消] 按鈕的方式停用屬性繫結) 上的元件本身的方法。這可能有點大材小用,在此案例中,但它示範了 Angular 很重要的層面: 您沒有執行所有動作範本本身直接在 UI 邏輯。應該取消邏輯變得很複雜,範本中有,可能是個好主意,但是我們必須將表單物件 (speakerForm 物件定義上個月) 可以在元件的程式碼中使用。

需要使用新的模組已不存在的元件中的其中一個:NgForm。

NgForm

NgForm 是專為使用表單定義中 Angular 的類別。它包含在個別的模組與其餘的角度的核心,因此需要擷取獨立匯入:

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

當使用表單在執行階段、 Angular 會建構物件的集合,代表各種控制項和表單本身,並使用它來進行驗證和其他處理。此物件的集合通常為了方便起見,在幕後會隱藏起來,但是永遠是用於角度開發人員可使用。

一旦傳遞至可取消的方法,您可以使用表單物件來檢查透過許多屬性在表單的狀態。NgForm 中途,定義無效、 初始化、 接觸、 不變且有效的屬性,以表示廣泛的不同使用者互動狀態的表單。示範用途,我要將更多診斷行加入至表單的可編輯的區段:

<br>Pristine: {{speakerForm.form.pristine}}
Dirty: {{speakerForm.form.dirty}}
Touched: {{speakerForm.form.touched}}
Untouched: {{speakerForm.form.untouched}}
Invalid: {{speakerForm.form.invalid}}
Valid: {{speakerForm.form.valid}}

這些只會顯示每種狀態,當使用者互動的表單,和說明什麼每項各代表。比方說,「 原貌 」 表示 — 相當逐字: 使用者尚未接觸到的任何方式表單。只要按一下 (或接觸,行動裝置上) 編輯欄位,使資料指標會顯示沒有足以轉譯為 「 接觸。 「 表單 不過,如果沒有輸入之中,即使表單"碰觸 」,並仍然"原有。 」 然後依此類推。

有效性,因為將會預期,建議使用者違反某種曾要求開發人員的資料輸入條件約束。角度來建置出標準 HTML5 有效性條件約束,因此,比方說,如果您決定第一個和最後一個名稱,必須喇叭,您可能會直接使用"required"屬性上的編輯欄位:

FirstName: <input name="firstName" type="text"
  [(ngModel)]="model.firstName" required><br>
LastName:  <input name="lastName" type="text"
  [(ngModel)]="model.lastName" required><br>

如此一來,如果使用者編輯現有的喇叭,並清除任一 firstName lastName 完全編輯欄位,或,無效的狀態翻轉為 true,且有效的狀態設為 false,因為 Angular 可以辨認的所需的旗標,也會顯示。話雖如此,雖然 Angular 不會執行任何其他項目,根據預設,Angular 未提供任何內建的 UI 來表示的格式無效。它是由開發人員在此欄位必須注意某些方式中的使用者發出信號。作法是在有許多種,所有相依於開發人員使用的 UI 支援。例如,常會使用啟動程序 CSS framework 旗標設為需要注意的著色 (或它的某些部分) 的表單欄位時紅色。或者,是很常見的隱藏的文字範圍下方或之後時,會以某種方式,違反條件約束和繫結範圍的隱藏屬性,以在表單的狀態會顯示欄位。

但會引發一點 — 您想要知道哪些控制項在表單中的無效,以便您可以將繫結至控制項的直接意見反應。幸運的是,NgForm 有 NgControl 物件的陣列,會提供控制項的屬性,而且中 (例如 firstName 和 lastName) 的表單定義的每個控制項必須 NgControl 執行個體來表示。因此,您可以參考這些控制項內的物件直接隱藏的屬性範本運算式:

FirstName: <input name="firstName" type="text"
  [(ngModel)]="model.firstName" required>
<span [hidden]="speakerForm.controls.firstName.valid">
  Speakers must have a first name</span><br>
LastName:  <input name="lastName" type="text"
  [(ngModel)]="model.lastName" required>
<span [hidden]="speakerForm.controls.firstName.valid">
  Speakers must have a first name</span><br>

Candor 會強迫我承認這段程式碼具有難以察覺的問題,當執行時,它會產生一些在執行階段錯誤。這是因為在元件的最早階段 NgForm 尚未建構 NgControl 物件的集合,使其運算式、 speakerForm.controls.firstName,會是未定義。

若要避免這個問題的簡易方式是定義控制項的本機範本變數而不是瀏覽表單的控制項陣列,並使用 * ngIf 指示詞來測試以查看接觸或已變更,而且如果是,是否有效:

FirstName: <input name="firstName" type="text"
  [(ngModel)]="model.firstName" #firstName="ngModel"
  required>
<div *ngIf="firstName.invalid &&
            (firstName.dirty || firstName.touched)">
  <div *ngIf="firstName.errors.required">
    A first name is required.
  </div>
</div>

基本上,這樣就不需要透過 speakerForm 處理,但卻很有幫助 speakerForm 物件是在執行階段,我們存取雖然伴隨著某些注意事項。

自訂驗證

在 HTML5 標準不會在其中定義驗證這些情況下,您想要或需要角度允許您撰寫自訂驗證程式,可以叫用它來測試有問題的欄位。例如,多年前,讓我們假設我有不正確的經驗與名為 Josh 喇叭。我不想要 Josh。永遠不會執行的方法。我不在意讓 guy 是我們的資料庫的一部分,所以我想要自訂的表單驗證程式不允許特定的輸入。(很明顯地,這是相當 pedantic 的範例,但這裡的概念保留幾乎所有種類的驗證程式,可以想像)。

如同其他的驗證,Angular 我想要再試一次 「 點選 「 HTML 語法盡可能,這表示讓 forbiddenName 驗證程式應該看起來像是任何其他的 HTML 驗證規則,甚至是自訂驗證程式會出現 HTML5 驗證程式,例如:

FirstName: <input name="firstName" type="text"
  [(ngModel)]="model.firstName" #firstName="ngModel"
  required forbiddenName="josh">

內這個範本時,您可以只是加入必要 * ngIf 指示詞來測試是否表單包含禁止的名稱指定,和如果是這樣,顯示特定的錯誤訊息:

<div *ngIf="firstName.invalid &&
            (firstName.dirty || firstName.touched)">
  <div *ngIf="firstName.errors.required">
    A first name is required.
  </div>
  <div *ngIf="firstName.errors.forbiddenName">
    NO JOSH!
  </div>
</div>

那里。應該保留出任何不必要的喇叭 (看看您 Josh)。

自訂驗證程式指示詞

若要這麼做,Angular 需要我們為角度指示詞,也就是連結到 HTML 尋找語法元素,例如 forbiddenName 指示詞中的輸入的欄位,或需要或甚至一些角度程式碼的方法中撰寫驗證程式 * ngIf。指示詞是相當強大,和相當多超過我在這裡的瀏覽完整的聊天室。但我至少可說明驗證程式運作方式,讓我們開始建立新的指示詞,使用 「 ng 產生指示詞 ForbiddenValidator 」 在命令列,,並讓它 scaffold 出禁止-validator.directive.ts:

import { Directive } from '@angular/core';
@Directive({
  selector: '[appForbiddenValidator]'
})
export class ForbiddenValidatorDirective {
  constructor() { }
}

@Directive 中的選取器是您想要使用 HTML 範本中的語法和老實說,appForbiddenValidator 不會取得真正賽的核心。它應該是稍微清除在其使用方式,例如 forbiddenName 中的項目。此外,指示詞必須將感受到現有的驗證程式集合,將不會太多詳細資料,@Directive 的提供者參數包含要提供給較大 ForbiddenValidatorDirective 需要重複使用驗證程式的集合:

@Directive({
  selector: '[forbiddenName]',
  providers: [{provide: NG_VALIDATORS,
               useExisting: ForbiddenValidatorDirective,
               multi: true}]
})

接下來,需要實作驗證程式的介面,提供單一方法、 驗證,其指示詞-無法猜到,驗證必須完成時叫用。不過,驗證函式的結果不正確的驗證,但要用來執行驗證本身的函式的成功/失敗結果的某種:

export class ForbiddenValidatorDirective implements Validator {
  @Input() forbiddenName: string;
  validate(control: AbstractControl): {[key: string]: any} {
    if (this.forbiddenName) {
      const nameRe = new RegExp(this.forbiddenName, 'i');
      const forbidden = nameRe.test(control.value);
      return forbidden ? {'forbiddenName': {value: control.value}} : null;
    } else {
      return null;
    }
  }
}

基本上,Angular 逐步解說的驗證程式清單,如果全部都傳回 null,則所有項目是 kosher,且所有輸入會被都視為有效。如果其中任何傳回以外的任何項目,它已被視為驗證錯誤組的一部分,並加入至範本中所參考的錯誤集合 * ngIf 陳述式前面。

驗證程式 forbiddenName 值,這是傳遞的內容中的指示詞的使用方式,則會進行驗證 — 元件的輸入用來建構 RegExp 執行個體 (不區分大小寫的相符項目使用"i"),並接著 RegExp 測試方法用來檢查控制項的值是否符合 name-which-shall-not-be-accepted。若是如此,一組會建構索引鍵的 forbiddenName (即項目範本已使用先前來判斷是否要顯示的錯誤訊息,請記住),與控制項的輸入值。否則,指示詞的指針回 null,且表單的驗證程式的其餘部分會引發。如果全部都送回 null,所有項目是合適。

總結

角度的驗證支援是,如您所見,相當廣泛且功能完整的。它會建置出找到 HTML5 的瀏覽器,但提供某種程度的擴充和強大時所需的執行階段控制項支援標準 HTML 驗證支援。大部分的應用程式會尋找足夠用於大部分用途而言,是內建的驗證程式,但讓其可以建立自訂驗證器,表示 Angular 可以很複雜,例如必要時處理使用者輸入。(這是很好,因為使用者不斷地尋找新方法來嘗試輸入到系統的記憶體回收。我責怪 Josh 該。) 仍有某些"@angular/forms 」 模組內前隱藏我們在這裡,即可隨時調整的多個意外。

祝各位寫程式愉快!


Ted Neward是西雅圖 polytechnology 顧問、 演講者和指導,目前正在處理的開發人員關聯在主管為Smartsheet.com。他已寫入有大量的發行項,撰寫和撰寫共置的數十個書籍,並說出世界各地。連線到他處ted@tedneward.com或讀取在他的部落格blogs.tedneward.com

非常感謝下列的 Microsoft 技術專家:Garvice Eakins


MSDN Magazine 論壇中的這篇文章的討論