Ektiva
Ektiva

Reputation: 3

Angular 9: BehaviorSubject not working for remote data

I'm trying to pass data between any to any component using behaviorSubject. Everything is working fine for static data. But when passing remote data (from API) The component which supposed to received the updated data is receiving the data before the update. I try several thing and I don't know what I've missed. Here is my code:

In my service: appService

// BehaviorSubjects creation :
products = new BehaviorSubject<Array<IProduct>>([]);
currentProducts = this.products.asObservable();

category = new BehaviorSubject<string>('All Categories');
currentCategory = this.category.asObservable();

shopParams = new BehaviorSubject<ShopParams>(
    {brandId: [-1], CategoryId: 0, sort: 'name', pageNumber: 1, pageSize: 36, search: ''}
);
currentShopParams = this.shopParams.asObservable();

// Function to "update" the BehaviorSubject:
changeProducts(products: IProduct[]){
    this.products.next(products);
}
changeCategory(category: string){
    this.category.next(category);
}
changeShopParams(shopParams: ShopParams){
    this.shopParams.next(shopParams);
}
// Function to get data from API
getItems(shopParams: ShopParams) {
    let params = new HttpParams();
    shopParams.brandId.forEach(brandIdSlected =>{
        if (brandIdSlected !== -1) {
            params = params.append('brandId', brandIdSlected.toString());
        }
    });

    if (shopParams.CategoryId) {
        params = params.append('categoryId', shopParams.CategoryId.toString());
    }

    params = params.append('sort', shopParams.sort);
    params = params.append('pageIndex', shopParams.pageNumber.toString());
    params = params.append('pageSize', shopParams.pageSize.toString());

    return this.http.get<IPagination>(this.baseUrl + 'items', {observe: 'response', params})
    .pipe(
        map(response => {
          return response.body;
        })
      );
}

In My first component: pageComponent

ngOnInit() {
    // Subscribe to category to get last update
    this.appService.currentCategory.subscribe(category => this.categoryNameSelected = category);
} 

// Method in which the category change
changeCategory(event){
    // some Code here  
    //Update category and shopParams for all suscribers
    this.appService.changeCategory(event);
    this.appService.changeShopParams(this.shopParams);  
    // Get the product from API base on category selected and new shopParams
    this.getItems();
   //Update products
    this.appService.changeProducts(this.products);
  }

// getItems function which call the getItem of my service to get data and subscribe
getItems() {
    this.appService.getItems(this.shopParams).subscribe(response => {
      this.products = response.data;
      this.shopParams.pageNumber = response.pageIndex;
      this.shopParams.pageSize = response.pageSize;
    }, error => {
      console.log(error);
    });   
  }

In my 2nd Component: productCoponent

ngOnInit() {
    // Subscribe to category, shopParam and product to get last update
    this.appService.currentCategory.subscribe(category => this.categoryNameSelected = category);
    this.appService.currentShopParams.subscribe(shopParams => this.shopParams = shopParams);
    this.appService.currentProducts.subscribe(products => this.products = products);
}

The pageComponent is suppose to updated category, shopParams and product anytime when onChangeCategory is call so all suscribers(like productCompnent) should get updated value. I am able to get updated value of category and shopParams in productCompnent but for the product I always get the penultimate value instead of last value I don't know what I'm missing.

Also the product depends on shopParams which itself depends on category and the pageComponent just change the category. I don't know if there is easy way to update my shopParams and product in productComponent by using only one behaviorSubject for categrory?

Upvotes: 0

Views: 219

Answers (1)

Aakash Garg
Aakash Garg

Reputation: 10979

Change your changeCategory and getItems method to :-

changeCategory(event){
    // some Code here  
    //Update category and shopParams for all suscribers
    this.appService.changeCategory(event);
    this.appService.changeShopParams(this.shopParams);  
    // Get the product from API base on category selected and new shopParams
    this.getItems().subscribe(res => {
      this.appService.changeProducts(this.products);
    });
  }

// getItems function which call the getItem of my service to get data and subscribe
getItems() {
    return this.appService.getItems(this.shopParams).pipe(tap((response) => {
      this.products = response.data;
      this.shopParams.pageNumber = response.pageIndex;
      this.shopParams.pageSize = response.pageSize;
    }, error => {
      console.log(error);
    }));   
  }

Explaination :- you are getting products from a api. you called getitems, and product will only receive latest value once subscription will be invoked. but your code will not wait for getitems to be complete before calling product.next. thats how asynchronous operations work.

Upvotes: 0

Related Questions