Search code examples
javascriptangularapirender

angular component doesnt update data to the dom after fetching using api unless i open the component again


im using fakeapi store to fetch products and loop on them to show in a component im using a service to do that and it goes as follows

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { environment } from 'src/environments/environment';

@Injectable({
  providedIn: 'root',
})
export class ProductsService {
  eleProducts: any[];
  spinnerElec: boolean;
  constructor(private http: HttpClient) {
    this.spinnerElec = true;
    this.eleProducts = [];
  }
  getElectronics() {
    this.spinnerElec = true;
    this.http
      .get(environment.baseUrl + '/category/electronics')
      .subscribe((res: any) => {
        this.eleProducts = res;
        this.spinnerElec = false;
      });
  }

then in the electronics-component.ts

export class ElectronicsComponent implements OnInit {
  Products: any[];
  spinner: boolean;

  constructor(public service: ProductsService) {
    this.Products = [];
    this.spinner = true;
  }

  ngOnInit(): void {
    this.getProducts();
  }

  getProducts() {
    this.spinner = this.service.spinnerElec;
    this.service.getElectronics();
    this.Products = this.service.eleProducts;
  }

and to display data in electronics-component.html

<div class="row gap-3 justify-content-center" *ngIf="!spinner">
    <div
      class="card col-lg-4 col-md-6 col-sm-12 bg-warning"
      style="width: 18rem"
      *ngFor="let product of Products"
    >
      <app-product
        [elecCart]="service.elecCart"
        [Product]="product"
        (target)="addToCart($event)"
      ></app-product>
    </div>
  </div>
  <div
    class="spin d-flex justify-content-center align-items-center w-100"
    *ngIf="spinner"
  >
    <app-spinner></app-spinner>
  </div>

im using ngif on the spinner to clear it from the dom and show data once it fetched sucessfuly the problem is that i must open the componet then go to another component then come back to it again to show the data otherwise the data wont show... thanks in advance


Solution

  • You are not suscribing in your componen, so as http is an async operation the first time you use call it in ngOnInit the code will continue and don't return anything because your component aren't listening that change.

    There are two ways to avoid this, if you are not familiar with Rxjs (as i am) you can use setTimeout to create a little delay allowing your code to "wait" until the call is made.

    getProducts() {
        this.spinner = this.service.spinnerElec;
        this.service.getElectronics();  
        setTimeout(() => {
          this.Products = this.service.eleProducts;
        }, 100);
      }
    

    BUT this is a way just for a quick fix. The correct way is to : a) return the http petition to the component and suscribe there.

    b) Convert eleproducts in an observable, when the http is load use .next(res) to emit the new value. In your component you'll suscribe to that observable and it will updated

    Look here to know more about how to suscribe to a service variable: https://www.learnrxjs.io/learn-rxjs/subjects/behaviorsubject