真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

Angular2+表單之模板驅(qū)動型表單的示例分析

這篇文章主要為大家展示了“Angular 2+表單之模板驅(qū)動型表單的示例分析”,內(nèi)容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領(lǐng)大家一起研究并學(xué)習(xí)一下“Angular 2+表單之模板驅(qū)動型表單的示例分析”這篇文章吧。

為惠城等地區(qū)用戶提供了全套網(wǎng)頁設(shè)計制作服務(wù),及惠城網(wǎng)站建設(shè)行業(yè)解決方案。主營業(yè)務(wù)為網(wǎng)站建設(shè)、成都網(wǎng)站設(shè)計、惠城網(wǎng)站設(shè)計,以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務(wù),秉承以專業(yè)、用心的態(tài)度為用戶提供真誠的服務(wù)。我們深信只要達(dá)到每一位用戶的要求,就會得到認(rèn)可,從而選擇與我們長期合作。這樣,我們也可以走得更遠(yuǎn)!

模版驅(qū)動的表單

模版驅(qū)動的表單和 AngularJS 對于表單的處理類似,把一些指令(比如 ngModel )、數(shù)據(jù)值和行為約束(比如 require 、 minlength 等等)綁定到模版中(模版就是組件元數(shù)據(jù) @Component 中定義的那個 template ),這也是模版驅(qū)動這個叫法的來源。總體來說,這種類型的表單通過綁定把很多工作交給了模版。

模版驅(qū)動的例子

還是用例子來說話,比如我們有一個用戶注冊的表單,用戶名就是 email ,還需要填的信息有:住址、密碼和重復(fù)密碼。這個應(yīng)該是比較常見的一個注冊時需要的信息了。那么我們第一步來建立領(lǐng)域模型:

// src/app/domain/index.ts
export interface User {
 // 新的用戶id一般由服務(wù)器自動生成,所以可以為空,用 ? 標(biāo)示
 id?: string; 
 email: string;
 password: string;
 repeat: string;
 address: Address;
}
export interface Address {
 province: string; // 省份
 city: string; // 城市
 area: string; // 區(qū)縣
 addr: string; // 詳細(xì)地址
}

接下來我們建立模版文件,一個最簡單的 HTML 模版,先不增加任何的綁定或事件處理:



 
 
     
           
 注冊

渲染之后的效果就像下面這樣:

Angular 2+表單之模板驅(qū)動型表單的示例分析 

簡單的Form

數(shù)據(jù)綁定

對于模版驅(qū)動型的表單處理,我們首先需要在對應(yīng)的模塊中引入 FormsModule ,這一點(diǎn)千萬不要忘記了。

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from "@angular/forms";
import { TemplateDrivenComponent } from './template-driven/template-driven.component';
@NgModule({
 imports: [
 CommonModule,
 FormsModule
 ],
 exports: [TemplateDrivenComponent],
 declarations: [TemplateDrivenComponent]
})
export class FormDemoModule { }
進(jìn)行模版驅(qū)動類型的表單處理的一個必要步驟就是建立數(shù)據(jù)的雙向綁定,那么我們需要在組件中建立一個類型為 User 的成員變量并賦初始值。
// template-driven.component.ts
// 省略元數(shù)據(jù)和導(dǎo)入的類庫信息
export class TemplateDrivenComponent implements OnInit {
 user: User = {
 email: '',
 password: '',
 repeat: '',
 address: {
  province: '',
  city: '',
  area: '',
  addr: ''
 }
 };
 // 省略其他部分
}

有了這樣一個成員變量之后,我們在組件模版中就可以使用 ngModel 進(jìn)行綁定了。

令人困惑的 ngModel

我們在 Angular 中可以使用三種形式的 ngModel 表達(dá)式: ngModel , [ngModel] 和 [(ngModel)] 。但無論那種形式,如果你要使用 ngModel 就必須為該控件(比如下面的 input )指定一個 name 屬性,如果你忘記添加 name 的話,多半你會看到下面這樣的錯誤:

ERROR Error: Uncaught (in promise): Error: If ngModel is used within a form tag, either the name attribute must be set or the form control must be defined as 'standalone' in ngModelOptions.

ngModel 和 FormControl

假如我們使用的是 ngModel ,沒有任何中括號小括號的話,這代表著我們創(chuàng)建了一個 FormControl 的實例,這個實例將會跟蹤值的變化、用戶的交互、驗證狀態(tài)以及保持視圖和領(lǐng)域?qū)ο蟮耐降裙ぷ鳌?/p>

如果我們將這個控件放在一個 Form 表單中, ngModel 會自動將這個 FormControl 注冊為 Form 的子控件。下面的例子中我們在

中加上了 ngForm 指令,聲明這是一個 Angular 可識別的表單,而 ngModel 會將 注冊成表單的子控件,這個子控件的名字就是 email ,而且 ngModel 會基于這個子控件的值去綁定表單的的值,這也是為什么需要顯式聲明 name 的原因。

其實在我們導(dǎo)入 FormsModule 的時候,所有的 標(biāo)簽都會默認(rèn)的被認(rèn)為是一個 NgForm ,因此我們并不需要顯式的在標(biāo)簽中寫 ngForm 這個指令。



 

這一切現(xiàn)在都是不可見的,所以大家可能還是有些困惑,那么下面我們將其“可視化”,這需要我們引用一下表單對象,所以我們使用 #f="ngForm" 以便我們可以在模版中輸出表單的一些特性。



 ...


{{f.value | json}}

這時如果我們在 email 中輸入 sss ,可以看到下圖的以 JSON 形式出現(xiàn)的表單值:

Angular 2+表單之模板驅(qū)動型表單的示例分析 

控件的輸入值同步到了表單的值中

單向數(shù)據(jù)綁定

那么接下來,我們看看 [ngModel] 有什么用?如果我們想給控件設(shè)置一個初始值怎么辦呢,這時就需要進(jìn)行一個單向綁定,方向是從組件到視圖。我們可以做的是在初始化 User 的時候,將 email 屬性設(shè)置成 wang@163.com

user: User = {
 email: 'wang@163.com',
 ...
 };

而且在模版中使用 [ngModel]="user.email" 進(jìn)行單向綁定,這個語法其實和普通的屬性綁定是一樣的,用中括號標(biāo)示這是一個要進(jìn)行數(shù)據(jù)綁定的屬性,等號右邊是需要綁定的值(這里是 user.email )。那么我們就可以得到下面這樣的輸出了, email 的初始值被綁定成功!

單向數(shù)據(jù)綁定

Angular 2+表單之模板驅(qū)動型表單的示例分析 

雙向數(shù)據(jù)綁定

但上面的例子存在一個問題,數(shù)據(jù)的綁定是單向的,也就是說,在輸入框進(jìn)行輸入的時候,我們的 user 的值不會隨之改變的。為了更好的說明,我們將 user 和 表單的值同時輸出

 user:  {{user | json}}
 表單: {{f.value | json}}

此時我們將默認(rèn)的電子郵件改成 wang@gmail.com 的話,表單的值是改變了,但 user 并未改變。

Angular 2+表單之模板驅(qū)動型表單的示例分析 

輸入的值影響了表單,但不會影響領(lǐng)域?qū)ο?/p>

如果我們希望的是在輸入時,這個輸入的值也反向的影響我們的 user 對象的值的話,那就需要用到雙向綁定了,也就是 [(ngModel)] 需要上場了。

Angular 2+表單之模板驅(qū)動型表單的示例分析 

表單和領(lǐng)域?qū)ο蟮闹当3至送?/p>

無論如何,這個 [()] 表達(dá)真是很奇怪的樣子,其實這個表達(dá)是一個語法糖。只要我們知道下面的兩種寫法是等價的,我們就會很清楚的理解了:用這個語法糖你就不用既寫數(shù)據(jù)綁定又寫事件綁定了。


ngModelGroup 是什么鬼?

如果我們仔細(xì)觀察上面的輸出的話,會發(fā)現(xiàn)一個問題: user 中是有一個嵌套對象 address 的,而表單中沒有嵌套對象的。如果要實現(xiàn)表單中的結(jié)構(gòu)和領(lǐng)域?qū)ο蟮慕Y(jié)構(gòu)一致的話,我們就得請出 ngModelGroup 了。 ngModelGroup 會創(chuàng)建并綁定一個 FormGroup 到該 DOM 元素。 FormGroup 又是什么呢?簡單來說,是一組 FormControl。


 
 
 
 

這樣的話,我們再來看一下輸出,現(xiàn)在就完全一致了:

Angular 2+表單之模板驅(qū)動型表單的示例分析 

表單和領(lǐng)域?qū)ο蟮慕Y(jié)構(gòu)也完全一致了

數(shù)據(jù)驗證

模版驅(qū)動型的表單的驗證也是主要由模版來處理的,在看怎么使用之前,需要界定一下驗證規(guī)則:

當(dāng)然除了這幾個規(guī)則,我們還希望在表單未驗證通過時提交按鈕是不可用的。


 
 
     
   注冊

Angular 中有幾種內(nèi)建支持的驗證器( Validators )

如果我們想看到結(jié)果的話,我們可以在模版中加上下面的代碼,將錯誤以 JSON 形式輸出即可。

 email 驗證: {{f.controls.email?.errors | json}}

我們看到,如果不填電子郵件的話,錯誤的 JSON 是 {"required": true} ,這告訴我們目前有一個 required 的規(guī)則沒有被滿足。

Angular 2+表單之模板驅(qū)動型表單的示例分析 

驗證結(jié)果

當(dāng)我們輸入一個字母 w 之后,就會發(fā)現(xiàn)錯誤變成了下面的樣子。這是因為我們對于 email 應(yīng)用了多個規(guī)則,當(dāng)必填項滿足后,系統(tǒng)會繼續(xù)檢查其他驗證結(jié)果。

{ 
"pattern": 
 { 
  "requiredPattern": "^([a-zA-Z0-9]+[_|_|.]?)*[a-zA-Z0-9]+@([a-zA-Z0-9]+[_|_|.]?)*[a-zA-Z0-9]+.[a-zA-Z]{2,4}$", 
  "actualValue": "w" 
 } 
}

通過幾次實驗,我們應(yīng)該可以得出結(jié)論,當(dāng)驗證未通過時,驗證器返回的是一個對象, key 為驗證的規(guī)則(比如 required, minlength 等),value 為驗證結(jié)果。如果驗證通過,返回的是一個 null 。

知道這一點(diǎn)后,我們其實就可以做出驗證出錯的提示了,為了方便引用,我們還是導(dǎo)出 ngModel 到一個 email 引用,然后就可以訪問這個 FormControl 的各個屬性了:驗證的狀態(tài)( valid/invalid )、控件的狀態(tài)(是否獲得過焦點(diǎn) -- touched/untouched,是否更改過內(nèi)容 -- pristine/dirty 等)



 email 是必填項
 email 格式不正確

自定義驗證

內(nèi)建的驗證器對于兩個密碼比較的這種驗證是不夠的,那么這就需要我們自己定義一個驗證器。對于響應(yīng)式表單來說,會比較簡單一些,但對于模版驅(qū)動的表單,這需要我們實現(xiàn)一個指令來使這個驗證器更通用和更一致。因為我們希望實現(xiàn)的樣子應(yīng)該是和 required 、 minlength 等差不多的形式,比如下面這個樣子 validateEqual="repeat"

     

那么要實現(xiàn)這種形式的驗證的話,我們需要建立一個指令,而且這個指令應(yīng)該實現(xiàn) Validator 接口。一個基礎(chǔ)的框架如下:

import { Directive, forwardRef } from '@angular/core';
import { NG_VALIDATORS, Validator, AbstractControl } from '@angular/forms';
@Directive({
 selector: '[validateEqual][ngModel]',
 providers: [
 { 
  provide: NG_VALIDATORS, 
  useExisting: forwardRef(()=>RepeatValidatorDirective), 
  multi: true 
 }
 ]
})
export class RepeatValidatorDirective implements Validator{
 constructor() { }
 validate(c: AbstractControl): { [key: string]: any } {
 return null;
 }
}

我們還沒有開始正式的寫驗證邏輯,但上面的框架已經(jīng)出現(xiàn)了幾個有意思的點(diǎn):

1.Validator 接口要求必須實現(xiàn)的一個方法是 validate(c: AbstractControl): ValidationErrors | null; 。這個也就是我們前面提到的驗證正確返回 null 否則返回一個對象,雖然沒有嚴(yán)格的約束,但其 key 一般用于表示這個驗證器的名字或者驗證的規(guī)則名字,value 一般是失敗的原因或驗證結(jié)果。

2.和組件類似,指令也有 selector 這個元數(shù)據(jù),用于選擇那個元素應(yīng)用該指令,那么我們這里除了要求 DOM 元素應(yīng)用 validateEqual 之外,還需要它是一個 ngModel 元素,這樣它才是一個 FormControl,我們在 validate 的時候才是合法的。

3.那么那個 providers 里面那些面目可憎的家伙又是干什么的呢? Angular 對于在一個 FormControl 上執(zhí)行驗證器有一個內(nèi)部機(jī)制: Angular 維護(hù)一個令牌為 NG_VALIDATORS 的 multi provider (簡單來說,Angular 為一個單一令牌注入多個值的這種形式叫 multi provider )。所有的內(nèi)建驗證器都是加到這個 NG_VALIDATORS 的令牌上的,因此在做驗證時,Angular 是注入了 NG_VALIDATORS 的依賴,也就是所有的驗證器,然后一個個的按順序執(zhí)行。因此我們這里也把自己加到這個 NG_VALIDATORS 中去。

4.但如果我們直接寫成 useExisting: RepeatValidatorDirective 會出現(xiàn)一個問題, RepeatValidatorDirective 還沒有生成,你怎么能在元數(shù)據(jù)中使用呢?這就需要使用 forwardRef 來解決這個問題,它接受一個返回一個類的函數(shù)作為參數(shù),但這個函數(shù)不會立即被調(diào)用,而是在該類聲明后被調(diào)用,也就避免了 undefined 的狀況。

下面我們就來實現(xiàn)這個驗證邏輯,由于密碼和確認(rèn)密碼有主從關(guān)系,并非完全的平行關(guān)系。也就是說,密碼是一個基準(zhǔn)對比對象,當(dāng)密碼改變時,我們不應(yīng)該提示密碼和確認(rèn)密碼不符,而是應(yīng)該將錯誤放在確認(rèn)密碼中。所以我們給出另一個屬性 reverse 。

export class RepeatValidatorDirective implements Validator{
 constructor(
 @Attribute('validateEqual') public validateEqual: string,
 @Attribute('reverse') public reverse: string) { }
 private get isReverse() {
 if (!this.reverse) return false;
 return this.reverse === 'true' ? true: false;
 }
 validate(c: AbstractControl): { [key: string]: any } {
 // 控件自身值
 let self = c.value;
 // 要對比的值,也就是在 validateEqual=“ctrlname” 的那個控件的值
 let target = c.root.get(this.validateEqual);
 // 不反向查詢且值不相等
 if (target && self !== target.value && !this.isReverse) {
  return {
  validateEqual: true
  }
 }
 // 反向查詢且值相等
 if (target && self === target.value && this.isReverse) {
  delete target.errors['validateEqual'];
  if (!Object.keys(target.errors).length) target.setErrors(null);
 }
 // 反向查詢且值不相等
 if (target && self !== target.value && this.isReverse) {
  target.setErrors({
   validateEqual: true
  })
 }
 return null;
 }
}

這樣改造后,我們的模版文件中對于密碼和確認(rèn)密碼的驗證器如下:



完成后的驗證錯誤提示

Angular 2+表單之模板驅(qū)動型表單的示例分析 

表單的提交

表單的提交比較簡單,綁定表單的 ngSubmit 事件即可

但需要注意的一點(diǎn)是,button如果不指定類型的話,會被當(dāng)做 type="submit" ,所以當(dāng)按鈕不是進(jìn)行提交表單的話,需要顯式指定 type="button" 。而且如果遇到點(diǎn)擊提交按鈕頁面刷新的情況的話,意味著默認(rèn)的表單提交事件引起了瀏覽器的刷新,這種時候需要阻止事件冒泡。

onSubmit({value, valid}, event: Event){ 
 if(valid){
 console.log(value);
 }
 event.preventDefault();
}

以上是“Angular 2+表單之模板驅(qū)動型表單的示例分析”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對大家有所幫助,如果還想學(xué)習(xí)更多知識,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!


文章名稱:Angular2+表單之模板驅(qū)動型表單的示例分析
分享地址:http://weahome.cn/article/jpdhgg.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部