【发布时间】:2021-10-29 13:14:15
【问题描述】:
我在 Angular 12 中使用 Firestore 作为后端实现了 ShoppingCart 服务。我的目标是在整个应用程序中坚持购物。当页面加载时,有一种方法可以检查localStorage 中的cartId 字段。如果它不存在,该方法会在 Firestore 中创建一个新的购物车,并将该 ID 作为 cartId 存储到 localStorage 中。我有两个组件通过订阅valuechanges() 使用此购物车服务。因为两个组件同时(或几乎)加载,所以订阅没有按预期发生。两个组件都执行各自的订阅并将 cartId 返回为 null,随后,我得到了 2 个新的购物车项目。
这是来自 codewithmosh.com 的一个项目(注意:他在实现中使用了 Angular 4 和 Firebase)。我正在接受使用 Firestore 将其更新到 Angular12 的挑战。
ShoppingCartService:
import { take } from 'rxjs/operators';
import { AngularFirestore} from '@angular/fire/firestore';
import { Injectable } from '@angular/core';
import { Product } from './models/app.product';
import { ShoppingCart } from './models/shopping-cart';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class ShoppingCartService {
constructor(private afs: AngularFirestore) { }
private async getOrCreateCartId(): Promise<string>{
let cartId = localStorage.getItem('cartId');
if (cartId) return cartId;
let result: any = await this.create();
localStorage.setItem('cartId', result.id);
return result.id;
}
private create() {
return this.afs.collection('shopping-carts').add({
dateCreated: new Date().getTime()
});
}
async getCartItems(): Promise<Observable<ShoppingCart[]>>{
let cartId = await this.getOrCreateCartId();
return this.afs.collection('shopping-carts').doc(cartId).collection<ShoppingCart>('items').valueChanges();
}
async getCart() {
let cartId = await this.getOrCreateCartId();
return this.afs.collection('shopping-carts').ref.doc(cartId).get();
}
private getItem(cartId: string, productId: string) {
return this.afs.collection('shopping-carts').doc(cartId).collection('items').doc(productId);
}
async updateItemQuantity(product: Product, change: number) {
let cartId = await this.getOrCreateCartId();
// check for a reference for this product in the current shopping cart
// if there is no reference, add it and set quantity to 1
// otherwise, increment the quantity
let item$ = this.getItem(cartId, product.id);
item$.get().pipe(take(1)).subscribe((item) => {
item$.set ({ product: product, quantity: ((item.data()?.quantity || 0) + change) })
});
}
async removeFromCart(product: Product) {
this.updateItemQuantity(product, -1);
}
async addToCart(product: Product) {
this.updateItemQuantity(product, 1);
}
getTotalItemsCount(cart: ShoppingCart[]) {
let count = 0;
cart.forEach((item: any) => {
count += item.quantity;
})
return count;
}
}
导航栏组件:
import { ShoppingCartService } from './../shopping-cart.service';
import { UserService } from './../user.service';
import { AuthService } from './../auth.service';
import { Component, OnInit } from '@angular/core';
import { AppUser } from '../models/app.user';
@Component({
selector: 'bs-navbar',
templateUrl: './bs-navbar.component.html',
styleUrls: ['./bs-navbar.component.css']
})
export class BsNavbarComponent implements OnInit {
miniMenuToggle = false;
isAdmin = false;
username = '';
shoppingCartItemCount: number = 0;
constructor(
public auth: AuthService,
private userService: UserService,
private cartService: ShoppingCartService) {
this.userService.getUsername().subscribe(
(user: AppUser) => {
this.username = user.name;
this.isAdmin = user.isAdmin;
}
);
}
async ngOnInit() {
let cart$ = (await this.cartService.getCartItems());
cart$.subscribe(items => {
this.shoppingCartItemCount = 0;
items.forEach((item: any) => {
this.shoppingCartItemCount += item.quantity;
})
})
}
toggle() {
this.miniMenuToggle = !this.miniMenuToggle;
}
logout() {
this.auth.logout();
}
}
产品组件:
import { ProductId } from './../models/app.product';
import { ShoppingCartService } from './../shopping-cart.service';
import { switchMap } from 'rxjs/operators';
import { ActivatedRoute } from '@angular/router';
import { ProductService } from './../product.service';
import { Component, OnInit, OnDestroy } from '@angular/core';
import { Product } from '../models/app.product';
import { Subscription } from 'rxjs';
@Component({
selector: 'products',
templateUrl: './products.component.html',
styleUrls: ['./products.component.css']
})
export class ProductsComponent implements OnInit, OnDestroy{
products: ProductId[] = [];
filteredProducts: Product[] = []
category: string | null = '';
showActions = false;
cart: any;
subcription= new Subscription;
constructor(
productService: ProductService,
private shoppingCartService: ShoppingCartService,
route: ActivatedRoute) {
productService.getAll().pipe(
switchMap(products => {
this.products = products
return route.queryParamMap;
})
).subscribe(params => {
this.category = params.get('category');
this.filteredProducts = (this.category) ?
this.products.filter(prod => prod.category === this.category) :
this.products;
});
}
async ngOnInit() {
this.subcription = (await this.shoppingCartService
.getCartItems()).subscribe(cart => this.cart = cart);
}
ngOnDestroy() {
this.subcription.unsubscribe();
}
}
【问题讨论】:
-
我认为这可以解决这个问题:我将相应地实施和更新:stackoverflow.com/questions/39627396/…
标签: angular google-cloud-firestore service null subscription