表單

版本:Angular 5.0.0-alpha

表單是商業(yè)應(yīng)用的支柱,我們用它來(lái)執(zhí)行登錄、求助、下單、預(yù)訂機(jī)票、安排會(huì)議,以及不計(jì)其數(shù)的其它數(shù)據(jù)錄入任務(wù)。

在開(kāi)發(fā)表單時(shí),創(chuàng)建數(shù)據(jù)方面的體驗(yàn)是非常重要的,它能指引用戶(hù)明細(xì)、高效的完成工作流程。

開(kāi)發(fā)表單需要設(shè)計(jì)能力(那超出了本章的范圍),而框架支持雙向數(shù)據(jù)綁定、變更檢測(cè)、驗(yàn)證和錯(cuò)誤處理,在本章你將會(huì)學(xué)習(xí)它們。

本章展示了如何從草稿構(gòu)建一個(gè)簡(jiǎn)單的表單。在這個(gè)過(guò)程中你將學(xué)會(huì)如何:

  • 用組件和模板構(gòu)建 Angular 表單。
  • ngModel創(chuàng)建雙向數(shù)據(jù)綁定,以讀取和寫(xiě)入輸入控件的值。
  • 跟蹤狀態(tài)的變化,并驗(yàn)證表單控件。
  • 使用特殊的 CSS 類(lèi)來(lái)跟蹤控件的狀態(tài)并給出視覺(jué)反饋。
  • 向用戶(hù)顯示驗(yàn)證錯(cuò)誤提示,以及啟用/禁用表單控件。
  • 使用模板引用變量在 HTML 元素之間共享信息。

你可以運(yùn)行在線示例(查看源代碼)。

模板驅(qū)動(dòng)表單

你可以使用 Angular 模板語(yǔ)法編寫(xiě)模板,結(jié)合本章所描述的表單專(zhuān)用指令和技術(shù)來(lái)構(gòu)建表單。

你還可以使用響應(yīng)式(也叫模型驅(qū)動(dòng))的方式來(lái)構(gòu)建表單。不過(guò)本章中只介紹模板驅(qū)動(dòng)表單。

利用 Angular 模板,可以構(gòu)建幾乎所有表單——登錄表單、聯(lián)系人表單, 以及任何非常漂亮的商務(wù)表單。可以創(chuàng)造性的擺放各種控件、把它們綁定到數(shù)據(jù)、指定校驗(yàn)規(guī)則、顯示校驗(yàn)錯(cuò)誤、有條件的禁用或啟用特定的控件、觸發(fā)內(nèi)置的視覺(jué)反饋等等,不勝枚舉。

Angular 通過(guò)處理大量重復(fù)的、模板化的任務(wù),簡(jiǎn)化了過(guò)程,從而使你不必陷入與自己的斗爭(zhēng)中。

你將學(xué)習(xí)構(gòu)建如下的“模板驅(qū)動(dòng)”表單:

英雄職業(yè)介紹所,使用這個(gè)表單來(lái)維護(hù)英雄們的個(gè)人信息。每個(gè)英雄都需要一份工作。公司的使命就是讓合適的英雄去應(yīng)對(duì)合適的危機(jī)。

表單中的三個(gè)字段,其中兩個(gè)是必填的。根據(jù) material design 指南,必填的字段用星號(hào)(*)標(biāo)出。

如果刪除了英雄的名字,表單就會(huì)用醒目的樣式把驗(yàn)證錯(cuò)誤顯示出來(lái)。

注意,提交按鈕被禁用了,而且輸入控件從綠色變?yōu)榱思t色。

你將一小步一小步地構(gòu)建此表單:

  1. 創(chuàng)建Hero模型類(lèi)。
  2. 創(chuàng)建控制此表單的組件。
  3. 創(chuàng)建具有初始表單布局的模板。
  4. 使用 ngModel 雙向數(shù)據(jù)綁定語(yǔ)法把數(shù)據(jù)屬性綁定到每個(gè)表單輸入控件。
  5. 為每個(gè)表單輸入控件添加 ngControl 指令。
  6. 添加自定義 CSS 來(lái)提供視覺(jué)反饋。
  7. 顯示和隱藏有效性驗(yàn)證的錯(cuò)誤信息。
  8. 使用 ngSubmit 處理表單提交。
  9. 禁用此表單的提交按鈕,直到表單變?yōu)橛行А?/li>

配置

根據(jù)配置的說(shuō)明創(chuàng)建一個(gè)名為forms的新項(xiàng)目。

添加 angular_forms

Angular 表單的功能在 angular_forms 庫(kù)中,它有自己的包,添加包到 pub 依賴(lài)中:

// {quickstart → forms}/pubspec.yaml

dependencies:
    angular: ^5.0.0-alpha       
+  angular_forms: ^2.0.0-alpha

創(chuàng)建模型

當(dāng)用戶(hù)輸入表單數(shù)據(jù)時(shí),需要捕獲它們的變化,并更新到模型的實(shí)例中。除非知道模型的樣子,否則無(wú)法設(shè)計(jì)表單的布局。

最簡(jiǎn)單的模型是個(gè)“屬性包”,用來(lái)存放關(guān)于應(yīng)用重點(diǎn)的資料。這里使用了描述Hero類(lèi)的三個(gè)必備字段 (id、namepower),和一個(gè)可選字段 (alterEgo)。

lib目錄,按照已給出的內(nèi)容創(chuàng)建下面的文件:

// lib/src/hero.dart

class Hero {
  int id;
  String name, power, alterEgo;
  Hero(this.id, this.name, this.power, [this.alterEgo]);
  String toString() => '$id: $name ($alterEgo). Super power: $power';
}  

這是一個(gè)少量需求和零行為的貧血模型。對(duì)演示來(lái)說(shuō)足夠了。

alterEgo是可選的,所以構(gòu)造函數(shù)允許你省略它;注意在[this.alterEgo]中的方括號(hào)。

可以像這樣創(chuàng)建新英雄:

var myHero = new Hero(
    42, 'SkyDog', 'Fetch any object at any distance', 'Leslie Rollover');
print('My hero is ${myHero.name}.'); // "My hero is SkyDog."

創(chuàng)建基本的表單

Angular 表單分為兩部分:基于 HTML 的模板 ,以及用來(lái)處理數(shù)據(jù)和用戶(hù)動(dòng)態(tài)交互的組件類(lèi)。先從這個(gè)類(lèi)開(kāi)始,是因?yàn)樗梢院?jiǎn)要說(shuō)明英雄編輯器能做什么。

創(chuàng)建表單組件

根據(jù)已給出的內(nèi)容創(chuàng)建下面的文件:

// lib/src/hero_form_component.dart (v1)

import 'package:angular/angular.dart';
import 'package:angular_forms/angular_forms.dart';

import 'hero.dart';

const List<String> _powers = [
  'Really Smart',
  'Super Flexible',
  'Super Hot',
  'Weather Changer'
];

@Component(
  selector: 'hero-form',
  templateUrl: 'hero_form_component.html',
  directives: [coreDirectives, formDirectives],
)
class HeroFormComponent {
  Hero model = new Hero(18, 'Dr IQ', _powers[0], 'Chuck Overstreet');
  bool submitted = false;

  List<String> get powers => _powers;

  void onSubmit() => submitted = true;
}

這個(gè)組件沒(méi)有什么特別的地方,沒(méi)有表單相關(guān)的東西,與之前寫(xiě)過(guò)的組件沒(méi)什么不同。

只需要前面章節(jié)中學(xué)過(guò)的 Angular 概念,就可以完全理解這個(gè)組件:

  • 這段代碼導(dǎo)入了 Angular 核心庫(kù)以及你剛剛創(chuàng)建的Hero模型。
  • @Component選擇器hero-form表示可以用<hero-form>元素把這個(gè)表單放進(jìn)父模板。
  • templateUrl屬性指向一個(gè)獨(dú)立的 HTML 模板文件(稍后創(chuàng)建)。
  • modelpowers定義模擬數(shù)據(jù)。

接下來(lái),你可以注入一個(gè)數(shù)據(jù)服務(wù),以獲取或保存真實(shí)的數(shù)據(jù),或者把這些屬性暴露為輸入屬性和輸出屬性(參見(jiàn)模板語(yǔ)法中的輸入和輸出屬性)來(lái)綁定到一個(gè)父組件。這不是現(xiàn)在需要關(guān)心的問(wèn)題,未來(lái)的更改不會(huì)影響到這個(gè)表單。

修改 app component

AppComponent 是應(yīng)用的根組件,HeroFormComponent 將被放在其中。

使用下面的內(nèi)容替換初始版本:

// lib/app_component.dart

import 'package:angular/angular.dart';

import 'src/hero_form_component.dart';

@Component(
  selector: 'my-app',
  template: '<hero-form></hero-form>',
  directives: [HeroFormComponent],
)
class AppComponent {}

創(chuàng)建初始 HTML 表單模板

使用下面的內(nèi)容創(chuàng)建模板文件:

// lib/src/hero_form_component.html (start)

<div class="container">
  <h1>Hero Form</h1>
  <form>
    <div class="form-group">
      <label for="name">Name&nbsp;*</label>
      <input type="text" class="form-control" id="name" required>
    </div>
    <div class="form-group">
      <label for="alterEgo">Alter Ego</label>
      <input type="text" class="form-control" id="alterEgo">
    </div>
    <div class="row">
      <div class="col-auto">
        <button type="submit" class="btn btn-primary">Submit</button>
      </div>
      <small class="col text-right">*&nbsp;Required</small>
    </div>
  </form>
</div>

這是一段簡(jiǎn)單的 HTML5 代碼。我們展現(xiàn)了Hero的兩個(gè)字段,namealterEgo,提供給用戶(hù)在輸入框中輸入。

Name<input>控件具有 HTML5 的required屬性;Alter Ego<input>控件沒(méi)有,因?yàn)?code>alterEgo是可選的。

在底部添加了一個(gè)具有一些 CSS 類(lèi)的提交按鈕。

你還沒(méi)有用到 Angular。沒(méi)有綁定,沒(méi)有額外的指令,只有布局。

在模板驅(qū)動(dòng)表單中,你只要導(dǎo)入了angular_forms庫(kù),就不用對(duì)<form>做任何其它的事情來(lái)使用庫(kù)的功能。接下來(lái)你會(huì)看到它的原理。

刷新瀏覽器。你會(huì)看到一個(gè)簡(jiǎn)單的,沒(méi)有樣式的表單。

給表單添加樣式

containerbtn類(lèi)都來(lái)自 Bootstrap。Bootstrap 也有特定的表單類(lèi),包括form-controlform-group。它們給表單添加了一點(diǎn)樣式。

Angular 不需要使用 Bootstrap 類(lèi)或任意外部庫(kù)的樣式。Angular 應(yīng)用可以使用任意 CSS 庫(kù)或一點(diǎn)也不用。

index.html<head>插入下面的鏈接來(lái)添加 Bootstrap 樣式。

// web/index.html (bootstrap)

<link rel="stylesheet"  integrity="sha384-WskhaSGFgHYWDcbwN70/dfYBj47jz9qbsMId/iRN3ewGhXQFZCSftd1LZCfmhktB" crossorigin="anonymous">

刷新瀏覽器。你會(huì)看到一個(gè)帶有樣式的表單。

使用 *ngFor 添加 powers

英雄必須從認(rèn)證過(guò)的固定列表中選擇一項(xiàng)超能力。你在內(nèi)部維護(hù)這個(gè)列表(在HeroFormComponent)。

在表單中添加select,用ngForpowers列表綁定到列表選項(xiàng),在之前的顯示數(shù)據(jù)一章中使用過(guò)的技術(shù)。

在緊跟著 Alter Ego 組的下方添加如下 HTML:

// lib/src/hero_form_component.html (powers)

<div class="form-group">
  <label for="power">Hero Power&nbsp;*</label>
  <select class="form-control" id="power" required>
    <option *ngFor="let p of powers" [value]="p">{{p}}</option>
  </select>
</div>

powers列表中的每一項(xiàng)超能力都會(huì)渲染成<option>標(biāo)簽。 模板輸入變量p在每個(gè)迭代指向不同的超能力,使用雙花括號(hào)插值表達(dá)式語(yǔ)法來(lái)顯示它的名稱(chēng)。

使用 ngModel 雙向數(shù)據(jù)綁定

現(xiàn)在運(yùn)行此應(yīng)用,有點(diǎn)令人失望。

你看不到英雄數(shù)據(jù)因?yàn)檫€沒(méi)有綁定到Hero。在前面的章節(jié)我們知道怎么去做。顯示數(shù)據(jù)介紹了屬性綁定。用戶(hù)輸入展示了如何通過(guò)事件綁定來(lái)監(jiān)聽(tīng) DOM 事件,以及如何用顯示的值更新組件的屬性。

現(xiàn)在,需要同時(shí)進(jìn)行顯示、監(jiān)聽(tīng)和提取。

雖然可以在表單中再次使用這些已知的技術(shù)。但是,你將使用新的[(ngModel)]語(yǔ)法,使表單綁定到模型的工作變得更容易。

找到Name對(duì)應(yīng)的<input>標(biāo)簽,并且像這樣更新它:

// lib/src/hero_form_component.html (name)

<!-- TODO: remove the next diagnostic line -->
<mark>{{model.name}}</mark><hr>
<div class="form-group">
  <label for="name">Name&nbsp;*</label>
  <input type="text" class="form-control" id="name" required
         [(ngModel)]="model.name"
         ngControl="name">
</div>

在 form-group 標(biāo)簽前添加用于診斷的插值表達(dá)式,以看清正在發(fā)生什么事。給自己留個(gè)注釋?zhuān)嵝涯阃瓿珊笠瞥?/p>

聚焦到綁定語(yǔ)法:[(ngModel)]="..."上。

現(xiàn)在運(yùn)行應(yīng)用,開(kāi)始在Name 輸入框中鍵入,添加和刪除字符,我們將看到它們從診斷文本中顯示和消失。某一瞬間,它看起來(lái)可能是這樣:

診斷信息可以證明,數(shù)據(jù)確實(shí)從輸入框流動(dòng)到模型,再反向流動(dòng)回來(lái)。

這就是雙向數(shù)據(jù)綁定!。更多信息,參見(jiàn)模板語(yǔ)法章節(jié)的使用 NgModel 雙向綁定

注意,<input>標(biāo)簽還添加了ngControl指令,并設(shè)置為 "name",表示英雄的名字。使用任何唯一的值都可以,但使用具有描述性的“name”會(huì)更有幫助。當(dāng)在表單組合中使用[(ngModel)]時(shí),必須要定義ngControl指令。

在內(nèi)部,Angular 創(chuàng)建了一些NgFormControl,并把它們注冊(cè)到NgForm指令,再將該指令附加到<form>標(biāo)簽。每個(gè)NgFormControl都都以你分配給NgFormControl指令的名稱(chēng)注冊(cè)。稍后會(huì)看到更多 NgForm 的信息。

Alter EgoHero Power 添加類(lèi)似的[(ngModel)]綁定和ngControl指令。

使用model替換診斷綁定表達(dá)式。這樣就能確認(rèn)雙向數(shù)據(jù)綁定在整個(gè) Hero 模型上都能正常工作了。

修改之后,這個(gè)表單的核心是這樣的:

// lib/src/hero_form_component.html (controls)

<!-- TODO: remove the next diagnostic line -->
<mark>{{model}}</mark><hr>
<div class="form-group">
  <label for="name">Name&nbsp;*</label>
  <input type="text" class="form-control" id="name" required
         [(ngModel)]="model.name"
         ngControl="name">
</div>
<div class="form-group">
  <label for="alterEgo">Alter Ego</label>
  <input type="text" class="form-control" id="alterEgo"
         [(ngModel)]="model.alterEgo"
         ngControl="alterEgo">
</div>
<div class="form-group">
  <label for="power">Hero Power&nbsp;*</label>
  <select class="form-control" id="power" required
          [(ngModel)]="model.power"
          ngControl="power">
    <option *ngFor="let p of powers" [value]="p">{{p}}</option>
  </select>
</div>
  • 每個(gè) input 元素都有id屬性,label元素的for屬性用它來(lái)匹配到對(duì)應(yīng)的輸入控件。
  • 每個(gè) input 元素都有ngControl指令,這是 Angular 表單注冊(cè)表單控件所必須的。

如果現(xiàn)在運(yùn)行本應(yīng)用,修改每個(gè) Hero 模型的屬性,表單可能顯示如下:

表單頂部的診斷信息證實(shí)了你所做的一切更改都反映在了 model 中。

從模板刪除診斷綁定因?yàn)樗呀?jīng)完成了它的使命。

基于控件狀態(tài)提供視覺(jué)反饋

使用 CSS 和類(lèi)綁定,可以改變表單控件的外觀來(lái)反映它的狀態(tài)。

追蹤控件狀態(tài)

一個(gè) Angular 表單控件可以告訴你,用戶(hù)是否碰過(guò)此控件,值是否發(fā)生改變,以及值是否無(wú)效。

Angular 表單的每個(gè)控件(NgControl)追蹤自身的狀態(tài),并通過(guò)檢查下面的成員字段使?fàn)顟B(tài)可用:

  • dirtypristine表明控件的值是否發(fā)生改變。
  • toucheduntouched表明控件是否被訪問(wèn)。
  • valid反映了控件值的有效性。

控件樣式

valid控件屬性是最引人注意的,因?yàn)楫?dāng)控件的值無(wú)效時(shí),你希望發(fā)出強(qiáng)烈的視覺(jué)信號(hào)。要?jiǎng)?chuàng)建這樣的視覺(jué)反饋,你需要使用 Bootstrap custom-forms 的類(lèi)is-validis-invalid

Name<input>標(biāo)簽添加一個(gè)名為name的模板引用變量。使用name和類(lèi)綁定有條件的指定恰當(dāng)?shù)谋韱斡行缘念?lèi)。

Name<input>標(biāo)簽臨時(shí)添加另一個(gè)名為spy的模板引用變量,用來(lái)顯示輸入框的 CSS 類(lèi)。

// lib/src/hero_form_component.html (name)

<input type="text" class="form-control" id="name" required
       [(ngModel)]="model.name"
       #name="ngForm"
       #spy
       [class.is-valid]="name.valid"
       [class.is-invalid]="!name.valid"
       ngControl="name">
<!-- TODO: remove the next diagnostic line -->
{{spy.className}}
模板引用變量

spy模板引用變量綁定到了<input>DOM元素,然而name變量(#name="ngForm")綁定到了與 input 元素相關(guān)聯(lián)的 NgModel。

為什么是 “ngForm”?指令exportAs 屬性告訴 Angular 如何鏈接模板引用變量到指令。把name設(shè)置為 “ngForm” 是因?yàn)?ngModel 指令的exportAs屬性是 “ngForm”。

刷新瀏覽器,遵循下面的步驟:

  1. Name 輸入框。
    • 它有一個(gè)綠色的邊框。
    • 它有form-controlis-valid類(lèi)。
  2. 添加一些字符來(lái)改變 name。類(lèi)名依然不變。
  3. 刪除 name。
    • 輸入邊框變紅。
    • is-invalid類(lèi)變成了is-valid

刪除#spy模板引用變量和使用到它的診斷信息。

另一種類(lèi)綁定的方法,可以使用 NgClass 指令給控件添加樣式。首先添加下面的方法來(lái)設(shè)置控件的狀態(tài)依賴(lài) CSS 類(lèi)名:

// lib/src/hero_form_component.dart (setCssValidityClass)

Map<String, bool> setCssValidityClass(NgControl control) {
  final validityClass = control.valid == true ? 'is-valid' : 'is-invalid';
  return {validityClass: true};
}

使用上面方法返回的 map 值,綁定到 NgClass 指令——更多關(guān)于這個(gè)指令及其替代品的信息請(qǐng)看模板語(yǔ)法章節(jié)。

// lib/src/hero_form_component.html (power)

<select class="form-control" id="power" required
        [(ngModel)]="model.power"
        #power="ngForm"
        [ngClass]="setCssValidityClass(power)"
        ngControl="power">
  <option *ngFor="let p of powers" [value]="p">{{p}}</option>
</select>

顯示和隱藏驗(yàn)證錯(cuò)誤信息

你可以改進(jìn)表單。Name 輸入框是必填的,清空它會(huì)使輸入框變紅。這表明有些東西錯(cuò)了,但用戶(hù)不知道錯(cuò)在哪里,或者如何糾正。利用控件狀態(tài)來(lái)顯示有用的信息。

使用 valid 和 pristine 狀態(tài)

當(dāng)用戶(hù)刪除姓名時(shí),表單看起來(lái)應(yīng)該是這樣的:

要達(dá)到這個(gè)效果,在緊跟著 Name <input>標(biāo)簽后面添加下面的<div>

// lib/src/hero_form_component.html (hidden error message)

<div [hidden]="name.valid || name.pristine" class="invalid-feedback">
  Name is required
</div>

刷新瀏覽器,刪除輸入框中的Name。錯(cuò)誤信息就顯示出來(lái)了。

基于name控件的狀態(tài),通過(guò)設(shè)置divhidden 屬性,顯式地控制錯(cuò)誤信息。

在這個(gè)例子中,當(dāng)控件是 valid 或 pristine 時(shí),隱藏消息。 “pristine” 意味著從它被顯示在表單中開(kāi)始,用戶(hù)還從未修改過(guò)它的值。

用戶(hù)體驗(yàn)取決于開(kāi)發(fā)人員的選擇

有些開(kāi)發(fā)人員會(huì)希望任何時(shí)候都顯示這條消息。如果忽略了 pristine 狀態(tài),就會(huì)只在值有效時(shí)隱藏此消息。如果往這個(gè)組件中傳入全新(空)的英雄,或者無(wú)效的英雄,將立刻看到錯(cuò)誤信息 —— 雖然你還什么都沒(méi)做。

有些開(kāi)發(fā)人員會(huì)希望只有在用戶(hù)做出無(wú)效的更改時(shí)才顯示這個(gè)消息。 如果當(dāng)控件是 “pristine” 狀態(tài)時(shí)也隱藏消息,就能達(dá)到這個(gè)目的。在往表單中添加新英雄時(shí),將看到這種選擇的重要性。

Alter Ego 是可選項(xiàng),所以不用改它。

英雄的超能力選項(xiàng)是必填的。只要愿意,可以往<select>上添加相同的錯(cuò)誤處理。但沒(méi)有必要,這個(gè)選擇框已經(jīng)限制了“超能力”只能選有效值。

添加清除按鈕

在組件類(lèi)中添加clear()方法:

// lib/src/hero_form_component.dart (clear)

void clear() {
  model.name = '';
  model.power = _powers[0];
  model.alterEgo = '';
}

提交 按鈕的右邊添加一個(gè)綁定click事件的 Clear 按鈕:

// lib/src/hero_form_component.html (Clear button)

<button (click)="clear()" type="button" class="btn">
  Clear
</button>

刷新瀏覽器。點(diǎn)擊 Clear 按鈕。文本域都被清空,如果之前改變了Power 的值,也會(huì)重置為默認(rèn)值。

使用 ngSubmit 提交表單

在填表完成之后,用戶(hù)應(yīng)該能提交這個(gè)表單。Submit 按鈕位于表單的底部,它自己不做任何事,但因?yàn)樗?type 值 (type="submit"),所以會(huì)觸發(fā)表單提交。

此時(shí)提交表單是無(wú)意義的。為了讓它有意義,指定表單組件的onSubmit()方法,綁定到表單的ngSubmit事件綁定:

<form (ngSubmit)="onSubmit()" #heroForm="ngForm">

注意模板引用變量#heroForm。正如前面所說(shuō)的,變量heroForm被綁定到管理整個(gè)表單的NgForm指令。

NgForm指令

Angular 自動(dòng)創(chuàng)建并添加 NgForm 指令到<form>標(biāo)簽。

NgForm指令給表單元素附加了額外的特性。它會(huì)控制那些帶有ngModelngControl指令的控件元素,監(jiān)聽(tīng)他們的屬性,包括其有效性。

你要把表單的總體有效性通過(guò)heroForm變量綁定到按鈕的disabled屬性上。

<button [disabled]="!heroForm.form.valid" type="submit" class="btn btn-primary">
  Submit
</button>

刷新瀏覽器。你會(huì)發(fā)現(xiàn)按鈕是可用的——盡管它還沒(méi)有做任何有用的事。

現(xiàn)在如果我們刪除 Name,就違反了“required”規(guī)則,它會(huì)恰當(dāng)?shù)娘@示在錯(cuò)誤信息中。提交 按鈕也被禁用了。

不覺(jué)得了不起嗎?再想一想。如果沒(méi)有 Angular 的幫助,我們又該怎樣讓按鈕的禁用/啟用狀態(tài)和表單的有效性關(guān)聯(lián)起來(lái)呢?

有了 Angular,它就是這么簡(jiǎn)單:

  1. 在(增強(qiáng)的)form 元素上定義一個(gè)模板引用變量。
  2. 在許多行之外的按鈕上引用該變量。

顯示模型 (可選)

此時(shí)提交表單沒(méi)有視覺(jué)特效。

改進(jìn) demo 也無(wú)法教給我們?nèi)魏侮P(guān)于表單的新知識(shí)。但這是一個(gè)練習(xí)新學(xué)到的綁定技能的好機(jī)會(huì)。如果你不感興趣,跳到本章的總結(jié)部分。

作為視覺(jué)效果,隱藏掉數(shù)據(jù)輸入?yún)^(qū)域并顯示一些其它東西。

把表單包裹進(jìn)<div>中,并把它的hidden屬性綁定到HeroFormComponent.submitted屬性。

// lib/src/hero_form_component.html (excerpt)

  <div [hidden]="submitted">
    <h1>Hero Form</h1>
    <form (ngSubmit)="onSubmit()" #heroForm="ngForm">
    </form>
  </div>

表單從一開(kāi)始就是可見(jiàn)的,因?yàn)?code>submitted屬性是 false,直到我們提交了這個(gè)表單,正如下面這段HeroFormComponent的代碼展示的:

// lib/src/hero_form_component.dart (submitted)

bool submitted = false;

void onSubmit() => submitted = true;

現(xiàn)在,在剛寫(xiě)的<div>包裹層下方,添加如下 HTML:

// lib/src/hero_form_component.html (submitted)

<div [hidden]="!submitted">
  <h1>Hero data</h1>

  <table class="table">
    <tr>
      <th>Name</th>
      <td>{{model.name}}</td>
    </tr>
    <tr>
      <th>Alter Ego</th>
      <td>{{model.alterEgo}}</td>
    </tr>
    <tr>
      <th>Power</th>
      <td>{{model.power}}</td>
    </tr>
  </table>

  <button (click)="submitted=false" class="btn btn-primary">Edit</button>
</div>

刷新瀏覽器,并提交表單。submitted標(biāo)記變成 true,表單消失了。你會(huì)看到英雄模型的值(只讀)顯示在表格中。

這個(gè)視圖包含一個(gè) Edit 按鈕,它的點(diǎn)擊事件綁定清除submitted標(biāo)志。當(dāng)你點(diǎn)擊 Edit 按鈕時(shí),表格消失,可編輯的表單又出現(xiàn)了。

總結(jié)

Angular 表單提供了數(shù)據(jù)修改、驗(yàn)證等支持。在本章中學(xué)到了怎樣使用下面的特性:

  • 一個(gè) HTML 表單模板和一個(gè)帶有@Component注解的表單組件類(lèi)。
  • 通過(guò)一個(gè)ngSubmit事件綁定處理表單提交。
  • 模板引用變量,例如heroFormname
  • 雙向數(shù)據(jù)綁定([(ngModel)])。
  • 用于驗(yàn)證和追蹤表單元素變化的ngControl指令。
  • input 控件的valid屬性(通過(guò)模板引用變量獲?。?,用于檢查控件的有效性和顯示/隱藏錯(cuò)誤信息。
  • NgForm.form的有效性來(lái)設(shè)置 提交 按鈕的激活狀態(tài)。
  • 定制 CSS 類(lèi)來(lái)給用戶(hù)提供控件狀態(tài)的視覺(jué)反饋。

下一步

依賴(lài)注入

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • angular提供了模板驅(qū)動(dòng)和模型驅(qū)動(dòng)兩種方式來(lái)構(gòu)建表單。模板驅(qū)動(dòng)模式使用模板表單內(nèi)置指令、內(nèi)置校驗(yàn)的方式來(lái)構(gòu)建表...
    oWSQo閱讀 946評(píng)論 0 0
  • 表單創(chuàng)建一個(gè)有機(jī)、有效、引人注目的數(shù)據(jù)輸入體驗(yàn)。 Angular 表單協(xié)調(diào)一組數(shù)據(jù)綁定控件,跟蹤變更,驗(yàn)證輸入的有...
    趙然228閱讀 1,582評(píng)論 0 0
  • 細(xì)說(shuō) Angular 2+ 的表單(二):響應(yīng)式表單 摘要 在企業(yè)應(yīng)用開(kāi)發(fā)時(shí),表單是一個(gè)躲不過(guò)去的事情,和面向消費(fèi)...
    接灰的電子產(chǎn)品閱讀 5,951評(píng)論 8 28
  • 主要內(nèi)容 第一節(jié) - 創(chuàng)建最簡(jiǎn)單的輸入框 第二節(jié) - 添加簡(jiǎn)單的驗(yàn)證功能 第三節(jié) - 顯示驗(yàn)證失敗的錯(cuò)誤信息 第四...
    semlinker閱讀 1,269評(píng)論 0 4
  • 周末閑在家里,一早山上透氣, 順手摘點(diǎn)杏兒,品嘗人間美味。 不想與人為伍,江湖實(shí)在太亂, 沒(méi)事看看格斗,生活真是愜意。
    健行賤遠(yuǎn)閱讀 256評(píng)論 0 1

友情鏈接更多精彩內(nèi)容