使用localStorage保存的数据在不刷新的情况下无法更新Angular组件视图层。

4

我有两个组件,它们都使用同一个服务从localStorage中获取(get())和设置(set())项目。其中一个组件将项目添加到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获取数据,并在表格中显示数据。
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';
   }

在这个组件中,我可以通过运行 this.cartService.get() 来更改localStorage并实时查看更改。

 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,但是表格不会更新新数据,除非刷新页面。

这是HTML表格,它使用*ngFor循环遍历“shoppingCart”并创建表格:

<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,但都没有生效。我在stackOverflow上搜索了很久,也读了RxJs observables的相关内容,但是我并没有能够应用它们或者完全理解它们的工作方式,也不确定那是否是正确答案。我如何才能让我的视图层对另一个组件中localStorage的更改做出响应而不刷新?我是Angular的新手,希望得到一个Angular的解决方案,但任何指导都会有所帮助!


你的表格中为什么有 confirmCheckout,但是在 .ts 文件中却有 checkout 方法?这可能是一个打字错误或者你忘记展示代码了。你是否尝试过移除结账的模态框并查看发生了什么? - Asura
confirmCheckout()是一个不同的函数,在CheckoutComponent中尚未编写。实际上,checkOut()只是在HTML中单击按钮时显示/拉起模态框(我现在意识到我没有在上面包含它)。如果我删除模态方面,那么我将无法查看“购物车”中的物品,因为它们就住在那里。 - Robin
你能否在 https://stackblitz.com/ 上发布一个小的示例以展示问题?在许多情况下,Stackblitz 示例可以极大地帮助我们找到问题和解决方案。此外,在Angular中使用@ViewChild和将HTML字段映射为#id时,无需使用getDocumentById。 - Asura
2个回答

3
尝试更改这个:

 shoppingCart: Product[]; 

转换为:

 get shoppingCart(): Product[] {
   this.cartService.get();
 };

那么每当内置变化检测(built-in change detection)检测到变化并重新评估绑定时,getter 函数将被调用并获取当前值。

我尚未尝试过将此技术与本地存储一起使用……但是它在服务方面运行良好,因此在这种情况下也可能有效。


干得好!谢谢!以下是我所做的更改:get shoppingCart( ): Product[ ] { const result = this.cartService.get(); return result; } constructor(private cartService: CartService) { 删除此处的内容 } 在我的删除功能中,我只需调用 this.cartService.get( ) 来使表格在进行更改/删除项目后重新生成。 - Robin
太好了!如果这解决了您的问题,您能将其标记为答案,以便问题可以关闭吗?谢谢! - DeborahK

0

我不确定这是否是最佳方法,但在CartService中,在构造函数之前,您可以添加一个名为“cart”的公共变量,例如BehaviorSubject类型的实例...

cart: Subject<Product[]> = new BehaviorSubject<Product[]>(null);

然后您将更改cartService中的代码,以便每次更改shoppingCart内容时通过调用其“next”函数更新其cart变量

this.cart.next(shoppingCart);

这将允许您在使用cartService的任何地方“订阅”对购物车变量所做的任何更改。例如,在您的CheckoutComponent的ngOnInit()函数中,您可以编写以下代码:

this.cartService.cart.subscribe((newCart) => { this.shoppingCart = newCart });    

这段代码的效果是,每当您通过cartService更新购物车内容时,所有订阅该购物车变量的位置都会得到更新。这有点间接,因为您并不直接订阅localStorage中的内容,而是订阅了一个负责处理这些localStorage内容的服务中的变量,但它应该能够解决问题。我很想知道您是否发现了更直接的方法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接