Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 442
All Іѕ Vаиітy Avatar asked Mar 18 '16 11:03

All Іѕ Vаиітy


2 Answers

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.

like image 66
Thierry Templier Avatar answered Nov 15 '22 03:11

Thierry Templier


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

    }

    callAnAPI(){
      if(this.data) {
        return Observable.of(this.data);
      } else {
        console.log('made an external request");
        return this._http.get(url)
            .map(res=>res.json())
            .do(res => this.data = res);
      }
    }
}
like image 42
Günter Zöchbauer Avatar answered Nov 15 '22 05:11

Günter Zöchbauer