Search code examples
angularangular2-servicesangular2-injection

Angular 2 call service only on app initialization


What I am trying to accomplish is to call external API only once per app initialization.

I have a simple service,

@Injectable()
export class XService {
    url = "http://api.example.com"
    constructor(private _http:Http) {

    }

    callAnAPI(){
        console.log('made an external request");
        return this._http.get(url)
            .map(res=>res.json());
    }
}

and two components, the main appComponent

@Component({
  selector: 'my-app',
  template: `
    <div>
      Test
    </div>
  `
})

export class AppComponent {
    isLoading = true;
    results = [];

    constructor(private _service: XService){

    }

    ngOnInit(){
        Observable.forkJoin(
            this._service.callAnAPI()
            // some more services here
        )
        .subscribe(
            res => {
                this.results = res[0];
            },
            null,
            () => {this.isLoading = false}
        );
    }
}

and another component used with a route

@Component({
  template: `
    <div>
      I want to use the service with this component.
    </div>
  `
})

export class SecondComponent {

    constructor(private _service: XService){

    }
}

the service is initialized and Angular hits server on the initialization of the AppComponent. I want to Use XService with SecondComponent too, whenever I try to call the service again from the SecondComponent, (via _service._service.callAnAPI()) Angular hits the external API. I want to minimize the external hits.

How do I obtain the data made by the AppComponent on initialization than calling again the service again in SecondComponent


Solution

  • You could use the do operator for this to get the data the first time and reuse them for next calls:

    @Injectable()
    export class XService {
      url = "http://api.example.com"
      constructor(private _http:Http) {
    
      }
    
      callAnAPI(){
        console.log('made an external request");
        if (this.cachedData) {
          return Observable.of(this.cachedData);
        } else {
          return this._http.get(url)
            .map(res=>res.json())
            .do((data) => {
              this.cachedData = data;
            });
        }
      }
    }
    

    If you want to load data as startup, you can call the callAnAPI method from the service constructor.

    To be able to use this approach, you need to define your service when bootstrapping your application:

    bootstrap(AppComponent, [ XService ]);
    

    This way you will use a single instance for your whole application.