Angular 使用 ControlValueAccessor 时的表单控件验证
Angular form control validation when using ControlValueAccessor
在父组件中我定义了表单。
cartForm = new FormGroup({
company: new FormControl('', [Validators.required]),
costCenter: new FormGroup({
account: new FormControl('', [Validators.required]),
activity: new FormControl('', [Validators.required, Validators.maxLength(5), Validators.minLength(5)]),
project: new FormControl('', [Validators.required, Validators.minLength(3), Validators.maxLength(10)]),
})
});
然后在子组件中使用 formControl project
。在此组件中,我需要自定义验证,只需添加
即可实现
validate(control: AbstractControl): ValidationErrors | null {
// To my validation here
}
除了在父组件中指定的 Validators
被覆盖外,这有效。
第二种方法是创建一个自定义验证器class..但是我无法从组件中获取@Input..?
更新:这是组件
@Component({
selector: 'ssp-project',
templateUrl: './project.component.html',
styleUrls: ['./project.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ProjectComponent implements ControlValueAccessor, OnInit {
@Input('companyNumber') set companyNumber(companyNumber: string) {
this._companyNumber = companyNumber;
}
private _companyNumber: string;
constructor(
@Optional() @Self() public ngControl: NgControl,
) {
if (this.ngControl != null) {
// Setting the value accessor directly (instead of using the providers) to avoid running into a circular import.
this.ngControl.valueAccessor = this;
}
}
onTouched = (_value?: any) => { };
onChanged = (_value?: any) => { };
writeValue(val: string): void {
if (val) {
this.ngControl.control?.setValue(val);
}
}
registerOnChange(fn: any): void {
this.onChanged = fn;
}
registerOnTouched(fn: any): void {
this.onTouched = fn;
}
registerOnValidatorChange(fn: any): void {
this.onChanged = fn;
}
ngOnInit() {
// this.ngControl.control.setValidators([this.validate.bind(this)]);
this.ngControl.control.setValidators(this.ngControl.control.validator ? [this.ngControl.control.validator, this.validate] : this.validate);
this.ngControl.control.updateValueAndValidity();
}
validate(control: AbstractControl): ValidationErrors | null {
if (this._companyNumber && control.value) {
return this._costCenterService
.validateProject(control.value, this._companyNumber)
.pipe(
debounceTime(3000),
map(projectIsValid => {
return { invalid: !projectIsValid };
})
).subscribe();
}
}
}
您可以使用 FormControl
的 validator
属性 将验证器添加到现有验证器列表中
control.setValidators(control.validator ? [ control.validator, this.validate ] : this.validate);
编辑:由于在问题中添加了代码,焦点已转移到异步验证器上。例如:
control.setAsyncValidators(
control.asyncValidator
? [control.asyncValidator, this.asyncValidator]
: this.asyncValidator
);
// definition of asyncValidator
asyncValidator(ctrl: AbstractControl): Observable<ValidationErrors | null> {
// Whatever your validation does asynchronously
return of(null);
}
在父组件中我定义了表单。
cartForm = new FormGroup({
company: new FormControl('', [Validators.required]),
costCenter: new FormGroup({
account: new FormControl('', [Validators.required]),
activity: new FormControl('', [Validators.required, Validators.maxLength(5), Validators.minLength(5)]),
project: new FormControl('', [Validators.required, Validators.minLength(3), Validators.maxLength(10)]),
})
});
然后在子组件中使用 formControl project
。在此组件中,我需要自定义验证,只需添加
validate(control: AbstractControl): ValidationErrors | null {
// To my validation here
}
除了在父组件中指定的 Validators
被覆盖外,这有效。
第二种方法是创建一个自定义验证器class..但是我无法从组件中获取@Input..?
更新:这是组件
@Component({
selector: 'ssp-project',
templateUrl: './project.component.html',
styleUrls: ['./project.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ProjectComponent implements ControlValueAccessor, OnInit {
@Input('companyNumber') set companyNumber(companyNumber: string) {
this._companyNumber = companyNumber;
}
private _companyNumber: string;
constructor(
@Optional() @Self() public ngControl: NgControl,
) {
if (this.ngControl != null) {
// Setting the value accessor directly (instead of using the providers) to avoid running into a circular import.
this.ngControl.valueAccessor = this;
}
}
onTouched = (_value?: any) => { };
onChanged = (_value?: any) => { };
writeValue(val: string): void {
if (val) {
this.ngControl.control?.setValue(val);
}
}
registerOnChange(fn: any): void {
this.onChanged = fn;
}
registerOnTouched(fn: any): void {
this.onTouched = fn;
}
registerOnValidatorChange(fn: any): void {
this.onChanged = fn;
}
ngOnInit() {
// this.ngControl.control.setValidators([this.validate.bind(this)]);
this.ngControl.control.setValidators(this.ngControl.control.validator ? [this.ngControl.control.validator, this.validate] : this.validate);
this.ngControl.control.updateValueAndValidity();
}
validate(control: AbstractControl): ValidationErrors | null {
if (this._companyNumber && control.value) {
return this._costCenterService
.validateProject(control.value, this._companyNumber)
.pipe(
debounceTime(3000),
map(projectIsValid => {
return { invalid: !projectIsValid };
})
).subscribe();
}
}
}
您可以使用 FormControl
的validator
属性 将验证器添加到现有验证器列表中
control.setValidators(control.validator ? [ control.validator, this.validate ] : this.validate);
编辑:由于在问题中添加了代码,焦点已转移到异步验证器上。例如:
control.setAsyncValidators(
control.asyncValidator
? [control.asyncValidator, this.asyncValidator]
: this.asyncValidator
);
// definition of asyncValidator
asyncValidator(ctrl: AbstractControl): Observable<ValidationErrors | null> {
// Whatever your validation does asynchronously
return of(null);
}