0

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

2 Answers 2

2

You are not returning anything in getProducts, and you should let the component to subscribe to that http call, not your service. With your current code in the service, even you add a return to it, it will return a Subscription, not the data you want to handle in the component.

I highly recommend the reactive approach, which is a good practice in Angular:

service

getElectronics(): Observable<any[]> { //you should create your own type, avoid using any
  return this.http.get(environment.baseUrl + '/category/electronics').pipe(
   tap(() => this.spinnerElect = false)
  );
}

Component

theProducts$!: Observable<any[]>; //it will store the data wrapped as an Observable

ngOnInit(): void {
  // store the observable from the service containing the products data
  this.theProducts$ = this.service.getElectronics();
}

template HTML

<app-product
  [theProducts]="theProducts$ | async"
  (target)="addToCart($event)"
></app-product>

Using the async pipe, you subscribe to the observable in the template HTML, without managing the subscription.

Sign up to request clarification or add additional context in comments.

Comments

1

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.