我有一个 Angular 17 在线商店,但我遇到了 BehaviourSubject 未更新组件模板的问题。
客户选择产品,它们存储在 CartProduct 类中:id、name、num(该产品的元素数量)。然后一切都在 CartService 中管理,该服务有一个 BehaviourSubject 来存储它们:
@Injectable({
providedIn: "root",
})
export class CartService {
cartSubject: BehaviorSubject<CartProduct[]> = new BehaviorSubject<CartProduct[]>([]);
get cart$(): Observable<CartProduct[]> {
return this.cartSubject.asObservable();
}
...
}
它还有一个“add”方法,用于接收 CartProduct 项目。此方法检查产品是否已在购物车中,如果产品已在列表中,它只会增加“num”计数器,如果不在,则会添加它:
add(cartProd: CartProduct) {
const currentCart: CartProduct[] = this.cartSubject.getValue();
const ind: number = currentCart.findIndex((x: CartProduct): boolean => x.id === cartProd.id);
if (ind != -1) {
currentCart[ind].num += cartProd.num;
else {
}
currentCart.push(cartProd);
}
this.cartSubject.next(currentCart);
}
商店由三个组件组成(相当多,但这不是问题:P):HomeComponent、HeaderComponent 和 OneProductComponent。
HomeComponent 有一个标题,显示侧边栏,其中包含购物车中的元素列表:
import { Component, OnInit } from '@angular/core';
import { CartService } from './cart.service';
@Component({
selector: 'app-header',
template: `
<ul>
@for (product of cart; track product.id) {
<li>
{{ product.name }}
</li>
}
</ul>
`,
styleUrls: ['./header.component.css'],
})
export class HeaderComponent implements OnInit {
cart: CartProduct[] = [];
constructor(private cartService: CartService) {}
ngOnInit() {
this.cartService.cart$.subscribe(() => {
this.cart = this.cartService.cart$.value;
});
}
}
主页上有一个名为 OneProductComponent 的产品列表,基本上是一张图片、一个名称和一个将其添加到购物车的按钮。
import { Component } from '@angular/core';
import { CartService } from './cart.service';
@Component({
selector: 'app-one-product',
template: `
<h2>{{ product.name }}</h2>
<p>{{ product.price }} €</p>
<button (click)="addProduct()">Add product</button>
`,
styleUrls: ['./one-product.component.css'],
})
export class OneProductComponent {
constructor(private cartService: CartService) {}
addProduct() {
this.cartService.add({
id: 1,
name: 'Product 1',
price: 10,
num: 1,
});
}
}
问题是,当我单击组件上的按钮时,它不会反映在标题上。如果我导航到其他地方,标题会正确更新并显示购物车,但当我点击添加按钮时,它什么也不做。
我还在对服务的“添加”调用之后添加了此内容:
console.log(this.cartService.cartSubject.value);
我看到该产品已正确添加到购物车。但什么也没发生。我还尝试在购物车的添加方法上添加 EventEmitter 并在标题上订阅它:
CartService:
public productAdded$: EventEmitter<void>;
add(product: CartProduct) {
...
this.cartSubject.next(currentCart);
this.productAdded$.emit();
}
HeaderComponent:
constructor(cartService: CartService) {
this.cartService.productAdded$.subscribe((): void => { console.log('product added'); });
}
也什么也没有发生。看起来它在加载时正确订阅并且显示了购物车,但是当我进行任何更改时,模板不会更新。
编辑:我在列表中的每个产品上添加了一个“x”以将其删除。我看到列表,我添加一些内容(列表未更新),我删除一些内容,列表更新删除元素并显示我添加的元素!看起来标题模板仅在对模板执行操作时才会刷新!
谢谢!
您需要使用 observable 订阅中的值,而不是 observable.value
// Incorrect
this.cartService.cart$.subscribe(() => {
this.cart = this.cartService.cart$.value;
});
// Correct
this.cartService.cart$.subscribe(value => {
this.cart = value;
});
找到了!!问题是我在启动时将 CartService 作为全局提供程序加载,但我在 HeaderComponent 和 OneProductComponent 上也有一个“providers”数组。我刚刚从组件中删除了该数组...现在它可以完美运行:)
感谢bmtheo的帮助!