Angular 11 反应形式 onchange 验证以检查重复值
Angular11 reactive form on change validate to check for duplicate value
我正在使用 Angular 11 并使用 formcontrolname 'name' 创建一个简单的响应式表单。
当用户在此字段中键入时,我需要验证唯一性。我尝试了以下操作,但每次我输入内容时它都会验证,但我想使用 debouncetime 并使用类似的逻辑。不确定如何用反应形式做到这一点
谁能帮我实现这个目标?
我最终得到以下 AsyncVaildator。如果可以简化,有人可以帮助我吗?因为我正在将服务传递给方法。有没有办法在这里使用依赖注入?
export class TemplateNameValidator {
createValidator(auditTemplateService: AuditTemplateService): AsyncValidatorFn {
console.log("Static factory call");
return (control: AbstractControl): Observable<ValidationErrors> => {
if(isEmptyInputValue(control.value)) {
return of(null);
} else {
return control.valueChanges.pipe(
debounceTime(500),
distinctUntilChanged(),
take(1),
switchMap((name: string) =>
auditTemplateService.isNameUnique(name)
.pipe(
map(isUnique => !isUnique ? { 'duplicate': true } : null)
)
)
);
}
};
}
}
function isEmptyInputValue(value: any): boolean {
return value === null || value.length === 0;
}
private registerFormGroup(): void {
this.nameField = new FormControl(
{ value: this.auditTemplate.title, disabled: true },
[Validators.compose([
Validators.required,
(control) => this.isNameUnique(control as AbstractControl)
])]
);
this.templateForm = this.formBuilder.group({
templateName: this.nameField,
tags: [this.auditTemplate.tags]
});
}
检查唯一性的验证:
isNameUnique(formField: AbstractControl): { [key: string] : any} {
const nameEntered = formField.value;
let isDuplicate = false;
if(nameEntered && this.availableNames) {
const index = this.availableNames.findIndex(templateName =>
templateName.name === nameEntered);
if(index !== -1) {
isDuplicate = true;
}
}
return isDuplicate ? { 'duplicate': true } : null;
}
谢谢
我确信这个问题有很多解决方案,简而言之,文档 https://angular.io/guide/form-validation#implementing-a-custom-async-validator.
中对此进行了描述
但是,如何使用异步验证器并不是很明显。所以一个最小的例子可能是这样的:
const myValidator: AsyncValidatorFn = (control: AbstractControl) => of(control.value)
.pipe(
delay(1000),
map(value => {
if (value === '1') {
return null;
}
return { invalid: true } as ValidationErrors;
}),
tap(console.log),
finalize(() => console.log('async validator unsubscribed')),
);
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
control = new FormControl('', Validators.required, myValidator);
}
现场演示:https://stackblitz.com/edit/angular-ivy-mk4wyv?file=src%2Fapp%2Fapp.component.ts
验证器从 control
中获取最新值,延迟它然后执行一些检查。在这种情况下,仅当您在输入字段中键入 "1"
时验证器才会通过。
请注意,去抖是由 delay()
执行的,没有使用 debounceTime()
运算符。这是因为在每次控制值更改时都会调用验证方法,并且需要 return 发出并完成的 Observable。如果有另一个待验证的 Observable,Angular 将取消订阅它并订阅新的 Observable。这就是为什么您会在控制台中看到许多 'async validator unsubscribed'
日志。
最后一件事,异步验证器作为另一个参数传递给 FormControl
,而不是在常规验证器中:
new FormControl('', Validators.required, myValidator)
我正在使用 Angular 11 并使用 formcontrolname 'name' 创建一个简单的响应式表单。 当用户在此字段中键入时,我需要验证唯一性。我尝试了以下操作,但每次我输入内容时它都会验证,但我想使用 debouncetime 并使用类似的逻辑。不确定如何用反应形式做到这一点
谁能帮我实现这个目标?
我最终得到以下 AsyncVaildator。如果可以简化,有人可以帮助我吗?因为我正在将服务传递给方法。有没有办法在这里使用依赖注入?
export class TemplateNameValidator {
createValidator(auditTemplateService: AuditTemplateService): AsyncValidatorFn {
console.log("Static factory call");
return (control: AbstractControl): Observable<ValidationErrors> => {
if(isEmptyInputValue(control.value)) {
return of(null);
} else {
return control.valueChanges.pipe(
debounceTime(500),
distinctUntilChanged(),
take(1),
switchMap((name: string) =>
auditTemplateService.isNameUnique(name)
.pipe(
map(isUnique => !isUnique ? { 'duplicate': true } : null)
)
)
);
}
};
}
}
function isEmptyInputValue(value: any): boolean {
return value === null || value.length === 0;
}
private registerFormGroup(): void {
this.nameField = new FormControl(
{ value: this.auditTemplate.title, disabled: true },
[Validators.compose([
Validators.required,
(control) => this.isNameUnique(control as AbstractControl)
])]
);
this.templateForm = this.formBuilder.group({
templateName: this.nameField,
tags: [this.auditTemplate.tags]
});
}
检查唯一性的验证:
isNameUnique(formField: AbstractControl): { [key: string] : any} {
const nameEntered = formField.value;
let isDuplicate = false;
if(nameEntered && this.availableNames) {
const index = this.availableNames.findIndex(templateName =>
templateName.name === nameEntered);
if(index !== -1) {
isDuplicate = true;
}
}
return isDuplicate ? { 'duplicate': true } : null;
}
谢谢
我确信这个问题有很多解决方案,简而言之,文档 https://angular.io/guide/form-validation#implementing-a-custom-async-validator.
中对此进行了描述但是,如何使用异步验证器并不是很明显。所以一个最小的例子可能是这样的:
const myValidator: AsyncValidatorFn = (control: AbstractControl) => of(control.value)
.pipe(
delay(1000),
map(value => {
if (value === '1') {
return null;
}
return { invalid: true } as ValidationErrors;
}),
tap(console.log),
finalize(() => console.log('async validator unsubscribed')),
);
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
control = new FormControl('', Validators.required, myValidator);
}
现场演示:https://stackblitz.com/edit/angular-ivy-mk4wyv?file=src%2Fapp%2Fapp.component.ts
验证器从 control
中获取最新值,延迟它然后执行一些检查。在这种情况下,仅当您在输入字段中键入 "1"
时验证器才会通过。
请注意,去抖是由 delay()
执行的,没有使用 debounceTime()
运算符。这是因为在每次控制值更改时都会调用验证方法,并且需要 return 发出并完成的 Observable。如果有另一个待验证的 Observable,Angular 将取消订阅它并订阅新的 Observable。这就是为什么您会在控制台中看到许多 'async validator unsubscribed'
日志。
最后一件事,异步验证器作为另一个参数传递给 FormControl
,而不是在常规验证器中:
new FormControl('', Validators.required, myValidator)