18

I need to access my custom http service from inside a static method, as example:

import {Control} from 'angular2/common';
import {HttpService} from './http.service';

class UsernameValidator {
    static usernameExist(control: Control): Promise<ValidationResult> { 
        ... /* Access my HTTPservice here */
    }
}

How can I access a service in this case?

Silencer
  • 1,602
  • 4
  • 17
  • 27

3 Answers3

10

Another approach consists in returning a function. This way this function can have access to HttpService instance provided during creation:

class UsernameValidator {
  static createUsernameExist(http:HttpService) {
    return (control: Control) => { 
      ... /* Access my HTTPservice here */
    }
  }
}

You can then use it like that:

validator: UsernameValidator.createUsernameExist(this.httpService)
Thierry Templier
  • 198,364
  • 44
  • 396
  • 360
  • When initializing FormControl like this: `username: ['', [Validators.required, UsernameValidator.createUsernameExist(this.httpService)]]` I'm receiving an error "TypeError: UsernameValidator.createUsernameExist is not a function", how to make this work? – mdziob Oct 04 '16 at 16:36
  • 1
    I'm following this example and I can see the log output of each case but my field is never valid. What should the service call look like? This is what I'm using. return (control: Control) => { ... /* Access my HTTPservice here */ return myService.getStuff().subscribe( data => { if(bad){ return {bad:true} }else { return null; } } } – Adam Mendoza Apr 07 '17 at 03:44
3
class UsernameValidator {
    constructor(http:HttpService){}

    usernameExist(control: Control): Promise<ValidationResult> { 
        ... /* Access my HTTPservice here */
    }
}

then use it like

validator: new UsernameValidator(http).usernameExist

The HttpService needs to be injected in the component constructor instead and then passed to the manually created validator instance as shown above.

Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • So I have to create new objects for each async Validator ? Would it be a good idea to implement my validator like the built-in `Validators.minLength(12)` and pass the http as the parameter ? – Silencer Feb 19 '16 at 12:58
  • Sure, if you use it as directive than the `HttpService` can be injected directly. I assumed FormBuilder. – Günter Zöchbauer Feb 19 '16 at 13:02
  • Thanks for your answer, after it I implemented the same thing Thierry gave, so I accepted his answer. – Silencer Feb 19 '16 at 13:43
  • is this still the way to go? I would hope that Validators could be instatiated and dependency-injected automatically (I dont want to call 'new') – Tobias Gassmann Aug 09 '17 at 15:08
  • 1
    There is nothing wrong with new, but you can also make it a service and inject it. It's up to you which way you chose. – Günter Zöchbauer Aug 09 '17 at 15:10
1

Using Günter Zöchbauer's answer this is how I implemented my validator to access services from inside the AsyncValidatorFn ...

IMHO it seems cleaner to let the DI inject the service dependencies directly into the validator class instead of passing the dependencies to a static method from the consumer component to create the AsyncValidatorFn.

Create your injectable validator class

import { Injectable } from '@angular/core';
import { AbstractControl, AsyncValidatorFn, ValidationErrors } from '@angular/forms';

@Injectable
export class UsernameValidator {
  constructor(
    private http: HttpService,
  ) { }

  usernameExists: AsyncValidatorFn = (control: AbstractControl): Observable<ValidationErrors> => {
    // access your HttpService here...
  }
}

Provide validator for injection in your module declaration

@NgModule({
  providers: [
    UsernameValidator, // register your validator for injection
  ],
})
export class UserModule { }

Set validator function in your component form

constructor(
  private formBuilder: FormBuilder,
  private usernameValidator: UsernameValidator, // inject your validator
) { }

ngOnInit() {
  this.form = this.formBuilder.group({
    username: [
      null, // initial value
      [Validators.required], // sync validators
      [this.usernameValidator.usernameExists], // async validators
    ],
  });
}
j3ff
  • 5,719
  • 8
  • 38
  • 51