0

I have an abstract class where I mentioned all my http calls and while extending it in child services throws error on compile time.

Can't resolve all parameters for MyService : (?).

baseservice.ts

import { HttpClient, HttpHeaders } from '@angular/common/http';

export abstract class BaseService{

    constructor(private http: HttpClient){} //http undefined on compile time                            

    get(){
       return this.http.get()
    }    
}

myservice.ts

@Injectable()
export class MyService extends BaseService{

  getSource() {
    return this.get('api/Source')
  }
}

If I added other injectTokens in constructor of abstract class this leads to not defined error

constructor(private http: HttpClient, @Inject(APP_CONFIG) private appConfig: any | undefined) {}

Uncaught ReferenceError: http_1 is not defined

if I trying to add Options, it initialising the HttpClient and all working fine

HttpOptions = {
   headers: new HttpHeaders({
    'Authorization': `Bearer ${this.token}`
   })

What is the reason behind this and how to over come this issue while creating instance HttpClient without any InjectTokens or httpOtions.

k11k2
  • 2,036
  • 2
  • 22
  • 36

2 Answers2

2

Your abstract class has a constructor, so...you have to declare the constructor too in the concrete class, and invoke to super:

@Injectable()
export class MyService extends BaseService{

  constructor(private http: HttpClient){
    super(http);
  }

  getSource() {
    return this.get('api/Source')
  }
}
Alan Grosz
  • 1,175
  • 10
  • 15
  • Yea, it will leads to import those modules in derived class also I want to avoid that. Is there any possibility of it. – k11k2 May 02 '18 at 11:32
  • I had a similar case and Instead of making the service abstract and extend from it made the baseclass a normal service and only added the service as dependency to all users. If you extend the baseclass you need to call the super constructor. – tom van green May 02 '18 at 12:05
  • @tomvangreen rn main concern is to avoid `super` if it is not possible I need to follow your suggestion. – k11k2 May 02 '18 at 12:15
  • It is not possible, if you extend a class in typescript you always need to call the super constructor. In my case I thought the base class was the better option, but in the end a separate service was the better solution. – tom van green May 02 '18 at 12:18
  • 1
    This is not true. First of all, a constructor is inherited in child class. If MyService doesn't need its own dependencies, it doesn't need its own constructor. And `private` modifier in child class will result in compilation error. – Estus Flask May 02 '18 at 13:10
0

http: HttpClient metadata should be emitted at compilation time on order to be recognized as dependency injection. Due to how emitting of type metadata works, a decorator should be specified on a class that contains metadata.

In a hierarchy of injectable classes that have dependencies annotated with TypeScript types like http: HttpClient, base class needs @Injectable() decorator:

@Injectable()
export abstract class BaseService{
    constructor(private http: HttpClient) {}                       
}

export class MyService extends BaseService {}

If child class has its own constructor, it needs @Injectable() decorator, too:

@Injectable()
export abstract class BaseService{
    constructor(private http: HttpClient) {}                       
}

@Injectable()
export class MyService extends BaseService {
    constructor(http: HttpClient, private foo: Foo) {
        super(http);
    }                       
}

Because of how @Injectable works, it isn't necessary in classes that use explicit @Inject annotation.

Estus Flask
  • 206,104
  • 70
  • 425
  • 565