skip to Main Content

I have a dilemma, I’m able to delete item from database collection carts, I figured out the reason I have to reload the cart to get update on cart, this is because item is being removed from database but not from the array. I tried a number of ways to delete from array but its not working for me. I tried using splice as well as indexOf. Can someone please point me in the right direction I would greatly appreciate it. I have included a snippet of necessary code.

CartItemComponent:

 cartitems$: Cartitems[] = []

 cartItems: CartItem [] = []


  handleRemoveFromCart(){
    alert("hit remove from cartitem");
   /* this.cartService.RemoveProductFromCart(this.cartItem._id).subscribe(() =>
   

     console.log("Product with Id deleted", this.cartItem._id  

   //this.cartitems$ = this.cartitems$.splice(this.cartItem._id) does not work

  
   );*/ //didn't work

  this.cartService.RemoveProductFromCart(this.cartItem._id).subscribe((index =>{



console.log("Product with Id deleted", this.cartItem._id),

  this.result =  this.cartitems$.findIndex(p => p._id === this.cartItem._id);

   if(this.result > -1){
    this.cartitems$.splice(this.result, 1);
    alert("Remove from array")
     }

   }


 }
  

cartService:

      RemoveProductFromCart(_id:string){  
    
        alert("show deleted item" + _id);
 return this.http.delete<Cartitems[]>(this.rootUrl + '/getProducts/removecartitems/' + _id);
 
     /* This goes back to calling function so I can try to delete from collection*/
  
 
 
   }

2

Answers


  1. Using tap from RxJS and filter instead of splice

    handleRemoveFromCart(cartItemId: string) {
        this.cartService.RemoveProductFromCart(cartItemId).pipe(
          tap(() => {
            this.cartItems = this.cartItems.filter(item => item._id !== cartItemId);
          })
        ).subscribe();
      }
    

    filter creates a new array without the specified carItemId while the tap operator allows you to perform a "side effect", in this case, deleting the item. Also, RemoveProductFromCart returns void, since there’s no need to return a new array after a delete request.

    RxJS – tap

    Login or Signup to reply.
  2. The naming convention you are using for your cartitems seems wrong, you usually use $ when the type is an Observable, if that’s a typo from your end and it is indeed an observable, then you have to update the cartItems by sending a new updated array like so:

    component.ts

    @Component({...})
    export class CartComponent {
      // the cart items data wrapped within an observable
      cartItems$!: Observable<CartItem[]>;
      
      //...
    
      // first approach:
      onDeleteItem(id: string): void {
        this.cartService.RemoveProductFromCart(id)
         .pipe(
           take(1),
           withLatestFrom(this.cartItems$) // grab the current data in the cart items
          )
         .subscribe(([response, cartItems]: [ResponseService, CartItem[]]) => {
            const filtered = cartItems.filter(e => e._id !== id); // remove the deleted item
            this.cartItems$.next(filtered); // update the cart items
         })
      }
    
      // second approach: (There are many actually...)
      onDeleteItem2(id: string): void {
         this.cartItems$ = this.cartService.RemoveProductFromCart(id)
           .pipe(
             withLatestFrom(this.cartItems$),
             concatMap(([response, cartItems]: [ResponseService, CartItem[]]) => {
                  const filtered = cartItems.filter(e => e._id !== id)
                  return of(filtered);
             })
           ) 
      }
    }
    

    component.html

    <!-- This is just an example on how to handle your cart items source  -->
    <!-- within the template HTML -->
    <ng-container *ngIf="cartItems$ | async as items">
      <li *ngFor="let item of items">{{ item.name }} - {{ item.price }}</li>
    </ng-container>
    
    <!-- If you are using the latest version of Angular, you could do it like this -->
    @if (cartItems$ | async; as items) {
      @for (item of items; track item) {
        <li>{{ item.name }} - {{ item.price }}</li>
      }
    }
    

    In the first approach, it subscribes manually to the http response from the server and in it, you next it with the updated cart items.

    The second one, you don’t subscribe, instead you pipe it and return a final Observable holding the updated cart items.

    Additionally, you should also handle the possible scenario of an error with catchError, but I didn’t implemented since I am not sure if you are already doing that in your project.

    As a side note, I am not sure why you have 2 cartItems declared in your component, both seems to be of the same type, the only differences are the names, one doesn’t have $ the other one does it which is very confusing.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search