3

I have a couple of components that are doing the same job. Everyone makes the same API call only with a different parameter:

this.http.get('url' + parameter).subscribe((data: Array<any>) => {
   //some state dispatches and other stuff
   return response;
});

I don´t want to write the same code in every component for reasons. In Java for example I use superclasses for this case. In Angular services are sufficient most of the time. But not in this case.

I tried to write a new class:

export class Content {
   constructor(private http: HttpClient) { }
   getContent() {
     this.http.get('url' + parameter).subscribe((data: Array<any>) => {
       //some state dispatches and other stuff
       return response;
     });      
   }
}

Now I can initialize this class in every component and it works:

export class MyComponent {
  constructor(private http: HttpClient) { }
  toggle() {
    new Content(http);
  }
}

The issue is that I have to use the constructor where I injected the HttpClient. I don´t want that because I have to pass additional dependencies(which are not relevant for the issue).

So is that the best practice and if yes how can I use HttpClient without passing it?

BinaryButterfly
  • 18,137
  • 13
  • 50
  • 91
Nico Schuck
  • 832
  • 3
  • 15
  • 32
  • If you want to have like 10 components that do the same thing why not using a ngFor in the html? Like `
    `
    – Jacopo Sciampi Sep 18 '18 at 10:02
  • Because every component manipulates the data diffrent. Only the request is the same – Nico Schuck Sep 18 '18 at 10:07
  • Why not use `return this.http.get(url).pipe(map(data) => {// some common stuff here});` in your service and then let the components do their own processing on it from that point on? That is a very common approach to this. – Igor Sep 18 '18 at 10:11
  • Your reasoning for “not wanting to inject the `HttpClient`” is unclear. Can you please explain further? Are you aware that you can inject multiple things in a constructor? – Alex Peters Sep 18 '18 at 10:22

4 Answers4

3
  • You should be using map in your service to perform common processing before the result is returned to the component.
  • The service should return an observable to the calling component. The component can then further process the result from that point.
  • This might just be for the example but do not use any if it can be helped, define an interface instead and use that to define the response and return types. This adds type safety to your code which is one of the primary reasons that typescript was created to begin with.
  • You should be injecting the service into the component. Really you should always use injection for any dependencies. If you have different actions you want to execute create different methods to handle them in your service or create methods that take parameters. In my experience there is no reason to manually create instances of HttpClient.

The following is a very common approach for what I think you are asking.

import { map } from 'rxjs/operators';
import { Observable } from 'rxjs';
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

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

   getContent() : Observable<Array<any>> {
     return this.http.get<Array<any>>('url' + parameter).pipe(map((data: Array<any>) => {
       // common processing here
       return data;
     }));
   }
}
@Component({})  
export class MyComponent {
  constructor(private contentService: ContentService) { }

  data: Array<any> = [];
  toggle() {
    this.contentService.getContent().subscribe(data => {
      // do something with returned data like...
      this.data = data;
    });
  }
}
Igor
  • 60,821
  • 10
  • 100
  • 175
  • If i get you right i don´t expor the data, i export the logik to manipulate the data? – Nico Schuck Sep 18 '18 at 10:56
  • @NicoSchuck - the service executes common processing but returns that as an observable. The component can then subscribe, get that result, and do whatever else needed on that resulting data. – Igor Sep 18 '18 at 10:59
  • @NicoSchuck - see also [How do I return the response from an asynchronous call?](https://stackoverflow.com/q/14220321/1260204) which has examples of returning rxjs observables. – Igor Sep 18 '18 at 11:06
  • 1
    awesome thats exactly what i need – Nico Schuck Sep 18 '18 at 11:16
1

Just put @Injectable before create the class of the service, and then you can inject the service inside the providers of app.module.ts

@Injectable()
export class Service {
  constructor(
      private http: HttpClient,
  ) {}

  getContent() {
     this.http.get('url' + parameter).subscribe((data: Array<any>) => {
       //some state dispatches and other stuff
     });      
   }
}

And then you can use it inside the constructor of your other component importing the service before :)

constructor(private service: Service) { }
  • Thats the way I´m using services. The issue is that I need a response from getContent(). i change my Question to clearify that – Nico Schuck Sep 18 '18 at 10:42
0

Create a Service. Import the service in any component that you need, and inside the Service import the HttpClient.

Here are the docs.

0

Create a service with httpClient. use a function which returns a promise. inside this function use http request. In your component just get the instance of the service and execute whatever you want after promise returns a value

service.ts

 export class ContentService {
   constructor(private http: HttpClient) { }
   getContent(): Promise<any> {
     this.http.get('url' + parameter).subscribe((data: Array<any>) => {
       return new Promise(resolve => resolve('whatever'));
     });      
   }
}

component.ts

constrctor (private classService: ClassService) {
   classService.getContent()
   .then(data => 'do whatever you want with tha data');
}
Sujay
  • 613
  • 1
  • 5
  • 16
  • Thank you for you help. unfortunately it doesnt works. Because if I declare the method as Promise, a return outside of the http request is required. If I add this return, I will always get this response. – Nico Schuck Sep 18 '18 at 10:49