Angular 组件视图层未随 localStorage 更新而未刷新
Angular component view layer not updating with localStorage changes without refresh
我有两个组件使用相同的服务将 get() 和 set() 项目用于本地存储。一个组件 sets()/'adds' items to localStorage
import { Component, OnInit, Input } from '@angular/core';
import {Product} from '../product';
import { PRODUCTS } from '../mock-products';
import {CartService} from '../cart.service';
@Component({
selector: 'app-cart-item',
templateUrl: './cart-item.component.html',
styleUrls: ['./cart-item.component.css']
})
export class CartItemComponent implements OnInit {
@Input() cartItem: Product;
constructor(private cartService: CartService) { }
ngOnInit() { }
addToCart() { // adds item to localStorage
this.closeModal();
alert('item(s) successfully added to cart');
const cart = [];
const currentCart = this.cartService.get();
if (currentCart != null && currentCart.length > 0) {
for (let i = 0; i < currentCart.length; i++) {
cart.push(currentCart[i]);
}
}
cart.push(this.cartItem);
this.cartService.set(cart);
}
}
另一个组件从 localStorage 获取()数据,在 table.
中显示数据
import { Component, OnInit, Input, ChangeDetectionStrategy } from
'@angular/core';
import { Product } from '../product'; // data types
import { PRODUCTS } from '../mock-products'; // database
import { CartService } from '../cart.service'; // service
@Component({
selector: 'app-checkout',
templateUrl: './checkout.component.html',
styleUrls: ['./checkout.component.css']
})
export class CheckoutComponent implements OnInit {
shoppingCart: Product[];
@Input() PRODUCTS: Product;
constructor(private cartService: CartService) { this.shoppingCart =
this.cartService.get(); }
ngOnInit() {}
checkOut() {
this.shoppingCart = this.cartService.get();
console.log(this.shoppingCart); // service is working, changes are
not being reflected in HTML
const span = document.getElementsByClassName('closeModal')[0];
const modal = document.getElementById('shoppingCart'); // pulls up
modal
modal.style.display = 'block';
}
在同一个组件中,我可以更改 localStorage 并通过 运行 查看实时更改:this.cartService.get()
deleteItem(id, shoppingCart) {
const newCart = [];
for (let i = 0; i < shoppingCart.length; i++) {
if (shoppingCart[i].id !== id) {
newCart.push(shoppingCart[i]);
}
}
this.cartService.set(newCart);
this.shoppingCart = this.cartService.get();
}
}
我已记录控制台并且正在将新项目设置 () 到 localStorage,table 只是不会更新新数据,除非刷新。
这是未更新的 HTML table,它使用 *ngFor 循环 'shoppingCart' 并创建 table:
<table id="shoppingCartTable" >
<thead>
<th> Item </th>
<th> </th>
<th> </th>
<th> Price </th>
<th> Quantity </th>
<th> Total </th>
<th> Delete? </th>
<tr *ngFor="let cartItem of this.shoppingCart">
<td>{{cartItem.productName}}</td>
<td><img src={{cartItem.img}} /></td>
<td>{{cartItem.description}}</td>
<td>${{cartItem.price}}</td>
<td>{{cartItem.quantity}}</td>
<td>{{cartItem.price * cartItem.quantity}}</td>
<td><button><img src="./assets/icons/trashcan.png"
(click)="deleteItem(cartItem.id, shoppingCart)" /></button></td>
</tr>
<tr>
<button id="checkoutBtn"(click)="confirmCheckout()"> Checkout
</button>
</tr>
</thead>
<tbody id="tbodyCart"></tbody>
</table>
这是我的服务:
import { Injectable } from '@angular/core';
import { Product } from './product'; // data model
import { PRODUCTS } from './mock-products'; // database +
@Injectable()
export class CartService {
constructor() { }
set(shoppingCart: Product[]) {
localStorage.setItem('shoppingCart', JSON.stringify(shoppingCart));
}
get() {
return JSON.parse(localStorage.getItem('shoppingCart'));
}
}
我试过使用默认的 ChangeDetectionStrategy 和 .OnPush,都没有用。我梳理了 Whosebug 并阅读了有关 RxJs observables 的内容,但未能 apply/am 不太了解它们的工作原理,甚至不确定这就是答案。我如何让我的视图层在不刷新的情况下响应来自另一个组件的 localStorage 中的更改?我是 Angular 的新手,想要 Angular 解决方案,但任何方向都会有所帮助!
我不确定这是否是最好的方法,但是在 CartService 中,您可以在构造函数之前添加一个名为 'cart' 的 public 变量,例如 BehaviorSubject 类型的实例,例如所以...
cart: Subject<Product[]> = new BehaviorSubject<Product[]>(null);
然后您将更改 cartService 中的代码,以便在每次更改 shoppingCart 内容时通过调用它的 'next' 函数来更新它的 cart 变量
this.cart.next(shoppingCart);
这将允许您 'subscribe' 在您使用 cartService 的任何地方对 cart 变量所做的任何更改。例如,在 CheckoutComponent 的 ngOnInit() 函数中,您可以编写
this.cartService.cart.subscribe((newCart) => { this.shoppingCart = newCart });
此代码的效果是,每次您通过 cartService 更新购物车的内容时,您 'subscribed' 到该购物车变量的所有位置都会更新。这有点间接,因为您不是直接订阅 localStorage 中的内容,而是订阅服务中负责处理这些 localStorage 内容的变量,但它应该可以解决问题。我很想知道您是否找到了更直接的东西。
尝试改变这个:
shoppingCart: Product[];
为此:
get shoppingCart(): Product[] {
this.cartService.get();
};
然后每次内置更改检测发现更改并重新评估绑定时,都会调用 getter 并获取当前值。
我还没有在本地存储上尝试过这种技术……但它对服务非常有效,所以在这种情况下也可以。
我有两个组件使用相同的服务将 get() 和 set() 项目用于本地存储。一个组件 sets()/'adds' items to localStorage
import { Component, OnInit, Input } from '@angular/core';
import {Product} from '../product';
import { PRODUCTS } from '../mock-products';
import {CartService} from '../cart.service';
@Component({
selector: 'app-cart-item',
templateUrl: './cart-item.component.html',
styleUrls: ['./cart-item.component.css']
})
export class CartItemComponent implements OnInit {
@Input() cartItem: Product;
constructor(private cartService: CartService) { }
ngOnInit() { }
addToCart() { // adds item to localStorage
this.closeModal();
alert('item(s) successfully added to cart');
const cart = [];
const currentCart = this.cartService.get();
if (currentCart != null && currentCart.length > 0) {
for (let i = 0; i < currentCart.length; i++) {
cart.push(currentCart[i]);
}
}
cart.push(this.cartItem);
this.cartService.set(cart);
}
}
另一个组件从 localStorage 获取()数据,在 table.
中显示数据import { Component, OnInit, Input, ChangeDetectionStrategy } from
'@angular/core';
import { Product } from '../product'; // data types
import { PRODUCTS } from '../mock-products'; // database
import { CartService } from '../cart.service'; // service
@Component({
selector: 'app-checkout',
templateUrl: './checkout.component.html',
styleUrls: ['./checkout.component.css']
})
export class CheckoutComponent implements OnInit {
shoppingCart: Product[];
@Input() PRODUCTS: Product;
constructor(private cartService: CartService) { this.shoppingCart =
this.cartService.get(); }
ngOnInit() {}
checkOut() {
this.shoppingCart = this.cartService.get();
console.log(this.shoppingCart); // service is working, changes are
not being reflected in HTML
const span = document.getElementsByClassName('closeModal')[0];
const modal = document.getElementById('shoppingCart'); // pulls up
modal
modal.style.display = 'block';
}
在同一个组件中,我可以更改 localStorage 并通过 运行 查看实时更改:this.cartService.get()
deleteItem(id, shoppingCart) {
const newCart = [];
for (let i = 0; i < shoppingCart.length; i++) {
if (shoppingCart[i].id !== id) {
newCart.push(shoppingCart[i]);
}
}
this.cartService.set(newCart);
this.shoppingCart = this.cartService.get();
}
}
我已记录控制台并且正在将新项目设置 () 到 localStorage,table 只是不会更新新数据,除非刷新。
这是未更新的 HTML table,它使用 *ngFor 循环 'shoppingCart' 并创建 table:
<table id="shoppingCartTable" >
<thead>
<th> Item </th>
<th> </th>
<th> </th>
<th> Price </th>
<th> Quantity </th>
<th> Total </th>
<th> Delete? </th>
<tr *ngFor="let cartItem of this.shoppingCart">
<td>{{cartItem.productName}}</td>
<td><img src={{cartItem.img}} /></td>
<td>{{cartItem.description}}</td>
<td>${{cartItem.price}}</td>
<td>{{cartItem.quantity}}</td>
<td>{{cartItem.price * cartItem.quantity}}</td>
<td><button><img src="./assets/icons/trashcan.png"
(click)="deleteItem(cartItem.id, shoppingCart)" /></button></td>
</tr>
<tr>
<button id="checkoutBtn"(click)="confirmCheckout()"> Checkout
</button>
</tr>
</thead>
<tbody id="tbodyCart"></tbody>
</table>
这是我的服务:
import { Injectable } from '@angular/core';
import { Product } from './product'; // data model
import { PRODUCTS } from './mock-products'; // database +
@Injectable()
export class CartService {
constructor() { }
set(shoppingCart: Product[]) {
localStorage.setItem('shoppingCart', JSON.stringify(shoppingCart));
}
get() {
return JSON.parse(localStorage.getItem('shoppingCart'));
}
}
我试过使用默认的 ChangeDetectionStrategy 和 .OnPush,都没有用。我梳理了 Whosebug 并阅读了有关 RxJs observables 的内容,但未能 apply/am 不太了解它们的工作原理,甚至不确定这就是答案。我如何让我的视图层在不刷新的情况下响应来自另一个组件的 localStorage 中的更改?我是 Angular 的新手,想要 Angular 解决方案,但任何方向都会有所帮助!
我不确定这是否是最好的方法,但是在 CartService 中,您可以在构造函数之前添加一个名为 'cart' 的 public 变量,例如 BehaviorSubject 类型的实例,例如所以...
cart: Subject<Product[]> = new BehaviorSubject<Product[]>(null);
然后您将更改 cartService 中的代码,以便在每次更改 shoppingCart 内容时通过调用它的 'next' 函数来更新它的 cart 变量
this.cart.next(shoppingCart);
这将允许您 'subscribe' 在您使用 cartService 的任何地方对 cart 变量所做的任何更改。例如,在 CheckoutComponent 的 ngOnInit() 函数中,您可以编写
this.cartService.cart.subscribe((newCart) => { this.shoppingCart = newCart });
此代码的效果是,每次您通过 cartService 更新购物车的内容时,您 'subscribed' 到该购物车变量的所有位置都会更新。这有点间接,因为您不是直接订阅 localStorage 中的内容,而是订阅服务中负责处理这些 localStorage 内容的变量,但它应该可以解决问题。我很想知道您是否找到了更直接的东西。
尝试改变这个:
shoppingCart: Product[];
为此:
get shoppingCart(): Product[] {
this.cartService.get();
};
然后每次内置更改检测发现更改并重新评估绑定时,都会调用 getter 并获取当前值。
我还没有在本地存储上尝试过这种技术……但它对服务非常有效,所以在这种情况下也可以。