angular11源码探索十三[表单基础篇二]
statusChanges
statusChanges: Observable
每次验证的状态,参数 status
new FormControl({value: '', disabled: true} 禁用也可以这样写
当我们手动设置报错
const login = new FormControl('someLogin');
login.setErrors({
notUnique: true
});
login.valid //false, 是否通过校验
login.setValue('aaa')
login.valid //true
get查询方式
profileForm: FormGroup = new FormGroup({
address: new FormGroup({
name1: new FormControl()
})
});
this.profileForm.get('address.name1');
this.profileForm.get(['address', 'name1']);
两种形式等价
getError/hasError 区别
查找方式
get('xxx')
get('aaa.bbb')
get(['aaa','bbb'])
get(['aaa',0]) // 数字就是索引
hasError 报错查找
this.profileForm.get(['address','name1'])?.setErrors({aaa:true})// 设置报错
console.log(this.profileForm.get(['address', 'name1'])?.hasError('aaa'));
等价
console.log(this.profileForm?.hasError('aaa', ['address', 'name1']));// true
源码
getError(errorCode: string, path?: Array<string|number>|string): any {
const control = path ? this.get(path) : this;
return control && control.errors ? control.errors[errorCode] : null;
}
hasError(errorCode: string, path?: Array<string|number>|string): boolean {
return !!this.getError(errorCode, path);
}
却别应该是返回类型不一样吧,而且两者本质上就是父子关系,
上个小案例
let aa = this.profileForm.get('firstName') as FormControl;
aa.setErrors({'aaa': '333'});
console.log(aa.getError('aaa'));// 333
console.log(aa.hasError('aaa'));// true
addControl 添加
(this.profileForm.get('address') as FormGroup).addControl('newControl', new FormControl(''));
this.profileForm.addControl('name1',new FormControl())
console.log(this.profileForm.value);
removeControl
this.profileForm.removeControl('address')
当删除或者增加的时候,页面没有生效,其实应该在OnInit 生命周期中添加
ngModel双向绑定
<input type="text" [(ngModel)]="sex" (ngModelChange)="changeA($event)">
校验器
pristine 为修改UI中的值,默认为true 干净
dirty 修改过UI的值,默认为false 脏的
两个的默认值时相反的
touched 类似触碰,失去焦点,默认是false
untouched 未接触,默认为true
异步验证的时候,表单控件进入 pending状态,默认false,并使用它提供有关正在进行的验证操作的视觉反馈
促发每一个子项是不是纯洁的
.markAsDirty() // pristine dirty 一般用这个
促发每一个子项touched是否动过
.markAsTouched/
有效性(就是是否禁用)
VALID: 该控件通过了所有有效性检查。
INVALID 该控件至少有一个有效性检查失败了。
PENDING:该控件正在进行有效性检查,处于中间状态。
DISABLED:该控件被禁用,豁免了有效性检查。
是否通过校验
.valid
显示报错信息
.errors
一般第二个参数用于校验,给数组整体添加校验
//第一个参数不能与aaa
function simpleValidator(c: AbstractControl): ValidationErrors|null {
//c.get([0]) 和 c.at(0) 类似
return c.get([0])!.value === 'aaa' ? null : {'broken': true};
}
//第一个参数必须传
function arrayRequiredValidator(c: AbstractControl): ValidationErrors|null {
return Validators.required(c.get([0]) as AbstractControl);
}
this.nameArr.valueChanges.subscribe(res => {
//是否通过校验
console.log(this.nameArr.valid);
// 报错信息
console.log(this.nameArr.errors);
})
nameArr: FormArray = new FormArray([
new FormControl('bb'),
],
[simpleValidator,arrayRequiredValidator]
)
pending
异步验证的时候,表单控件进入 pending状态,默认false,并使用它提供有关正在进行的验证操作的视觉反馈
function arrayRequiredValidator(c: AbstractControl): ValidationErrors | null {
return of({name1: true}).pipe(delay(500))
}
this.profileForm = new FormGroup({
firstName: new FormControl('xxx', null!, arrayRequiredValidator),
})
let aa = this.profileForm.get('firstName') as FormControl;
console.log(aa.pending);// true
of(null).pipe(delay(1000)).subscribe(_ => {
console.log(this.profileForm.get('lastName').pending);// false
})
markAsPending() 手动设置
console.log(this.profileForm.get('lastName').pending);//true
this.profileForm.get('lastName').markAsPending()
console.log(this.profileForm.get('lastName').pending);// false
默认直属父级也会被修改为true
c = new FormControl('value');
g = new FormGroup({'one': c});
c.markAsPending();
g.pending //true
源码
markAsPending(opts: {onlySelf?: boolean, emitEvent?: boolean} = {}): void {
(this as {status: string}).status = PENDING;
if (opts.emitEvent !== false) {
(this.statusChanges as EventEmitter<any>).emit(this.status);
}
if (this._parent && !opts.onlySelf) {
this._parent.markAsPending(opts);
}
}
校验器源码
function isEmptyInputValue(value: any): boolean {
// 这里我们不检查字符串,所以它也适用于数组
return value == null || value.length === 0;
}
function hasValidLength(value: any): boolean {
// 判断有值得
return value != null && typeof value.length === 'number';
}
疑问为什么有时候可以写单个值,有时候写数组,因为他是第二个参数,多个就写数组,单个就直接写单个值就行了
min
最小值,输入number 比较大小
const control = new FormControl(2, Validators.min(3))
//actual 当前值
console.log(control.errors); // {min: {min: 3, actual: 2}}
const control = new FormControl(16, Validators.max(15));
console.log(control.errors); // {max: {max: 15, actual: 16}}
可以用来限制min max的number 值
上个源码吧
static max(max: number): ValidatorFn {
return (control: AbstractControl): ValidationErrors|null => {
if (isEmptyInputValue(control.value) || isEmptyInputValue(max)) {
return null; // 不要验证空值来允许可选控件
}
const value = parseFloat(control.value);
// 不是NaN然后比较大小
return !isNaN(value) && value > max ? {'max': {'max': max, 'actual': control.value}} : null;
};
}
决定自己的高度的是你的态度,而不是你的才能
记得我们是终身初学者和学习者
总有一天我也能成为大佬