Access a service from a custom validator in Angular2
Asked Answered
F

3

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?

Fogged answered 19/2, 2016 at 12:35 Comment(2)
Could you please put more snippet of your code?Regenaregency
What is HTTPService? Put snippet of it.Regenaregency
O
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)
Oulu answered 19/2, 2016 at 13:8 Comment(2)
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?Cattle
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; } } }Redford
C
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.

Carswell answered 19/2, 2016 at 12:53 Comment(5)
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 ?Fogged
Sure, if you use it as directive than the HttpService can be injected directly. I assumed FormBuilder.Monroe
Thanks for your answer, after it I implemented the same thing Thierry gave, so I accepted his answer.Fogged
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')Tricornered
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.Monroe
S
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
    ],
  });
}
Startle answered 12/10, 2018 at 15:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.