Angular 如何将参数传递给异步验证器以进行被动角度控制? 问题
我对读取/编辑例程使用相同的组件<代码>异步验证器与新条目完美配合。如果用户意外更改了值并试图恢复到保存的值,则问题开始出现。我的当前代码将不受影响地运行,并返回现有值。我希望传递更多数据和控制值,以便验证该对值是否已经存在 我正在发布相关代码 这是我的Angular 如何将参数传递给异步验证器以进行被动角度控制? 问题,angular,angular-reactive-forms,angular-validation,Angular,Angular Reactive Forms,Angular Validation,我对读取/编辑例程使用相同的组件异步验证器与新条目完美配合。如果用户意外更改了值并试图恢复到保存的值,则问题开始出现。我的当前代码将不受影响地运行,并返回现有值。我希望传递更多数据和控制值,以便验证该对值是否已经存在 我正在发布相关代码 这是我的表单控件 patientEmail: new FormControl( null, [Validators.email, Validators.required], FormControlValidator.createEmail
表单控件
patientEmail: new FormControl(
null,
[Validators.email, Validators.required],
FormControlValidator.createEmailAsyncValidator(
this.asyncValidatorService
),
),
我的异步验证器创建者类是
export class FormControlValidator {
static createEmailAsyncValidator(asyncValidatorService: AsyncValidationService) {
return (control: AbstractControl) => {
if (!control.pristine) {
control.markAsPristine();
return asyncValidatorService
.validateEmailNotTaken(control)
.map((response: HttpResponse<boolean>) => {
return !response.body ? null : { taken: true };
});
}
return Observable.of(null);
};
}
我希望能够将另一个参数传递给我的
createEmailAsyncValidator
,如有可能,类似于表单中的另一个控件值。如果需要基于另一个控件验证控件,则需要将验证程序提升到父控件。下面是一个验证器示例,它检查电子邮件是否以人名(另一个控制值)开头
app.component.ts
import { Component } from '@angular/core';
import {FormBuilder, FormControl, FormGroup, ValidatorFn} from '@angular/forms'
const personalEmailValidator: ValidatorFn = (ctrl: FormGroup) => {
const email = ctrl.get('email') as FormControl;
const name = ctrl.get('name') as FormControl;
const valid = (email.value || '').startsWith(name.value);
return valid ? null : { personalEmailError: 'Email must start with a person name'}
}
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
form: FormGroup;
constructor(private fb: FormBuilder) {
this.form = this.fb.group({
email: [null],
name: [null]
}, { validator: personalEmailValidator })
}
}
app.component.html
<input [formControl]="form.get('name')" placeholder="name" />
<input [formControl]="form.get('email')" placeholder="email" />
{{ form.hasError('personalEmailError') ? form.getError('personalEmailError') : 'form is valid'}}
{{form.hasError('personalEmailError')?form.getError('personalEmailError'):'form is valid'}
所以我用另一种方式,灵感来自 我创建了一个异步
指令
,它实现了异步验证器
接口,
我将额外的参数作为`对象传递,在我的例子中,它看起来是这样的
{
coupledControl: AbstractControl,
method: {
apiUrl: string
}
}
这是我的指令
代码
import { Directive, forwardRef, Input } from '@angular/core';
import { NG_ASYNC_VALIDATORS, Validator, AbstractControl } from '@angular/forms';
import { Observable } from 'rxjs/Observable';
import { HttpClientService } from '../../../../../shared/services/httpclient.service';
import { HttpResponse } from '@angular/common/http';
import { IAsyncMethod } from './../interfaces/async-methods-interface';
@Directive({
// tslint:disable-next-line:directive-selector
selector: '[asyncValidator][formControlName], [asyncValidator][ngModel]',
providers: [
{
provide: NG_ASYNC_VALIDATORS,
useExisting: forwardRef(() => AsynValidatorDirective),
multi: true,
},
],
})
export class AsynValidatorDirective implements Validator {
@Input() asyncValidator: { coupledControl: AbstractControl; method: IAsyncMethod };
validate(
control: AbstractControl,
): Promise<{ [key: string]: any }> | Observable<{ [key: string]: any }> {
return this.validateIsExistAsync(control);
}
constructor(private httpService: HttpClientService) {}
validateIsExistAsync(control: AbstractControl) {
if (!control.pristine) {
const coupledControl: AbstractControl = this.asyncValidator.coupledControl;
const method: IAsyncMethod = this.asyncValidator.method;
return this.httpService
.getRequest(method.apiUrl + '?control=' + control.value + '&id=' + coupledControl.value)
.map((response: HttpResponse<boolean>) => {
return !response.body ? null : { asyncInvalid: true };
});
}
return Observable.of(null);
}
}
在我的后端,我检查存在和匹配,简单的逻辑
如果您有任何意见,将不胜感激。您是否需要基于其他控件验证电子邮件?如果是这样,最佳实践是将验证器提升到父控件。如果需要,我可以提供示例。@TomaszKula,电子邮件控件属于
formGroup
,是否需要将电子邮件控件与另一个控件分组?我会很感激这个例子当然,给我10分钟,我会为你创建一些东西:)@TomaszKula,谢谢:)在这种情况下,personalEmailValidator
会运行async
吗?在我的例子中,我使用了一个简单的验证函数。如果您需要执行一些http请求,那么最好将验证器作为常规类实现,并实现AsyncValidator
接口。通过这种方式,您可以将http注入构造函数,在validate
方法中执行您需要的任何异步操作。您可以给我演示一个简单的示例,说明如何将异步功能添加到组验证器中吗?
import { Directive, forwardRef, Input } from '@angular/core';
import { NG_ASYNC_VALIDATORS, Validator, AbstractControl } from '@angular/forms';
import { Observable } from 'rxjs/Observable';
import { HttpClientService } from '../../../../../shared/services/httpclient.service';
import { HttpResponse } from '@angular/common/http';
import { IAsyncMethod } from './../interfaces/async-methods-interface';
@Directive({
// tslint:disable-next-line:directive-selector
selector: '[asyncValidator][formControlName], [asyncValidator][ngModel]',
providers: [
{
provide: NG_ASYNC_VALIDATORS,
useExisting: forwardRef(() => AsynValidatorDirective),
multi: true,
},
],
})
export class AsynValidatorDirective implements Validator {
@Input() asyncValidator: { coupledControl: AbstractControl; method: IAsyncMethod };
validate(
control: AbstractControl,
): Promise<{ [key: string]: any }> | Observable<{ [key: string]: any }> {
return this.validateIsExistAsync(control);
}
constructor(private httpService: HttpClientService) {}
validateIsExistAsync(control: AbstractControl) {
if (!control.pristine) {
const coupledControl: AbstractControl = this.asyncValidator.coupledControl;
const method: IAsyncMethod = this.asyncValidator.method;
return this.httpService
.getRequest(method.apiUrl + '?control=' + control.value + '&id=' + coupledControl.value)
.map((response: HttpResponse<boolean>) => {
return !response.body ? null : { asyncInvalid: true };
});
}
return Observable.of(null);
}
}
<input [asyncValidator]="{coupledControl: patientRestrationForm.get('patientFileId'), method: this.asyncMethods.validatePatientEmail }" [errorStateMatcher]="matcher" matInput autocomplete="off" formControlName="patientEmail">