Search code examples
angularobservablerouterlinkngoninit

Service subscription in ngOnInit gets called once and does not stay populated on route change


Just to clarify. This angular app is populating the data to the view but when I navigate from one component to the other the ngOnInit lifecycle hook does not seem to get invoked thus meaning that the list on the view remains empty. When i hit f5 (refresh) the data on whichever page i am gets populated meaning that the service is working alright. Could it be that the life cycle hook is the issue?

So given that i have the following collection in the file product.service.ts

 export class ProductsService {

  private productsCollection:AngularFirestoreCollection<Product>;
  private products:Observable<Product[]>;

  constructor(private afs:AngularFirestore) { 
    //Code was removed from here as it is beyond the scope of the problem
    //this.products is getting populated here successfully 
  }

 getProducts(){
   return this.products;
 }
}

And i subscribe to the method from two separate components as follows (using the same exact code below)

constructor(private productService:ProductsService) { }

      ngOnInit() {
        this.productService.getProducts().subscribe(
          products => {
              this.products = products;
          });

So assuming that componentA and componentB both have this code, the lists should be populated on both components when they are loaded. When i key in the URL to the component the list is populated but when i use routerlinks and the data is not populated and its like as if ngOnit is not triggered when the new route is invoked. Both views show the lists but they don't get populated when i use routerlink as opposed to writing the address or refreshing the page. The service is shared in the app.module.ts as a provider. Some help is appreciated.


Solution

  • Use a behaviour subject rather than an observable. A behaviour subject is a hot observable that allows any subscribers to pull existing data that has already been pushed to it. One difference with behaviour subject is that you push data using the .next method. BehaviorSubjects also need to be passed an initial value when being initialised in this case I have passed null as I assume your constructor does something in order to fetch the data needed. Code example below:

     export class ProductsService {
    
         private productsCollection:AngularFirestoreCollection<Product>;
         private products:BehaviorSubject<Product[]> = new BehaviorSubject(null);
    
         constructor(private afs:AngularFirestore) { 
           //code here to set products
           this.products.next('data to set products here')
         }
    
         getProducts(){
            return this.products.asObservable();
         }
     }