Using an injected angular service as a dependency within a static method
Asked Answered
I

2

11

I am trying to use a injected dependency within a static method and of course the injected dependency is instance-scoped and can't be used within the static method.

Here is my class:

@Injectable()
export class PasswordValidationService {

  constructor(private userAccountService:UserAccountService) {
  }

  static passwordValidator(control:AbstractControl) {
    return control
      .valueChanges
      .debounceTime(400)
      .switchMap(()=> this.userAccountService.checkCurrentPassword(control.value))
      .map(res=> {
          if (res.json() === true) {
            return null;
          }
          else {
            return {invalid: true};
          }
        }
      );
  }

}

My question is what is the best practice in order to use the UserAccountService (dependency) within a static method?

edit: I redesigned my app towards using instance methods instead of static methods as follows:

Here is the validator:

import {Injectable} from "@angular/core";
import {UserAccountService} from "../../useraccount/useraccount.service";
import {AbstractControl} from "@angular/common";
import {Observable} from "rxjs/Observable";


@Injectable()
export class PasswordValidationService {

  constructor(private userAccountService:UserAccountService) {
  }

  passwordValidator(control:AbstractControl):Observable<any> {
    let validationResult = this.userAccountService.checkCurrentPassword(control.value)
      .map(res=> {
          if (res.json() === true) {
            return null;
          }
          else {
            return {invalid: true};
          }
        }
      );

    return validationResult;
  }

}

Here is the component using the validator:

constructor(private router:Router,
              private formBuilder:FormBuilder,
              private stylingService:StylingService,
              private sessionService:SessionService,
              private passwordValidationService:PasswordValidationService) {
  }

  ngOnInit() {
    this.signinForm = this.formBuilder.group({
      credentials: this.formBuilder.group({
        username: [this.credentials.username, Validators.required],
        password: [this.credentials.password, [Validators.required, this.passwordValidationService.passwordValidator]]
      })
    });
  }

Here is the error message I get:

browser_adapter.ts:82 TypeError: Cannot read property 'userAccountService' of undefined
    at PasswordValidationService.passwordValidator (http://localhost:8080/app/shared/services/password-validation.service.js:18:36)
    at eval (http://localhost:8080/vendor/@angular/forms/src/validators.js:137:49)
    at Array.map (native)
    at _executeValidators (http://localhost:8080/vendor/@angular/forms/src/validators.js:137:23)
    at FormControl.eval [as validator] (http://localhost:8080/vendor/@angular/forms/src/validators.js:116:33)
    at FormControl.AbstractControl._runValidator (http://localhost:8080/vendor/@angular/forms/src/model.js:178:56)
    at FormControl.AbstractControl.updateValueAndValidity (http://localhost:8080/vendor/@angular/forms/src/model.js:164:29)
    at new FormControl (http://localhost:8080/vendor/@angular/forms/src/model.js:304:14)
    at FormBuilder.control (http://localhost:8080/vendor/@angular/forms/src/form_builder.js:36:16)
    at FormBuilder._createControl (http://localhost:8080/vendor/@angular/forms/src/form_builder.js:68:25)
Inhabitancy answered 19/7, 2016 at 11:2 Comment(0)
D
4

Either don't make the method static or forward from an instance method

export class PasswordValidationService {

  constructor(private userAccountService:UserAccountService) {
  }

  validate(control:AbstractControl) {
    return PasswordValidationService.passwordValidator(control);
  }

  static passwordValidator(control:AbstractControl) {
    ...
  }
}
Deach answered 19/7, 2016 at 11:6 Comment(12)
That doesn't make much sense to me. If it needs to call a static method, there is no point in injecting it. Why does it need a static method?Dipteral
Do you see what I mean? It needs to be in a validator array like so: [Validators.required, ValidationService.passwordValidator]Inhabitancy
Mind you I could always have a function as described here: blog.thoughtram.io/angular/2016/03/14/…Inhabitancy
Why not [injectedValidator.validate]? There is no need for a static method.Dipteral
That's right. A little less cleaner because I need to inject the validator but OK still.Inhabitancy
I don't understand your last comment. What is the whole question about if you don't want to inject it?Dipteral
I wanted to avoid injecting the validator into the component but still inject the userAccountService into the validator.Inhabitancy
I see, I missed that. I don't think there is a clean way to do it without injecting. I'd rather make the static method an instance method and inject the validator.Dipteral
I tried that and I am running into another issue. I have edited my post accordingly.Inhabitancy
Did you provide UserAccountService anywhere?Dipteral
I have yes. In my main's bootstrap method.Inhabitancy
I guess you need to register the validator as [Validators.required, (control) => passwordValidationService.passwordValidator(control)]or ``[Validators.required,passwordValidationService.passwordValidator.bind(passwordValidationService)]to make this` work inside passwordValidatorDipteral
G
1

I used it setting an instance as static somewhere in the app initialization, and then use it.

class AppComponent {
    constructor(private barService: BarService{
        BarService.appInstance = barService
    }
}


class FooUtil{

  doSomethingFancy(){
      //you might even check for BarService.appInstance the way you want to handle it
     BarService.appInstance.somethingEvenMoreFancy()
  }

}
Genitor answered 20/11, 2023 at 15:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.