Обнаружение угловых изменений не сработало, части viewlayer не обновляются. ChangeDetectorRef не решает проблему.

У меня есть компонент:

import { Component, OnInit, Input, NgZone, ChangeDetectorRef } from '@angular/core';
import { Product } from '../product'; // data types
import { PRODUCTS } from '../mock-products'; // database
import { CartService } from '../cart.service'; // service
import { Subscription } from 'rxjs/Subscription';

@Component({
 selector: 'app-checkout',
 templateUrl: './checkout.component.html',
 styleUrls: ['./checkout.component.css']
 })


export class CheckoutComponent implements OnInit {

 get shoppingCart(): Product[] {
   const result = this.cartService.get();
   return result;
  }
 cartTotal: number;
 @Input() PRODUCTS: Product; 


 constructor(private cartService: CartService, private zone: NgZone, 
   private changeDetectionRef: ChangeDetectorRef) {
     this.cartService.shoppingCart.subscribe((nextValue) => {
     this.changeDetectionRef.detectChanges();
     console.log('nextValue', nextValue); // returns properly
     console.log(`subscribe: ${NgZone.isInAngularZone()}`);  // RETURNS TRUE
});

 }
 ngOnInit() {
  console.log(`ngOnInit: ${NgZone.isInAngularZone()}`); // RETURNS TRUE
  this.estimatedTotal();  // THIS FUNCTION RUNS BUT IS NEVER UPDATED WITH NEW VALUES
  }

 deleteItem(id, shoppingCart) {
  console.log('id to be deleted ' + id.toString());

   const newCart = [];
   for (let i = 0; i < shoppingCart.length; i++) {
     if (shoppingCart[i].id !== id) { 
    newCart.push(shoppingCart[i]); 
    }
  }

this.cartService.set(newCart); 
this.changeDetectionRef.detectChanges(); // THIS DOES NOT SEEM TO BE WORKING AT ALL 
}

  estimatedTotal() {
    const totals = [];
      for (let i = 0; i < this.shoppingCart.length; i++) { // looping through cart
        if (this.shoppingCart != null && this.shoppingCart.length > 0) {
          totals.push(this.shoppingCart[i].price * this.shoppingCart[i].quantity);
          this.cartTotal = totals.reduce((total, amount) => total + amount);
           } else {
            this.cartTotal = 0;
        }
      }
    }

который использует сервис get() и set() для localStorage:

import { Injectable, NgZone } from '@angular/core';
import { Product } from './product'; // data model
import { PRODUCTS } from './mock-products'; // database +
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import { ReplaySubject } from 'rxjs/ReplaySubject';
import { Subject } from 'rxjs/Subject';
import { CartItemComponent } from './cart-item/cart-item.component';
import { CheckoutComponent } from './checkout/checkout.component';

@Injectable()
export class CartService {
 shoppingCart: Subject<Object> = new ReplaySubject<Object>(1);
 constructor() { console.log(`cartService: ${NgZone.isInAngularZone()}`); }

 set(shoppingCart: Product[]) { 
  this.shoppingCart.next(shoppingCart);
  localStorage.setItem('shoppingCart', JSON.stringify(shoppingCart));

 }
 get() {
  return JSON.parse(localStorage.getItem('shoppingCart'));
  }


  }

Вот HTML-код:

<div class="pinned">
  <button (click)="checkOut()">
  <img src="./assets/icons/shoppingcart.png"/>
  </button>
</div>

<!--Modal 3-->
<div id="shoppingCart" class="modal">
<!--Modal 3 Content-->
 <div class="modal-content">
  <span class="closeModal" (click)="close()">&times;</span>
   <h3> Shopping Cart </h3>
  <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>
      <td></td>
      <td></td>
      <td></td>
      <td>Estimated Total:</td>
      <td></td>
      <td style = "font-weight:bold">${{cartTotal}}</td>
      <td></td>
    </tr>
    <tr>
      <button id="checkoutBtn" (click)="confirmCheckout()"> Checkout
  </button>
    </tr>

  </thead>
  <tbody id="tbodyCart"></tbody>
  </table>
 </div>
</div>

Проблема, с которой я сталкиваюсь, заключается в том, что мой пользовательский интерфейс не обновляет {{cartTotal}}, когда новые элементы добавляются, удаляются или когда localStorage (через cartService) изменяется каким-либо образом. Я думал, что это может быть проблема зоны, возможно, некоторые изменения были обработаны за пределами зоны, и все экземпляры NgZone.isInAngularZone() вернули true. Я подписался на cartService, чтобы посмотреть, может ли это решить проблему, и отключил ChangeDetection, что также не дало мне желаемых результатов. Затем я попытался принудительно применить ChangeDetection к подписке, это также не обновляет мой {{cartTotal}}. Я застрял на этом более суток, любой совет будет принята с благодарностью!

2 ответа

Вы вызываете оцениваемый общий доступ к ngOnInit, который вызывается только один раз после инициализации компонента. Поэтому нормально, что cartTotal никогда не обновляется.

Вы должны вызывать его всякий раз, когда корзина обновляется, то есть в методе подписки this.cartService.shoppingCart.subscribe

this.cartService.shoppingCart.subscribe((nextValue) => {
     this.estimatedTotal();
}

Решение Дэвида сработало частично, ценность будет обновлена, но всегда была на шаг позади. У меня было два компонента с одноуровневыми отношениями, которые опирались друг на друга, я закончил тем, что рекомбинировал эти компоненты как одни, у них не было слишком много функциональности. Это решило проблему!

Другие вопросы по тегам