Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 2 subscribe from component or service?

Context

I have a component HospitalComponent that tries to show a list of hospitals. It uses the readAll method from the HospitalService (that returns an Observable from firebase) :

ngOnInit() {
  this.hospitalService
    .readAll() // Make a firebase call
    .subscribe(hospitals => this.hospitals = hospitals);
}

The route /hospital is plugged to this component HospitalComponent. Each time I reach /hospital, Angular 2 make a new HospitalComponent, and a new call is made to the hospitalService.

Problem

Each time I reach /hospital, the hospital list is showing with delay.

Question

Is it a good practice to retrieve the hospital list from the service constructor itself ? This way, I can manage the refresh list from background, instead of having some delay. I would have in the component :

ngOnInit() {
  this.hospitals = this.hospitalService.readAll();
}

and in the service :

constructor(private hospitalService: HospitalService) {
  hospitalService.subscribe(hospitals => this.hospitals = hospitals);
}

But this implies to manage manually all hospital changes ..

like image 782
soywod Avatar asked Dec 07 '16 15:12

soywod


People also ask

Can we subscribe in Angular service?

Normally Subscription means an arrangement to receive something. Similarly, in Angular applications Observables will be connected to observers and whenever they observe a new value or change in data, they will execute code with the help of Subscription and all the subscribed components will receive the updated outcome.

Can we use subscribe in service?

In ServicesThere is no reason for the service itself to subscribe. Of course, a service might call another service, and get back an Observable. You (as the author of the first service) might consider subscribing to the Observable, but remember: your service only made that call because it was itself called.

Do I need to unsubscribe from service Angular?

As you probably know when you subscribe to an observable or event in JavaScript, you usually need to unsubscribe at a certain point to release memory in the system. Otherwise, you will have a memory leak.

What does subscribe in Angular 2?

subscribe() is a method on the Observable type. The Observable type is a utility that asynchronously or synchronously streams data to a variety of components or services that have subscribed to the observable.


1 Answers

From a technical viewpoint both "solutions" are pretty much equal - since they basically do the same thing it is up to your personal taste if you just want to conside your two solutions.

But in general: Try to avoid manual subscriptions at all.

There are a couple things that you can improve (the following code is based on the assumption, that you'd rather show an outdated list, that is updated in the background than to show a loading-indicator):

  • try to avoid manual subscriptions (especially(!!) in components) -> use the async-pipe instead
  • try to avoid stateful components (even services if possible) -> use streams instead

Your Service

export class HospitalService {
    allHospitals$: BehaviorSubject<IHospital[]> = new BehaviorSubject<IHospital[]>([]);

    // the fetchAll() method can be called in the constructor, or somewhere else in the application e.g. during startup, this depends on your application-flow, maybe some login is required ect...
    fetchAll(): Observable<IHospital[]> {
        const fetch$: Observable<IHospital[]> = ...get_stuff_from_firebase().share();
        fetch$
            .do(allHospitals => this.allHospitals$.next(allHospitals);
            .subscribe();
        return fetch$; // optional, just in case you'd want to do something with the immediate result(or error) outside the service
    }
}

Your component (=> just inject the service)

constructor(private hospitalService: HospitalService) {
    // nothing to do here
}

The template of the component (=> the async-pipe automatically manages the subscription and unsubscribes automatically as well, so you don't have to worry about memory-leaks ect...)

<div *ngFor="let hospital of (hospitalService.allHospitals$ | async)">
    {{hospital.name}}
</div>

A fourth(but much more extended) solutions would be to use a central store like ngrx - So with ngrx basically the part of allHospitals$ would be moved to a centrally managed store-module and you would strictly divide up your application, so that a service will do nothing but fetching and processing data, the store will do nothing but storing and emitting data and a component will do nothing but displaying data.

like image 103
olsn Avatar answered Sep 25 '22 04:09

olsn