问题
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.
来源:https://stackoverflow.com/questions/40833704/i-want-to-calculate-the-sum-of-the-shoppingcart-at-firebase-with-angularfire2