具有依赖项

时间:2017-01-17 13:20:29

标签: angular dependency-injection dependencies custom-validators

在Angular 2中,我正在尝试创建自己的自定义验证器。

我创建了自己的CustomValidators类,它实现了验证器接口。

import { FormControl } from "@angular/forms";
import { MyhttpService } from "./myhttp.service";
import { Response } from "@angular/http";
import { Injectable, Directive } from '@angular/core';


@Injectable()
export class CustomValidators{

constructor(private _http : MyhttpService){

}

public api(c : FormControl)
{
    // Run 
    this._http.get("/expenses/email?email=" + c.value).subscribe((res:Response) => {
        if(res.status === 200){
            // email exists
            return null;
        } else {
            return {"email" : true}
        }
    });
}

如果我使api成为静态方法,那么我可以成功使用该类。

this._formDetails = fb.group({
  "managerEmail" : ["", [Validators.required, CustomValidators.api] ]
});

然而,当然这是一个静态方法,因此我无法访问任何构造函数值,因为构造函数尚未运行。

因此,我无法找到一种实现具有依赖关系的自定义验证器的方法,必须有办法。

我已经尝试将CustomValidators列为提供者,因此我的类会收到该类的实例化对象。

属性'api'在类型'typeof CustomValidators'上不存在

我是否以正确的方式提供课程?为什么该方法不存在?

2 个答案:

答案 0 :(得分:1)

我使用Angular v5.2.9遇到类似情况,并验证我的数据库中是否已存在用户名。我的用例有点不同 - 我使用的是一个很容易缓存的小用户列表,我的数据是使用@ngrx库集中的,但我希望它有用。

从Validator类开始,构造函数负责生成获取请求并将结果缓存在可观察的静态列表中;实际验证方法将使用此列表observable来查看用户名是否已被使用。

import { Injectable } from '@angular/core'
import { FormControl } from '@angular/forms'

import { Store } from '@ngrx/store'

import { Observable } from 'rxjs/observable'
import 'rxjs/add/operator/take'
import 'rxjs/add/operator/map'

import { myActions } from '../@ngrx/actions/some.actions'
import { State, selectIds } from '../@ngrx/reducers/some.reducer'


@Injectable()
export class CustomValidators {

  static ids_in_use$: Observable<string[]>;

  constructor(
    private store: Store<State>
  ) {
    this.store.dispatch({ type: myActions.FETCH_REQUEST })
    CustomValidators.ids_in_use$ = this.store
      .select( selectIds )
      .map( ( id_list: string[] ) => id_list.map( id => id.toLowerCase() ) )
  }

  static api( control: FormControl ) {
    return new Promise(
      ( resolve ) => {
        CustomValidators.ids_in_use$
          .take( 1 )
          .subscribe(
            id_list => {
              if( id_list.indexOf( control.value.toLowerCase() ) === -1 ) 
                resolve( null )
              else resolve({ 'email-in-use': true })
            })
      })
}

为了避免在静态方法中缺少对实例属性的访问,验证器的构造函数负责设置静态属性。因为这个类是用@Injectable()修饰的,所以它可以依赖注入到使用它的组件的构造函数中:

constructor(
  ...,
  private fb: FormBuilder,
  private customValidators: CustomValidators
) { }

这是我能够确保执行验证器的构造函数中的代码的方法,尽管主验证逻辑是静态方法。类似地,我想你可以使用这个实例来验证你在验证之前特别需要的任何实例属性/方法 - 在你的情况下,发出http请求。然后,我可以在FormBuilder组中使用静态验证方法(请记住,除非您调用它,否则您的tslint会警告您'customValidators' is declared but its value is never read

this._formDetails = fb.group({
  'managerEmail': [ '', Validators.required, CustomValidators.api ]
})

最后,必须为可注入服务声明一个提供者,这可以在@Component装饰器中完成:

@Component({
  ...,
  providers: [ CustomValidators ]
})

答案 1 :(得分:0)

试试这个:

this._formDetails = fb.group({
  "managerEmail" : ["", Validators.required, CustomValidators.api]
});

Validators.required是同步验证器,但您的CustomValidators.api是异步验证器。

Per the official documentation,每个表单控件都应使用state,synchronous validator(s)和async validator(s)指定。