您现在的位置是:首页 >其他 >【Angular】响应式表单之 FormControl网站首页其他
【Angular】响应式表单之 FormControl
FormControl
跟踪单个表单控件的值和验证状态。
响应式表单提供了一种模型驱动的方式来处理表单的输入。我们可以很方便的控制表单项的状态和验证器。响应式表单是围绕Observable
流构建的。流的消费者可以即方便又安全的操纵这些数据。
使用响应式表单控件
要想模块中使用响应式表单,需要三步:
- 在应用模块中注册响应式表单模块。该模块声明了响应式表单的指令。
- 在组件中生成新的
FormControl
实例,确保可以在组件和组件的模板中访问到。 - 在模板中应用这个
FormControl
。
比如,我们有个AccountModule
,里面包含了一个登录组件,我们来使用响应式表单来完成这个登录表单。
在模块中注册响应式表单模块
首先是需要在AccountModule
里面注册响应式表单模块:
import {NgModule} from '@angular/core';
import {CommonModule} from '@angular/common';
import { LoginComponent } from './login/login.component';
import {ReactiveFormsModule} from "@angular/forms";
({
declarations: [LoginComponent],
imports: [
CommonModule,
ReactiveFormsModule,
]
})
export class AccountModule {
}
在组件中使用FormControl
然后在LoginComponent
组件的ts中定义FormControl
:
import {FormControl} from '@angular/forms';
({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.scss']
})
export class LoginComponent {
name: FormControl = new FormControl(null);
}
在模板中应用该控件
为表单控件添加formControl
绑定,formControl
是由ReactiveFormsModule
中的FormControlDirective
提供的。
<label for="name">登录名</label>
<input id="name" type="text" [formControl]="name"/>
在模板中板绑定后,就把我们声明的FormControl
表单控件注册给了模板中名为name
的input
输入元素。这样,表单控件和DOM元素就建立了通道,视图模板(view)会反映模型的变化,模型也会接收视图中的变动。
获得表单控件的值
有两种方式获得FormControl
的值:
- 可观察对象
valueChanges
。可以在模板中使用AsyncPipe
或者在组件类中订阅来监听表单的值。 - 使用value属性。可以获得控件的当前值的一份快照。
首先我们在模板中来获取值:
name 的快照值为:{{name.value}}
name 实时监听值: {{name.valueChanges | async}}
可以看到两者基本上是同步变化的。
这里额外说下AsyncPipe
。这个管道是从一个异步回执中获取值。async管道会订阅一个Observable或Promise,并返回它发出的最近的一个值。当新值到来时,async管道就会把该组件标记为需要进行变更检测。当组件被销毁时,async管道就会自动取消订阅,以消除潜在的内存泄露问题。具体可以查看angular async pipe。
然后我们再看看在组件类中以订阅的方式获得控件值变更的方式:
this.name.valueChanges.subscribe(res => {
console.log(res);
});
运行的时候可以看到,这里的输出和页面上基本保持一致的。这个方式的意义在于,我们可以监听字段值的变化,以便于在输入的时候去控制它。可以看看这篇以前写的限制input输入的文章。
更新表单控件的值
FormControl
提供了setValue
方法,可以在组件类中动态修改控件的值,而不依赖交互的输入。
我们先在组件类中添加一个方法,使用setValue
修改name
的值:
updateName() {
this.name.setValue('tony');
}
然后在模板中使用这个方法:
<button (click)="updateName()">修改名字</button>
可以看到,当点击后模板中的所有显示的地方都变化为修改后的值,而且我们的组件类中的监听函数也收到了值的变更。
当然,FormControl
也提供了patchValue
方法来修补控件的值,但它在FormControl
层面上和setValue
没啥区别,这个函数只在FormGroup
和FormArray
上具有不同于setValue
的行为。
禁用/解除禁用表单控件
在表单中这是个很常见的场景了。我们展示表单的时候,希望某个表单控件是被禁用的,无法输入的。
一般做法是直接在模板上给表单控件加上disabled
属性。这个在模板驱动表单的时候是可以的,但是在使用响应式表单的时候直接加disabled的话会出现个提示:
It looks like you're using the disabled attribute with a reactive form directive.....
这个警告是说,你既然使用了响应式表单,那么最好用响应式表单的方式来禁用,不要使用模板的那一套了。
那么我们怎么通过响应式表单的方式来禁用呢?
禁用表单控件
我们在初始化表单控件的时候,是直接使用了new FormControl(null)
这样创建的,来看看FormControl
的初始化参数:
formState
使用初始值或定义了初始值和禁用状态的对象初始化控件。可选,默认是nullvalidatorOrOpts
同步验证器函数或验证器数组。或者包含验证函数和验证触发器的对象。可选。asyncValidator
异步验证器或验证器数组。可选。
我们可以这样在初始化的时候赋值和禁用表单控件:
export class LoginComponent {
name: FormControl = new FormControl({
value: 'tony',
disabled: true,
});
}
运行可以看到,表单控件是已经禁用的状态,也无法输入。
当然,这个禁用是禁用交互输入,在组件类中使用setValue
还是可以变更值的。
PS:需要特别注意,当formState
是对象的时候,那么必须要包含两个属性:value
和disabled
,否则就会当成控件的初始值来显示,模板中会显示[object, Object]。
不仅仅是在初始化的时候禁用,我们可以在初始化之后,通过FormControl
的disable
函数来动态禁用:
ngOnInit() {
this.name.disable();
}
解除禁用
既然能禁用,那么也可以解除禁用,FormControl
提供了disable
和enable
两组,来禁用和解除禁用。
我们在组件类中提供两个方法来禁用和解除禁用:
disableName() {
this.name.disable();
}
enableName() {
this.name.enable();
}
在模板中消费:
<button (click)="disableName()">禁用 name</button>
<button (click)="enableName()">解除禁用name</button>
真是如丝般滑~ 😎
我们可以读取控件的禁用状态,然后用一个按钮综合起来:
nameState() {
if (this.name.disabled) {
this.name.enable();
} else {
this.name.disable();
}
}
在模板中消费:
<button (click)="nameState()">
{{name.disabled ? '启用' : '禁用'}}
name
</button>
FormControl
是响应式表单的基石,先搞清楚这个是基本。后续的FormGroup
和FormArray
的组成对象都是FormControl
。先夯实基础,然后再有上层建筑。