I want to calculate the sum of the ShoppingCart at

2019-03-06 07:55发布

问题:

I'm building an experimental application that uses Angular2, Firebase and AngularFire2. This is what my data looks like:

{
  "ShoppingCartItem":
      {
        "item1":{
            "quantity": 2,
            "productId": "abc"
        },
        "item2":{
            "quantity": 1,
            "productId": "bcd"
        }
      }
  "Product"
      {
        "abc":{
            "name": "product1",
            "price": 5
    },
        "bcd":{
            "name": "product2",
            "price": 6
        }
    }
}

Below are my cart.ts

this.items = this.af.database.list('ShoppingCartItem')
          .map(carts => {
            return carts.map(item => {
              item.product = this.af.database.object(`Product/${item.productId}`);
              return item;
            });
          });

Below are my cart.html

<table>
<tbody>
    <tr *ngFor="let item of (items | async)">
        <td>{{(item.product | async)?.name}}</td>
        <td><input type="text" name="quantity" [(ngModel)]="item.quantity" size="1" class="form-control"></td>
        <td>{{(item.product | async)?.price | number: '.2'}}</td>
        <td>{{(item.product | async)?.price * item.quantity | number: '.2'}}</td>
    </tr>
</tbody>
<tfoot>
    <tr>
      <td colspan="2" class="text-right">
        <strong>Total :</strong>
      </td>
      <td colspan="2" class="text-left">
        ?????????
      </td>
    </tr>
</tfoot>

I want to calculate the sum of the ShoppingCart. So I want to find the value of (2*5) + (1*6) = 16 as the data shows. How do i do it.

This plunker

回答1:

The problem is in this code:

carts.map(cart => {
    this.af.database.object(`Product/${cart.productId}`)
    .subscribe(d => {
        cart.product = d;
    });
  return cart;
});
carts.forEach(cartItem => {
    qty += cartItem.quantity;
    total += cartItem.quantity * cartItem.product.price;
    // console.log(cartItem);
});

Two calls: carts.map and carts.forEach are synchronous and happen one after another. But loading of products (via af.database.object) is asynchronous so when you iterating over cartItem products not been loaded yet.

The solution would be to chain product loading and total calculation. See here.



回答2:

Since you are using Firebase, first thing I notice is key names. Fix them like this. Where cart.$key is some hashcode e.g. -KXeML1Na9qCsvK4JSyQ.

{
  "ShoppingCartItem": {
    -KXeML1OkDyUVTAdHYPx : {
      -KXeML1OkDyUVTAdHYPx: true,
      -KXeML1PP4faQG2Z3fzU: true
    },
    -KXeML1Na9qCsvK4JSyQ: {
      -KXeML1PP4faQG2Z3fzU: true
    }
  },
  "Products": {
    -KXeML1OkDyUVTAdHYPx:{
      "name": "product1",
      "price": 5
    },
    -KXeML1PP4faQG2Z3fzU:{
      "name": "product2",
      "price": 6
    }
  }
}

Now rewrite your frontend logic. Please write and export suitable Product class as well. Put below inside shoppingcart.service.ts

findProductKeysForCart(cartId: string): Observable<string[]> {
 return this.database.list('ShoppingCartItem', {
    query: {
      orderByKey: true,
      equalTo: cartId
    }
  })
    //.do(console.log)// Check whats coming,
    //.map(result => result[0])// might be needed
    .map(sci => sci.map(product => product.$key));
}

findProductsForProductKeys(productKeys$: Observable<string[]>): Observable<Product[]> {
  return productKeys$
    .map(productKeys => productKeys.map(productKey => this.database.object(`Products/${productKey}`)))
    .flatMap(prodObservables => Observable.combineLatest(prodObservables));
}


findAllProductsForCart(cartId): Observable<Product[]> {
    //this fn gets your Products for a cart
    return this.findProductsForProductKeys(this.findProductKeysForCart(cartId));
}

NOW, do your final calculations either in Product class or subscribe. Below would go inside DisplayCart.component.ts

items;
constructor(private shoppingCartService: ShoppingCartService){}

ngOnInit(){
  const items$ = this.shoppingCartService.findAllProductsForCart(this.cartId);

 items$.subscribe(items => this.items = items);
}

You still need to complete the remaining stuff on your own, good luck.