3

I am managing my state in Angular app by using Behavior Subject. I am using two services. One to perform send and get request using web sockets and one to store the data in an observable. As soon as the data is retrieved I pass the data to the behavior subject. I am having an issue here. Everything is working perfectly except, when I delete the item and press the back button. Some of my data gets lost during this process. I don't know why is this happening. Here's my code:

cart.store.ts // for managing state

private cartItems$ = new BehaviorSubject<Product[]>(null);
private items: Product[] = [];

setCart(cartItems: Product[]) {
    this.cartItems$.next(cartItems);
}

setSingleItem(item: Product) {
    this.items.push(item);
    this.cartItems$.next(this.items);
}

deleteCart(item: Product) {
    this.cartItems$.subscribe((res) => {
      let index;
      for (let i = 0; i < res.length; i++) {
         if (item.upc === res[i].upc) {
            index = i;
        }
      }
     res.splice(index, 1);
   });
}

cart.component.ts //calls cart service and fetches the data

getCartItems() {
if (!this.cartItems?.length) {
  const payload = this.localStorageService.getData(LOCAL_STORAGE_KEY.PHONE);
  this.cartService.getCart(payload).then((res) => {
    //after fetching storing the data
    this.cartStore.setCart(res);
    for (let x = 0; x < res.length; x++) {
      this.totalPrice = this.totalPrice + res[x].price;
    }
    this.cartItems$ = this.cartStore.getCart();  //using async pipe to display in template
  });
}
}

cart.service.ts //for getting and removing data

getCart(payload): Promise<any> {
this.socketService.sendMessage(AUTH_EVENTS.ON_DEVICE_CONNECT, payload);
const serverRes = (async () => {
  try {
    const data = await this.socketService.receivedJustSingleValue(
      CART_EVENTS.GET_CART_ITEMS,
    );
    if (data) {
      return data;
    } else {
      throw new Error('some shit happened');
    }
  } catch (error) {
    return error;
  }
})();
return serverRes;
}   

//remove cart works the same way

When I remove an item and press the back button, my data gets lost. Can anybody tell me what's wrong?

Package.JSON
  • 301
  • 5
  • 25
  • How are your services provided (both CartStoreService and CartService)? – Octavian Mărculescu Nov 01 '21 at 07:23
  • Can you tell what data is lost? How is it hampering the application flow? Which Behavior Subject are you using? – Apoorva Chikara Nov 01 '21 at 07:25
  • @OctavianMărculescu, I am providing cartservice in providers array and using providedIn root for cartstoreservice – Package.JSON Nov 01 '21 at 07:27
  • @ApoorvaChikara, if there are 2 items in the checkout and i delete 1. Press on go back of browser then the remaining 1 product gets deleted from the behavior subject. – Package.JSON Nov 01 '21 at 07:29
  • What I would suggest you to check the flow if the application. When you hit the back button try checking what all things are getting updated. It seems when you hit back button, it updates the behaviour subject with empty data. Also, Does other BS behaving the same way? – Apoorva Chikara Nov 01 '21 at 07:36
  • @ApoorvaChikara, no, I have used another for the same purpose for another feature and it's working fine. – Package.JSON Nov 01 '21 at 07:39
  • 1
    Yes, I suggest you to re-check the flow. Your subscription is getting updated with some empty data. – Apoorva Chikara Nov 01 '21 at 07:48
  • `cartItems$.subscribe` is never unsubscribed, which looks suspicious. If you only want the latest value you can use `cartItems$.value` – NickL Nov 01 '21 at 08:01

1 Answers1

1

The problem is in the deleteCart function. You subscribe to the observable but never unsubscribe. So every time you call next(), The deleteCart runs again and deletes an item.

You can use BehaviorSubject.value to get the current items. The result should see like this:

private cartItems$ = new BehaviorSubject<Product[]>(null);
// private items: Product[] = [];

setCart(cartItems: Product[]) {
    this.cartItems$.next(cartItems);
}

setSingleItem(item: Product) {
    this.cartItems$.next([...this.cartItems$.value, item]);
}

deleteCart(item: Product) {
    const items = this.cartItems$.value;
    let index;
    for (let i = 0; i < items.length; i++) {
        if (item.upc === items[i].upc) {
            index = i;
        }
    }
    items.splice(index, 1);
    this.cartItems$.next(items);
}
Shalom Peles
  • 2,285
  • 8
  • 21
  • 1
    Ben Lesh wrote a good answer regarding the usage of getValue: https://stackoverflow.com/questions/37089977/how-to-get-current-value-of-rxjs-subject-or-observable/45227115#45227115. Please consider reading this article if you build up a state by usage of getValue. Alternatively you can always use the https://rxjs.dev/api/operators/scan operator for state. – Jonathan Stellwag Nov 02 '21 at 00:25