1

Hi everyone, i'm new with Angular and I am having troubles with Injectable classes.

I have an abstract class (on web.ts) which one of its protected attributes is an HttpClient object. The definition of this abstract class is as follows:

import { HttpClient } from "@angular/common/http";


export abstract class Web {
   protected baseURL: string;

   constructor(baseURL: string, protected http: HttpClient) {
      this.baseURL =  baseURL;
   }

   public abstract RetrieveData(pattern: string);
}

Then I have another class (on webA.ts) which extends the Web class:

import { Web } from './web';

export class WebA extends Web {

   constructor() {
      super("https://www.test.com");
   }

   private Search(pattern: string) {
      pattern = pattern.replace(" ", "+");
      var searchURL = this.baseURL + `/site/searchpage.jsp?st=${pattern}&id=pcat17071`;

      console.log(searchURL);

      this.http.get(searchURL).subscribe(data => {
         console.log(data);
      });
   }

   public RetrieveData(pattern: string) {
      this.Search(pattern);
   }
}

Finally, in a class of a component for my website I want to instantiate WebA as:

private webA: Web = new WebA();

It tells me that I need to pass an HttpClient object on super("https://www.test.com"); in webA.ts. To fix it, I can make the constructor for WebA like:

constructor(@Inject(HttpClient) http: HttpClient) {
      super("https://www.test.com", http);
}

But this would lead me to do private webA: Web = new WebA(this.http); forcing me to have on my component class:

import { HttpClient } from "@angular/common/http";
...
constructor(private http: HttpClient) {}

I know there must be another way to do it because in my opinion this is breaking hierarchy on my classes

TL;DR:
I need to "auto-inject" an HttpClient on an abstract class to not to need passing this object as an argument on super in the extender class.

Salva Corts
  • 862
  • 1
  • 7
  • 12

2 Answers2

1

Either remove the constructor in WebA

export class WebA extends Web {

   //constructor() {
   //   super("https://www.test.com");
   //}

or repeat the constructor parameters and forward them with super()

export class WebA extends Web {

   constructor(baseURL: string, protected http: HttpClient) {
      super(baseURL, http);
   }

If you need a constructor in the derived class (WebA) the only way is to repeat the parameters and forward them.

Update

There is no such thin as auto-inject when you create an instance with new Xxx(). Dependency injection works only for instances that Angulars DI creates for you.

Otherwise see my answer above.

Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • 1
    I think his problem is when he wants to `create` the instance, he doesn't want to pass `httpClient` manually. Hi does not inject `WebA`, but creates manually – Suren Srapyan Jan 22 '18 at 17:54
  • @SurenSrapyan thanks for the hint. There is no dependency injection for classes created with `new ...`. I updated my answer. – Günter Zöchbauer Jan 22 '18 at 17:57
  • Thats what i thought to do on first, but as I said it breaks hierarchy. Is there some way to Inject HttpClient on Web abstract class? I dont have neither WebA nor Web on app.module.ts because they are not a component of my app, just auxiliary classes. Maybe I can make angular to inject HttpClient on WebA by adding it to app.module.ts?? – Salva Corts Jan 22 '18 at 18:03
  • There is no injection for abstract classes. As I mentioned there is only injection for classes Angular instantiates for you and Angular only instantiates concrete classes. – Günter Zöchbauer Jan 22 '18 at 18:05
  • @GünterZöchbauer Yes, I see... Then, i can add `webA` to `@NgModule` on app.module.ts on `declarations []` and `HttpClient` in `providers []`? If I do so it stills says me that I still need to pass http as an argument on `private webA: Web = new WebA();` – Salva Corts Jan 22 '18 at 18:09
  • Not sure what you mean. Yes, you need to add `WebA` to `providers` and the constructor needs to look like in my answer. Not sure what `baseURL` is. You can't inject a string without `@InjectToken('foo')` decorator. – Günter Zöchbauer Jan 22 '18 at 18:15
1

"auto-inject" works only if you want the DI mechanism to create the type for you. In your case I think it is better to declare the class WebA as injectable with @Injectable and in your class, where you need it just inject WebA instance. This way the HttpClient will be passed automatically.

@Injectable()
export class WebA extends Web {

   ...

   constructor(private httpClient: HttpClient) {
      super("https://www.test.com", httpClient);
   }

   ...

}
Suren Srapyan
  • 66,568
  • 14
  • 114
  • 112