What makes the observable I use in this Angular 11 component return undefined?
Problem Description:
I am working on adding a promotions feature to an Angular 11 e-commerce app.
I have a service that makes a get
request and reads a JSON containing the campaign’s data.
The service:
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Campaign } from '../models/campaign';
@Injectable({
providedIn: 'root'
})
export class PromoProductsService {
public apiURL: string;
public promo$: Observable<Campaign>;
constructor(private http: HttpClient) {
this.apiURL = `${environment.bffApi}/offer-service`;
this.promo$ = this.http.get<Campaign>(`${this.apiURL}/campaign`).pipe(shareReplay());
}
}
NOTE: the campaign JSON contains other (arrays of) "things" the just banners and I would prefer to make a single GET request for all of them. This is why I use promo$: Observable<Campaign>
.
In the category component I have:
public getCampaignBanners() {
this.promoProductsService.promo$.pipe(takeUntil(this.destroyed$)).subscribe((data: any) => {
this.campaignData = data;
this.campaignBanners = this.campaignData.campaign.banners;
if (this.campaignBanners && this.campaignBanners.length > 0) {
this.displayCampaignBanners();
}
});
}
public displayCampaignBanners(){
this.productList$.pipe(takeUntil(this.destroyed$)).subscribe((productList) => {
this.campaignBanner = this.campaignBanners.find((banner: any) => {
return banner.category.toLowerCase() == productLists.category_name.toLowerCase();
});
});
}
The problem
Unless I refresh the page after accssing a product list, productList$
is undefined and the the line this.productList$.pipe(takeUntil(this.destroyed$)).subscribe((productList) => {
throws a Cannot read properties of undefined (reading 'pipe')
error.
Questions:
- What am I doing wrong?
- What is the easiest way to fix this issue?
Solution – 1
When you call Backend with Angular, you need to subscribe to the observable for get data.
I dont really understand why you create an Observable<Campaign>
this.http.get<Campaign>(this.apiURL + "/campaign").subscribe(response => {
console.log(response);
})
Or something like this if you want to have a method
public getCampaignBanners() :Observable<Campaign> {
return this.http.get<Campaign>(this.apiURL + "/campaign");
}
// call it after
this.promoProductService.getCampaignBanners().subscribe( response => {
// ...
})
If you want to handle some error you can do this.
this.http.get<Campaign>(this.apiURL + "/campaign").subscribe(response => {
console.log(response);
},
(error) => {
console.error(error);
switch(error.status){
case 404:
// 404 code
break;
case 500:
// 500 code
break;
default :
break
}
})
Hope it will help you, maybe it’s not the main problem here, did you try to call your API with POSTMAN or CURL ?
(Sorry for bad english , not native 🙂 )
EDIT
promo: Observable:<any>;
getPromo(){
if(this.promo == undefined){
/* Do API CALL and Set promo with Data*/
}else{
return this.promo;
}
}