从本章开始会进入 Angular Form 的部分,在现代网页中与使用者互动的过程变得越来越重要,其中最主要的便是 Form,从一开始的登陆页面到对商品或对网页中元素的设定都需要使用到 Form 来取得使用者输入的资料,也需要对使用者输入的资料做验证以防使用者输入了非格式的数据导致出错。
Angular 提供了两种不同的方法来处理使用者的输入,分别是 reactive
与 template-driven
,两种方法都是从 view 中捕获使用者输入事件、验证用户输入、创建表单模型或更新数据模型,本篇会大概介绍这两种方法以及他们之间的差别,那就继续往下看吧!
Reactive forms
和 template-driven forms
以不同的方式处理和管理表单数据,他们各有各自的优势:
简单
的表单,他很容易被添加到专案中但他的扩展性与可测试性比较差。可以透过一张表单来总结 Reactive forms
和 template-driven forms
之间的主要区别
'' | Reactive | Template |
---|---|---|
Setup of form model | 明显的,在 Component 中创建 | 隐式的,由 directive 创建 |
Data model | 结构化和不可变 | 非结构化且可变 |
Data flow | 同步 | 非同步 |
Form validation | 透过 function | 透过 directive |
如果 Form 是你专案中的核心部分的话,那麽就需要将整个 Form 模型重复使用於各个不同的 Component,所以可伸缩性就非常重要。
Reactive forms 比 template-driven forms 更具有可扩展性
,他提供了对底层表单 API 的直接访问,并在 view 和数据模型之间使用同步
的数据流,这让你创建大型的表单变得更加容易,他也需要比较少的测试设置,并且测试不需要深入了解就可以正确的测试表单的更新和验证。
相较於 Reactive forms 而言 Template-driven forms 比较常用在 简单且不可重复使用的场景
,他对底层表单 API 的访问比较抽象,并在 view 与数据模型之间使用非同步
的数据流,由於他的对 API 的访问较为抽象所以对於测试来说比较不好撰写,非常需要依赖手动更改检测执行才能成功,需要非常多的设置。
Reactive forms
和 template-driven forms
都会追踪使用者与画面中的表单和 Component 中表单数据之间的变化,他们在底层来说是共享同一个地层构建模块,但在创建和管理表单控制实例的方法不同。
Reactive forms 与 template-dirven forms 都建立在以下的 base classes 之上:
单个
表单控制元件的值和验证状态,简单来说他会负责追踪画面中一个绑定的 <input>
元素的内容。多个
表单控制元件的值和状态,简单来说他像是 javeascript 的 object,里面包含了很多个不同的表单控制元件,可能由多个 FormControl 或 FormArray 所组成,甚至里面在包含一个 FormGroup。使用 reactive forms 可以直接在 component 中定义你的表单模型,[formControl]
directive 会使用 internal value accessor
将创建的 FormControl intance 链结到 view 中被绑定的单个输入元素,来举个例子吧
首先先在 app.module.ts 中引入 Form module
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
@NgModule({
declarations: [
AppComponent,
],
imports: [
BrowserModule,
AppRoutingModule,
FormsModule,
ReactiveFormsModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
在 app.component.ts 中建立 FormControl
import { Component } from '@angular/core';
import { FormControl } from '@angular/forms'; // (1)
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
})
export class AppComponent {
favoriteColorControl = new FormControl(''); // (2)
}
@angular/forms
中引入 FormControl在 app.component.html 中绑定表单控制元件
<!-- app.component.html -->
<div>
Favorite Color: <input type="text" [formControl]="favoriteColorControl" />
</div>
将 <input>
元件与 formControl 绑定後,他会追踪画面中 <input>
内容的变化并将它传递给 component 中被绑定的 property ( favoriteColorControl ),其实跟着上面的范例是无法在 console 中获得输入的值,要怎麽获得我之後会详细讲解。
接着来看如何建立 template-dirven forms 的表单控制模型,在 template-dirven forms 中的控制模型是隐性的,使用 directive MgModel
为给定的表单元素创建和管理一个 formControl 实例,一样举个例子
在 app.component.ts 中新增一个 property
import { Component } from '@angular/core';
@Component({
selector: 'app-template-favorite-color',
templateUrl: './app.component.html',
})
export class FavoriteColorComponent {
favoriteColor = '';
}
在 app.component.html 中使用 NgModel
绑定刚刚建立的 property
<!-- app.component.html -->
<div>
Favorite Color: <input type="text" [(ngModel)]="favoriteColor" />
</div>
在画面中可以看到透过 NgModel
将指定的 property 绑定,当画面中的表单元素内容发生变化时会传递给 component 中被绑定的 property,一样上面的范例是无法看到 console 的内容之後会讲解。
介绍完如何绑定表单的控制元件後,接着要来看看 Form 的数据流,当你的专案中有使用表单时,Angular 必须保持 view 与 component 模型内容的同步,当使用者更改画面中的值时这个新的值需要立即的反映在数据模型中,相同的当数据模型的值更新时也需要立马反映在画面中,而两种不同的 form 有着不同的处理数据与更改画面的方式。
在 reactive forms 中 view 的每一个表单元素都直接链结到 component 中的表单模型(formControl instance),从 view 到表单模型以及表单模型到 view 的更新是同步
的,不依赖於 UI 的呈现方式。
view 到表单模型显示了当在画面中输入字串後从 view 通过以下步骤流向表单模型:
<input>
中输入了一个值,例子中是输入了喜欢的颜色(blue)。<input>
)发送了带有最新值(blue) 的输入事件
。control value accessor
会监听输入元素的事件,当接收到事件後会立即将最新的值中继到 FormControl 实例上valueChanges
这个 observable
发出最新的值( valueChange.subscribe(val => { ... }) )。而表单模型到 view 显示了对表单模型进行编成更改後如何通过以下步骤更新 view 的值:
setValue()
method 用於更新 FormControl 的内容。control value accessor
使用这个最新的值更新画面表单元素在 template-driven forms 中每个表单元素都链结到一个内部管理表单模型的 directive,从 view 到模型显示了当在画面中输入字串後从 view 通过以下步骤流向表单模型:
<input>
中输入新的值(blue)。<input>
元素发出一个带有 blue 的 input 事件
。<input>
的 control value accessor
会触发 FormControl 实例上的 setValue() method。valueChanges observable
发出新的值。NgModel.viewToModelUpdater()
,这个 method 会发出一个 ngModelChange
的事件。favoriteColor
property 使用双向属性绑定 (Two-way binding) ,所以 component 中的 favoriteColor property 被更新为 ngModelChange
事件发出的值 (blue)。表单模型到 view 显示了当 favoriteColor 从蓝色变为红色时,数据会如何从表单模型流向 view,通果以下步骤:
ngOnChanges
在 NgModel
directive 实例上被调用,因为他的 input binding 发生更改。非同步
的方式设置 FormControl 实例的值control value accessor
会使用最新的 favoriteColor 值更新 view 中的表单输入元素更改和追踪的 method 在两种不同的 form 会有不同的作用:
不可更改
的数据结构用来保持表单数据模型的纯净,每次在表单数据模型上触发更改时,FormControl 实例都会返回一个新的
表单数据模型而不是更改现有的模型,这使你可以通过 FormControl 的 Observable
追踪表单数据模型的更改,让更改检测更有效,因为他只要追踪 FormControl 的更改,由於数据的更新遵循 reactive 的模式,所以可以使用 observable 的操作符改变表单数据。双向数据绑定
的可变性在 template 中进行更改後也更改 component 中的 property,由於在使用双向数据绑定时没有办法只跟踪表单数据模型,所以效率较低。以上面例子而言两种不同的 form 对於数据的变更处理:
本篇中介绍了 Angular 的两种不同的 Form,分别是 Reactive forms
与 template-driven forms
,虽然两种方法都可以做到与使用者的互动,但是还是有些的不同,Reactive forms
有更高的可扩展性、可重用性和可测试性,而 template-driven forms
则是使用双向绑定的方式将 component 的 property 与 template 的输入元件绑定,所以常用在比较简单的 Form 结构上。
虽然在本篇中简单的介绍了该如何使用 Reactive forms
与 template-driven forms
,不过只有稍微提到而已,接下来会分别对他们两个做比较详细的介绍与如何使用,那就明天见吧!
<<: 伪类与伪元素-30天学会HTML+CSS,制作精美网站
>>: 【Day08】Git 版本控制 - GitHub 简介
前言 上篇介绍了visualVM的安装,这篇就要来介绍如何使用 范例我们拿Day23-JDK可视化监...
Data Flow 中文直译为资料流, React 中文圈通常说法是 单向资料流/单一资料流, 如字...
Object.defineProperty 定义物件属性,调整属性特徵(请牢记!!) // 定义物件...
html的form标签之input小记录 前言本篇是上课中所提及好用,但是笔者小新手之前未发现的上课...
最初,Linux Kernel 的社群采用压缩档或是补丁的方式进行维护工作。一直到 2002 年,开...