Hello my goal is to empty the shopping cart after transaction is a success. it works fine with one item(id) its when there is more than one item in cart.
I have a forEach method that according to document should take an arrow, using => typescript complains saying expected ",". I get an exception error 5 is not a function, 5 is the endpoint which is an id that I'm trying to delete . I don't understand, I put this same code in a function that is called at onInit and it works fine. I put it there merely for test purposes. But when I call this service from a function it blows up, throws an exception. The thing is it still deletes the id of the item it complains about when refresh the page. I tried with a function per the documentation but then I get all types of errors still saying I need a comma(,). Can someone please point me in the right direction as far as what I'm doing wrong? I would greatly appreciate it.
code snippet below:
cart service
deleteCartItems(): Observable<CartItem[]> {
return this.http.get<CartItem[]>(cartUrl).pipe(
map((result: any[]) => {
let cartItems: CartItem[] =[];
for(let item of result) {
cartItems.push( new CartItem(item.id, item.size, item.product, item.imageUrl ));
alert("whats in item" item.id);
this.cartIdsArray = cartItems.map(item => item.id)
let id: number = item.id;
let endPoints = "/cart/" id;
//var endPoints = "/cart/";
this.cartIdsArray.forEach((item.id),this.http.delete(this.url endPoints).subscribe(data=>{
console.log(data);
})
)
}
return cartItems;
})
);
}
CodePudding user response:
10 End Point(id) Is Not A Function
Now, that the problem is understood fixing it is easier.
it works fine with one item(id) its when there is more than one item in cart.
When forEach()
method gets executed, it evaluates both the parameters causing the delete API to be called and raises an error after when it sees that the first parameter is not a function. As the error is not caught it stops the execution of the deleteCartItems() method. The remaining items in the cartIdsArray
never get processed.
Refactored solution 1
You do not need to iterate over the complete list of results as there's a loop already.
new CartItem() instance is not needed.
There are lot of subscriptions created which results in memory leak. Stackblitz
deleteCartItems(): Observable<CartItem[]> { const cartUrl = 'https://62c41dc97d83a75e39f0d512.mockapi.io/api/v1/cart'; return this.http.get<CartItem[]>(cartUrl).pipe( tap((cartItems: CartItem[]) => { cartItems.forEach((cartItem) => { this.http .delete(this.url '/cart/' cartItem.id) .pipe(first()) .subscribe(); }); return cartItems; }) );
}
Refactored solution 2
We do not need to use Array forEach()
method by using Array map()
method
You can actually use forkJoin()
operator to make parallel API calls. Also, map()
operator is not actually needed as you are not transforming the result, tap()
is a better candidate as you want a side effect
Stackblitz
deleteCartItems(): Observable<CartItem[]> {
const cartUrl = 'https://62c41dc97d83a75e39f0d512.mockapi.io/api/v1/cart';
return this.http.get<CartItem[]>(cartUrl).pipe(
tap((cartItems: CartItem[]) => {
forkJoin(
cartItems.map((cartItem) =>
this.http.delete(this.url '/cart/' cartItem.id).pipe(first())
)
).subscribe();
return cartItems;
})
);
}
Refactored solution 3
Nested subscribe()
is still bad and can be removed as below.
deleteCartItems(): Observable<CartItem[]> {
const cartUrl = 'https://62c41dc97d83a75e39f0d512.mockapi.io/api/v1/cart';
return this.http.get<CartItem[]>(cartUrl).pipe(
first(),
mergeMap(cartItems => {
return forkJoin(
cartItems.map((cartItem) =>
this.http.delete<CartItem>(this.url '/cart/' cartItem.id).pipe(first())
)
)
})
)
}
Note: I have left error handling as an exercise, but it should be done for a real project.
CodePudding user response:
Here is a simplified code snippet (pure Typescript, mock data, no Angular and no service calls) that I think is what you're trying to achieve. Focus on what the loop does and how to finally repeatedly call the service in the last forEach
. If I'm correct then you can change your code accordingly.
class CartItem {
id: number;
}
const result = [{ id: 1 }, { id: 2 }] as CartItem[];
const cartItems: CartItem[] = [];
for (let item of result) {
cartItems.push({ id: item.id });
console.log("whats in item " item.id);
this.cartIdsArray = cartItems.map(item => item.id);
}
this.cartIdsArray.forEach(id => {
const endPoint = "/cart/" id;
console.log(id, endPoint);
});
Or even simpler:
class CartItem {
id: number;
}
const result = [{ id: 1 }, { id: 2 }] as CartItem[];
const cartItems: number[] = [];
for (let item of result) {
console.log("whats in item " item.id);
cartItems.push(item.id);
}
cartItems.forEach(id => {
const endPoint = "/cart/" id;
console.log(id, endPoint);
});