【问题标题】:How to pass params to async validator for reactive angular control?如何将参数传递给异步验证器以进行反应性角度控制?
【发布时间】:2018-04-06 21:49:59
【问题描述】:

问题,

我将相同的组件用于读取/编辑例程。 async-validator 与新条目完美配合。如果用户不小心更改了值并尝试恢复为保存的值,问题就开始了。我当前的代码将无论如何运行并将值返回为现有值。我想传递更多数据以及控制值,以便验证该对值是否已经存在。

我正在发布相关代码,

这是我的form control

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);
    };
  }

最后是我的服务,

@Injectable()
export class AsyncValidationService {
  constructor(private httpService: HttpClientService) {}

  public validateEmailNotTaken(control: AbstractControl) {
    return this.httpService.getRequest(
      'PatientsRegistration/IsPatientEmailExist?email=' + control.value,
    );
  }
}

我希望能够将另一个参数传递给我的createEmailAsyncValidator,如果可能的话,类似于表单中的另一个控制值。

【问题讨论】:

  • 您是否需要基于另一个控件来验证电子邮件?如果是这样,最佳实践是将验证器提升到父控件。如果需要,我可以提供示例。
  • @TomaszKula,电子邮件控件属于formGroup,我需要将电子邮件控件与另一个分组吗?我会很感激这个例子
  • 好的,给我 10 分钟,我会为你创造一些东西 :)
  • @TomaszKula,谢谢 :)

标签: angular angular-reactive-forms angular-validation


【解决方案1】:

如果需要基于另一个控件验证控件,则需要将验证器提升到父控件。这是一个验证器示例,用于检查电子邮件是否以人名(另一个控制值)开头。

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'}}

Live demo

【讨论】:

  • 在这种情况下personalEmailValidator 会运行async 吗?
  • 在我的示例中,我使用了一个简单的验证功能。如果您需要执行一些 http 请求,最好将验证器实现为常规类并实现 AsyncValidator 接口。这样你就可以将 http 注入到构造函数中,在 validate 方法中做任何你需要的异步操作。
  • 你能告诉我一个关于如何将异步功能添加到组验证器的简短示例吗?
【解决方案2】:

所以我以另一种方式工作,灵感来自Tomasz Kula answer

我创建了一个异步Directive 实现AsyncValidator 接口, 我将额外的参数作为“对象”传递,在我的情况下,它看起来像这样,

{
 coupledControl: AbstractControl,
 method: {
          apiUrl: string
         }
} 

这是我的directive 代码,

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);
  }
}

在我的HTML

 <input [asyncValidator]="{coupledControl: patientRestrationForm.get('patientFileId'), method: this.asyncMethods.validatePatientEmail }" [errorStateMatcher]="matcher" matInput autocomplete="off" formControlName="patientEmail">

在我的后端我检查存在和匹配,简单的逻辑!

不胜感激,

【讨论】:

    猜你喜欢
    • 2014-08-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多