掃二維碼與項(xiàng)目經(jīng)理溝通
我們?cè)谖⑿派?4小時(shí)期待你的聲音
解答本文疑問/技術(shù)咨詢/運(yùn)營(yíng)咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流
本教程將為你演示如何創(chuàng)建一個(gè)模板驅(qū)動(dòng)表單,它的控件元素綁定到數(shù)據(jù)屬性,并通過輸入驗(yàn)證來保持?jǐn)?shù)據(jù)的完整性和樣式,以改善用戶體驗(yàn)。

當(dāng)在模板中進(jìn)行更改時(shí),模板驅(qū)動(dòng)表單會(huì)使用雙向數(shù)據(jù)綁定來更新組件中的數(shù)據(jù)模型,反之亦然。
Angular 支持兩種交互式表單的設(shè)計(jì)方法。你可以使用 Angular 中的
模板語法和指令,以及本教程中描述的表單專用指令和技巧編寫模板來構(gòu)建表單,或者你可以使用響應(yīng)式方式(或叫模型驅(qū)動(dòng)方式)來構(gòu)建表單。
模板驅(qū)動(dòng)表單適用于小型或簡(jiǎn)單的表單,而響應(yīng)式表單則更具伸縮性,適用于復(fù)雜表單。
你可以用 Angular 模板來構(gòu)建各種表單,比如登錄表單、聯(lián)系人表單和幾乎所有的業(yè)務(wù)表單。你可以創(chuàng)造性地對(duì)控件進(jìn)行布局并把它們綁定到對(duì)象模型的數(shù)據(jù)上。你可以指定驗(yàn)證規(guī)則并顯示驗(yàn)證錯(cuò)誤,有條不紊地啟用或禁用特定控件,觸發(fā)內(nèi)置的視覺反饋等等。
本教程將向你展示如何通過一個(gè)簡(jiǎn)化的范例表單來從頭構(gòu)建一個(gè)表單,就像“英雄之旅”教程的中用一個(gè)表單來講解這些技巧一樣。
運(yùn)行或下載范例應(yīng)用:現(xiàn)場(chǎng)演練 / 下載范例。
本教程將教你如何執(zhí)行以下操作:
ngModel ?創(chuàng)建雙向數(shù)據(jù)綁定,以便讀寫輸入控件的值模板驅(qū)動(dòng)表單依賴于 ?FormsModule ?定義的指令。
|
指令 |
詳細(xì)信息 |
|---|---|
NgModel | 會(huì)協(xié)調(diào)其附著在的表單元素中的值變更與數(shù)據(jù)模型中的變更,以便你通過輸入驗(yàn)證和錯(cuò)誤處理來響應(yīng)用戶輸入。 |
NgForm | 會(huì)創(chuàng)建一個(gè)頂級(jí)的 |
NgModelGroup | 會(huì)創(chuàng)建 |
英雄雇傭管理局使用本指南中的范例表單來維護(hù)英雄的個(gè)人信息。畢竟英雄也要工作啊。這個(gè)表單有助于該機(jī)構(gòu)將正確的英雄與正確的危機(jī)匹配起來。
該表單突出了一些易于使用的設(shè)計(jì)特性。比如,這兩個(gè)必填字段的左邊是綠色條,以便讓它們醒目。這些字段都有初始值,所以表單是有效的,并且 Submit 按鈕也是啟用的。
當(dāng)你使用這個(gè)表單時(shí),你將學(xué)習(xí)如何包含驗(yàn)證邏輯,如何使用標(biāo)準(zhǔn) CSS 自定義表達(dá)式,以及如何處理錯(cuò)誤條件以確保輸入的有效性。比如,如果用戶刪除了英雄的名字,那么表單就會(huì)失效。該應(yīng)用會(huì)檢測(cè)已更改的狀態(tài),并以醒目的樣式顯示驗(yàn)證錯(cuò)誤。此外,Submit 按鈕會(huì)被禁用,輸入控件左側(cè)的“必填”欄也會(huì)從綠色變?yōu)榧t色。
在本教程中,你將使用以下步驟將一個(gè)范例表單綁定到數(shù)據(jù)并處理用戶輸入。
FormsModule?ngModel ?指令和雙向數(shù)據(jù)綁定語法把表單控件綁定到數(shù)據(jù)屬性。ngModel ?如何使用 CSS 類報(bào)告控件狀態(tài)ngModel ?可以訪問它們ngModel ?跟蹤輸入的有效性和控件的狀態(tài)。ngSubmit ?輸出屬性來處理表單提交。你可以根據(jù)這里提供的代碼從頭創(chuàng)建范例應(yīng)用,也可以查看 現(xiàn)場(chǎng)演練 / 下載范例。
Hero ?類,用于定義表單中所反映的數(shù)據(jù)模型。export class Hero {
constructor(
public id: number,
public name: string,
public power: string,
public alterEgo?: string
) { }
}
HeroFormComponent? 類中定義的。import { Component } from '@angular/core';
import { Hero } from '../hero';
@Component({
selector: 'app-hero-form',
templateUrl: './hero-form.component.html',
styleUrls: ['./hero-form.component.css']
})
export class HeroFormComponent {
powers = ['Really Smart', 'Super Flexible',
'Super Hot', 'Weather Changer'];
model = new Hero(18, 'Dr IQ', this.powers[0], 'Chuck Overstreet');
submitted = false;
onSubmit() { this.submitted = true; }
}該組件的 ?selector ?值為 “app-hero-form”,意味著你可以用 ?? 標(biāo)簽把這個(gè)表單放到父模板中。
const myHero = new Hero(42, 'SkyDog',
'Fetch any object at any distance',
'Leslie Rollover');
console.log('My hero is called ' + myHero.name); // "My hero is called SkyDog"這個(gè)演示使用虛擬數(shù)據(jù)來表達(dá) ?model ?和 ?powers?。在真正的應(yīng)用中,你會(huì)注入一個(gè)數(shù)據(jù)服務(wù)來獲取和保存實(shí)際數(shù)據(jù),或者把它們作為輸入屬性和輸出屬性進(jìn)行公開。
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
import { HeroFormComponent } from './hero-form/hero-form.component';
@NgModule({
imports: [
BrowserModule,
CommonModule,
FormsModule
],
declarations: [
AppComponent,
HeroFormComponent
],
providers: [],
bootstrap: [ AppComponent ]
})
export class AppModule { }
初始模板定義了一個(gè)帶有兩個(gè)表單組和一個(gè)提交按鈕的表單布局。表單組對(duì)應(yīng)于 Hero 數(shù)據(jù)模型的兩個(gè)屬性:name 和 alterEgo。每個(gè)組都有一個(gè)標(biāo)簽和一個(gè)用戶輸入框。
? 控件元素中包含了 HTML5 的 ?required ?屬性? 沒有控件元素,因?yàn)?nbsp;?alterEgo ?是可選的Submit 按鈕里面有一些用于樣式化的類。此時(shí),表單布局全都是純 HTML5,沒有綁定或指令。
container?,?form-group?,?form-control? 和 ?btn?。要使用這些樣式,就要在該應(yīng)用的樣式表中導(dǎo)入該庫。@import url('https://unpkg.com/[email protected]/dist/css/bootstrap.min.css');
powers ?列表是數(shù)據(jù)模型的一部分,在 ?HeroFormComponent ?內(nèi)部維護(hù)。Angular 的?NgForOf ?指令會(huì)遍歷這些數(shù)據(jù)值,以填充這個(gè) ?? 元素。
如果你現(xiàn)在正在運(yùn)行該應(yīng)用,你會(huì)看到選擇控件中的超能力列表。由于尚未將這些 input 元素綁定到數(shù)據(jù)值或事件,因此它們?nèi)匀皇强瞻椎模瑳]有任何行為。
下一步是使用雙向數(shù)據(jù)綁定把輸入控件綁定到相應(yīng)的 ?Hero ?屬性,這樣它們就可以通過更新數(shù)據(jù)模型來響應(yīng)用戶的輸入,并通過更新顯示來響應(yīng)數(shù)據(jù)中的程序化變更。
該 ?ngModel ?指令是由 ?FormsModule ?聲明的,它能讓你把模板驅(qū)動(dòng)表單中的控件綁定到數(shù)據(jù)模型中的屬性。當(dāng)你使用雙向數(shù)據(jù)綁定的語法 ?[(ngModel)]? 引入該指令時(shí),Angular 就可以跟蹤控件的值和用戶交互,并保持視圖與模型的同步。
hero-form.component.html?。? 標(biāo)記。[(ngModel)]="..."? 添加 ?ngModel ?指令。
TODO: remove this: {{model.name}}
這個(gè)例子中在每個(gè) input 標(biāo)記后面都有一個(gè)臨時(shí)的診斷插值 ?
{{model.name}}?,以顯示相應(yīng)屬性的當(dāng)前數(shù)據(jù)值。本提醒是為了讓你在觀察完這個(gè)雙向數(shù)據(jù)綁定后刪除這些診斷行。
當(dāng)你導(dǎo)入了 ?FormsModule ?時(shí),Angular 會(huì)自動(dòng)為模板中的 ?? 標(biāo)簽創(chuàng)建并附加一個(gè) ?NgForm ?指令。(因?yàn)?nbsp;?NgForm ?定義了一個(gè)能匹配 ?? 元素的選擇器 ?form?)。
要訪問 ?NgForm ?和表單的整體狀態(tài),就要聲明一個(gè)模板引用變量。
hero-form.component.html?。? 標(biāo)簽添加模板引用變量 ?#heroForm?,并把它的值設(shè)置如下。模板變量 ?heroForm ?現(xiàn)在是對(duì) ?NgForm ?指令實(shí)例的引用,該指令實(shí)例管理整個(gè)表單。
在添加和刪除字符時(shí),你可以看到它們從數(shù)據(jù)模型中出現(xiàn)和消失。比如:
用來顯示插值的診斷行證明了這些值確實(shí)從輸入框流向了模型,然后再返回。
在元素上使用 ?[(ngModel)]? 時(shí),必須為該元素定義一個(gè) ?name ?屬性。Angular 會(huì)用這個(gè)指定的名字來把這個(gè)元素注冊(cè)到父 ?? 元素上的 ?NgForm ?指令中。
這個(gè)例子中為 ?? 元素添加了一個(gè) ?name ?屬性,并把它的值設(shè)置為 “name”,用來表示英雄的名字。任何唯一的值都可以用,但最好用描述性的名稱。
[(ngModel)]? 綁定和 ?name ?屬性。json ?管道的新文本綁定。?json ?管道會(huì)把數(shù)據(jù)序列化為字符串。表單模板修改完畢后,應(yīng)如下所示:
{{ model | json }}
? 元素都有一個(gè) ?id ?屬性。?? 元素的 ?for ?屬性用它來把標(biāo)簽匹配到輸入控件。這是一個(gè)標(biāo)準(zhǔn)的 HTML 特性。? 元素都有一個(gè)必需的 ?name ?屬性,Angular 用它來注冊(cè)表單中的控件。如果你現(xiàn)在運(yùn)行該應(yīng)用并更改英雄模型的每個(gè)屬性,該表單可能會(huì)顯示如下:
通過表單頂部的診斷行可以確認(rèn)所有的更改都已反映在模型中。
{{ model | json }}? 的文本綁定了。控件上的 ?NgModel ?指令會(huì)跟蹤該控件的狀態(tài)。它會(huì)告訴你用戶是否接觸過該控件、該值是否發(fā)生了變化,或者該值是否無效。Angular 在控件元素上設(shè)置了特殊的 CSS 類來反映其狀態(tài),如下表所示。
|
狀態(tài) |
為 TRUE 時(shí)的類名 |
為 FALSE 時(shí)的類名 |
|---|---|---|
該控件已被訪問過。 | ng-touched | ng-untouched |
控件的值已被更改。 | ng-dirty | ng-pristine |
控件的值是有效的。 | ng-valid | ng-invalid |
此外,Angular 還會(huì)在提交時(shí)把 ?ng-submitted? 類應(yīng)用到 ?? 元素上。這個(gè)類不會(huì)應(yīng)用到內(nèi)部控件上。
你可以用這些 CSS 類來根據(jù)控件的狀態(tài)定義其樣式。
要想知道框架是如何添加和移除這些類的,請(qǐng)打開瀏覽器的開發(fā)者工具,檢查代表英雄名字的 ??
? 元素。除了 “form-control” 類之外,你還可以看到該元素有多個(gè) CSS 類。
? 框中執(zhí)行以下操作,看看會(huì)出現(xiàn)哪些類。ng-touched? 類,取代了 ?ng-untouched? 類。ng-invalid? 類會(huì)取代 ?ng-valid? 類。注意 ?ng-valid? / ?ng-invalid? 這兩個(gè)類,因?yàn)槟阆朐谥禑o效時(shí)發(fā)出強(qiáng)烈的視覺信號(hào)。你還要標(biāo)記必填字段。
你可以在輸入框的左側(cè)用彩條標(biāo)記必填字段和無效數(shù)據(jù):
要想用這種方式修改外觀,請(qǐng)執(zhí)行以下步驟。
ng-*? CSS 類添加一些定義。forms.css? 文件中。index.html? 的兄弟:.ng-valid[required], .ng-valid.required {
border-left: 5px solid #42A948; /* green */
}
.ng-invalid:not(form) {
border-left: 5px solid #a94442; /* red */
}
index.html? 文件中,更新 ?? 標(biāo)簽以包含新的樣式表。
Name 輸入框是必填的,清除它就會(huì)把彩條變成紅色。這表明有些東西是錯(cuò)的,但是用戶并不知道要怎么做或該做什么。你可以通過查看和響應(yīng)控件的狀態(tài)來提供有用的信息。
當(dāng)用戶刪除該名字時(shí),該表單應(yīng)如下所示:
Hero Power 選擇框也是必填的,但它不需要這樣的錯(cuò)誤處理,因?yàn)檫x擇框已經(jīng)把選擇限制在有效值范圍內(nèi)。
要在適當(dāng)?shù)臅r(shí)候定義和顯示錯(cuò)誤信息,請(qǐng)執(zhí)行以下步驟。
? 標(biāo)簽,你可以用來從模板中訪問輸入框的 Angular 控件。在這個(gè)例子中,該變量是 ?#name="ngModel"?。模板引用變量(?
#name?)設(shè)置為 ?"ngModel"?,因?yàn)?nbsp;"ngModel" 是 ?NgModel.exportAs? 屬性的值。這個(gè)屬性告訴 Angular 如何把引用變量和指令鏈接起來。
?
- 通過把 ?
name ?控件的屬性綁定到 ?? 元素的 ?hidden ?屬性來顯示或隱藏錯(cuò)誤信息。
- 為 ?
name ?輸入框添加一個(gè)有條件的錯(cuò)誤信息,如下例所示。
Name is required
關(guān)于 "PRISTINE"(原始)狀態(tài)的說明
在這個(gè)例子中,當(dāng)控件是有效的(valid)或者是
原始的(pristine)時(shí),你會(huì)隱藏這些消息。原始表示該用戶在此表單中顯示的值尚未更改過。如果你忽略了 ?
pristine ?狀態(tài),那么只有當(dāng)值有效時(shí)才會(huì)隱藏這些消息。如果你把一個(gè)新的(空白)英雄或一個(gè)無效的英雄傳給這個(gè)組件,你會(huì)立刻看到錯(cuò)誤信息,而這時(shí)候你還沒有做過任何事情。
你可能希望只有在用戶做出無效更改時(shí),才顯示該消息。因此當(dāng) ?
pristine ?狀態(tài)時(shí),隱藏這條消息就可以滿足這個(gè)目標(biāo)。當(dāng)你在下一步中為表單添加一個(gè)新的英雄時(shí),就會(huì)看到這個(gè)選擇有多重要。
添加一個(gè)新英雄
本練習(xí)通過添加模型數(shù)據(jù),展示了如何響應(yīng)原生 HTML 按鈕單擊事件。要讓表單用戶添加一個(gè)新的英雄,就要添加一個(gè)能響應(yīng) click 事件的 New Hero 按鈕。
- 在模板中,把 “New Hero” 這個(gè) ?
? 元素放在表單底部。
- 在組件文件中,把創(chuàng)建英雄的方法添加到英雄數(shù)據(jù)模型中。
newHero() {
this.model = new Hero(42, '', '');
}
- 把按鈕的 click 事件綁定到一個(gè)創(chuàng)建英雄的方法 ?
newHero()? 上。
- 再次運(yùn)行該應(yīng)用,單擊 New Hero 按鈕。
表單會(huì)清空,輸入框左側(cè)的必填欄會(huì)顯示紅色,說明 ?name ?和 ?power ?屬性無效。請(qǐng)注意,錯(cuò)誤消息是隱藏的。這是因?yàn)楸韱翁幱谠紶顟B(tài)。你還沒有改過任何東西。
- 輸入一個(gè)名字,然后再次點(diǎn)擊 New Hero。
現(xiàn)在,該應(yīng)用會(huì)顯示一條錯(cuò)誤信息 ?Name is required?,因?yàn)樵撦斎肟虿辉偈窃紶顟B(tài)。表單會(huì)記住你在單擊 New Hero 之前輸入過一個(gè)名字。
- 要恢復(fù)表單控件的原始狀態(tài),可以在調(diào)用 ?
newHero()? 方法之后強(qiáng)制調(diào)用表單的 ?reset()? 方法以清除所有標(biāo)志。
現(xiàn)在單擊 New Hero 會(huì)重置表單及其控件標(biāo)志。
使用 ngSubmit 提交表單
用戶應(yīng)該可以在填寫之后提交這個(gè)表單。表單底部的 Submit 按鈕本身沒有任何作用,但由于它的類型(?type="submit"?),它會(huì)觸發(fā)一個(gè)表單提交事件。要響應(yīng)此事件,請(qǐng)執(zhí)行以下步驟。
- 把表單的 ?
ngSubmit ?事件屬性綁定到一個(gè) hero-form 組件的 ?onSubmit()? 方法中。
- 使用模板引用變量 ?
#heroForm? 訪問包含 Submit 按鈕的表單,并創(chuàng)建一個(gè)事件綁定。你可以把表示它整體有效性的 form 屬性綁定到 Submit 按鈕的 ?disabled ?屬性上。
- 運(yùn)行該應(yīng)用。注意,該按鈕已啟用 - 雖然它還沒有做任何有用的事情。
- 刪除名稱值。這違反了“必需”規(guī)則,因此會(huì)顯示錯(cuò)誤消息,并注意它還會(huì)禁用“提交”按鈕。
你不必把按鈕的啟用狀態(tài)明確地關(guān)聯(lián)表單的有效性上。當(dāng) ?FormsModule ?在增強(qiáng)的表單元素上定義模板引用變量時(shí),會(huì)自動(dòng)執(zhí)行此操作,然后在按鈕控件中引用該變量。
響應(yīng)表單提交
要展示對(duì)表單提交的響應(yīng),你可以隱藏?cái)?shù)據(jù)輸入?yún)^(qū)域并就地顯示其它內(nèi)容。
- 把整個(gè)表單包裹進(jìn)一個(gè) ?
? 中并把它的 ?hidden ?屬性綁定到 ?HeroFormComponent.submitted? 屬性上。
Hero Form
- 主表單從一開始就是可見的,因?yàn)樵谔峤恢?,它?nbsp;?
submitted ?屬性都是 false,正如 ?HeroFormComponent ?中的這個(gè)片段所顯示的:
submitted = false;
onSubmit() { this.submitted = true; }
- 點(diǎn)擊 Submit 按鈕后,?
submitted ?標(biāo)志就變?yōu)?nbsp;?true?,表單就會(huì)消失。
- 要在表單處于已提交狀態(tài)時(shí)顯示其它內(nèi)容,請(qǐng)?jiān)谛碌?nbsp;?
? 包裝器下添加以下 HTML。
You submitted the following:
Name
{{ model.name }}
Alter Ego
{{ model.alterEgo }}
Power
{{ model.power }}
這個(gè) ??(用于顯示帶插值綁定的只讀英雄)只在組件處于已提交狀態(tài)時(shí)才會(huì)出現(xiàn)。另外還顯示了一個(gè) Edit 按鈕,它的 click 事件綁定到了一個(gè)清除 ?submitted ?標(biāo)志的表達(dá)式。
- 單擊 Edit 按鈕,將顯示切換回可編輯的表單。
總結(jié)
本頁討論的 Angular 表單利用了下列框架特性來支持?jǐn)?shù)據(jù)修改,驗(yàn)證等工作。
- 一個(gè) Angular HTML 表單模板
- 帶 ?
@Component? 裝飾器的表單組件類
- 綁定到 ?
NgForm.ngSubmit? 事件屬性來處理表單提交
- 模板引用變量,比如 ?
#heroForm? 和 ?#name ?
- 雙向數(shù)據(jù)綁定的 ?
[(ngModel)]? 語法
- ?
name ?屬性的用途是驗(yàn)證和表單元素的變更跟蹤
- 用輸入控件上的引用變量的 ?
valid? 屬性來檢查控件是否有效,并據(jù)此顯示或隱藏錯(cuò)誤信息
- 用 ?
NgForm ?的有效性來控制 Submit 按鈕的啟用狀態(tài)
- 自定義 CSS 類,為用戶提供關(guān)于無效控件的視覺反饋
這里是該應(yīng)用最終版本的代碼:
- hero-form/hero-form.component.ts
import { Component } from '@angular/core';
import { Hero } from '../hero';
@Component({
selector: 'app-hero-form',
templateUrl: './hero-form.component.html',
styleUrls: ['./hero-form.component.css']
})
export class HeroFormComponent {
powers = ['Really Smart', 'Super Flexible',
'Super Hot', 'Weather Changer'];
model = new Hero(18, 'Dr IQ', this.powers[0], 'Chuck Overstreet');
submitted = false;
onSubmit() { this.submitted = true; }
newHero() {
this.model = new Hero(42, '', '');
}
}
- hero-form/hero-form.component.html
Hero Form
You submitted the following:
Name
{{ model.name }}
Alter Ego
{{ model.alterEgo }}
Power
{{ model.power }}
- hero.ts
export class Hero {
constructor(
public id: number,
public name: string,
public power: string,
public alterEgo?: string
) { }
}
- app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
import { HeroFormComponent } from './hero-form/hero-form.component';
@NgModule({
imports: [
BrowserModule,
CommonModule,
FormsModule
],
declarations: [
AppComponent,
HeroFormComponent
],
providers: [],
bootstrap: [ AppComponent ]
})
export class AppModule { }
- app.component.html
- app.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent { }
- main.ts
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
if (environment.production) {
enableProdMode();
}
platformBrowserDynamic().bootstrapModule(AppModule);
- forms.css
.ng-valid[required], .ng-valid.required {
border-left: 5px solid #42A948; /* green */
}
.ng-invalid:not(form) {
border-left: 5px solid #a94442; /* red */
}
新聞標(biāo)題:創(chuàng)新互聯(lián)Angular教程:Angular構(gòu)建模板驅(qū)動(dòng)表單
網(wǎng)站路徑:http://uogjgqi.cn/article/dhecpho.html
掃二維碼與項(xiàng)目經(jīng)理溝通
我們?cè)谖⑿派?4小時(shí)期待你的聲音
解答本文疑問/技術(shù)咨詢/運(yùn)營(yíng)咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流