Search code examples
angulartypescriptangular2-formsangular2-injection

Angular2 RC6 HttpModule manual injection


I'm migrating a project from angular2 RC4 to RC6 and I have a custom Form Validator which needs Http. Before the migration I used the ReflectiveInjector with the HTTP_PROVIDERS, but with RC6 this is not possible anymore as HTTP_PROVIDERS is deprecated, respectively not present anymore. This is the static method in the Validator:

    static checkVat(control: FormControl) {
    let checkVatUrl = "http://localhost:8080/checkvat";


    let injector = ReflectiveInjector.resolveAndCreate([HTTP_PROVIDERS]);
    let http = injector.get(Http);
    let authHttp = new AuthHttp(new AuthConfig(), http);

    if (control.value === "") {
        return new Observable((obs: any) => {
            obs.next(null);
            obs.complete();
        });
    } else {
        return authHttp.get(checkVatUrl + "/" + control.value)
            .map((data: Response) => {
                if (data.json().valid) {
                    return null;
                } else {
                    let reason = "isNotValidVat";
                    return {[reason]: true};
                }
            })
            .catch(function (e) {
                return new Observable((obs: any) => {
                    obs.complete();
                });
            });
    }
}

Just replacing HTTP_PROVIDERS with HttpModule didn't work, I found a similar problem here on stackoverflow (NG2 RC5: HTTP_PROVIDERS is deprecated) regarding testing, but the only answer is specific for testing.

How do I manually "inject" Http or HttpModule with RC6, if there is another or better solution for this custom Validator I'm open to that too.

Thanks in advance.

UPDATE: The checkVat method is static, that is why I had to use the ReflectiveInjector and not just inject it via the constructor, like everywhere else. The custom Validator gets used like this:

this.vatCtrl = new FormControl("", Validators.compose([Validators.pattern(this.vatService.vatPattern)]),VatValidator.checkVat);

UPDATE2: With the help of Günther Zöchbauer's answer I changed the Code as follows to get it working without a static function and no need for manual injection:

The Validator:

@Injectable()

export class VatValidator {

constructor(private http: Http) {
}

checkVat(control: FormControl) {

    let checkVatUrl = "http://localhost:8080/checkvat";

    let authHttp = new AuthHttp(new AuthConfig(), this.http);

    if (control.value === "") {
        return new Observable((obs: any) => {
            obs.next(null);
            obs.complete();
        });
    } else {
        return authHttp.get(checkVatUrl + "/" + control.value)
            .map((data: Response) => {
                if (data.json().valid) {
                    return null;
                } else {
                    let reason = "isNotValidVat";
                    return {[reason]: true};
                }
            })
            .catch(function (e) {
                return new Observable((obs: any) => {
                    obs.complete();
                });
            });
    }

}

}

In the component which has the FormControl:

    constructor(private vatValidator: VatValidator) {

    this.vatCtrl = new FormControl("", Validators.compose([Validators.pattern(vatPattern)]), this.vatValidator.checkVat.bind(this.vatValidator));

}

Solution

  • If you change your validator class a bit, you don't need a static method

    @Injectable()
    class PatternValidator {
      constructor(private http:Http){}
    
      // this is a method that returns a validator function  
      // configured with a pattern
      pattern(pattern) {
        return (control:Control) => {
          this.http.get(...)
    
        ...
        }
      }
    }
    

    You can use it like:

    • inject it to your component so DI passes it's dependencies in (Http)
    constructor(private pattern:PatternValidator) {}
    
    • pass it with bind(pattern) so .this keeps working inside the validator function
    this.vatCtrl = new FormControl("", 
        Validators.compose([
            this.pattern(this.vatService.vatPattern).bind(this.pattern)
        ]), VatValidator.checkVat);
    

    See also Inject Http manually in angular 2