简体   繁体   English

Angular 中子属性的更改检测

[英]Change detection for child property in Angular

I have the following Product object inside an Angular application.我在 Angular 应用程序中有以下 Product 对象。 The product contains array of orders and other product information.该产品包含一系列订单和其他产品信息。

Product.ts产品.ts

export interface Product { 
    ProductID: number;
    ProductName: string;
    Orders: Order[]
}

I need to display product information and generate order summary inside a child angular component.我需要在子角度组件中显示产品信息并生成订单摘要。

order-summary.component.ts订单摘要.component.ts

export class OrderSummary {

  _product: Product;
  @Input() set product(value: Product) {
    this._product = value;
    this.generateOrderSummary(value.Orders);
  }

  private generateOrderSummary(orders: Order[]) {
   // Logic to generate order summary
  }

}

order-summary.component.html订单摘要.component.html

<b>{{_product.ProductName}}</b>
<b> ... show other product details </b>
<table> ... show generated order summary ... </table>

I believe every time the product object changes, it will generate the order summary ( generateOrderSummary ) even if the Orders array hasn't been changed.我相信每次产品对象更改时,即使Orders数组没有更改,它也会生成订单摘要( generateOrderSummary )。 What is a better way to fix this issue?解决此问题的更好方法是什么?

I am thinking of adding another property for Orders[] so I can regenerate summary only when order has been changed.我正在考虑为 Orders[] 添加另一个属性,因此只有在订单更改时我才能重新生成摘要。 However, product already contains orders not sure if it is a good design.但是,产品已经包含订单,不确定它是否是一个好的设计。

order-summary.component.ts订单摘要.component.ts

export class OrderSummary {
  _product: Product;
  @Input() set product(value: Product) {
    this._product = value;
  }

  @Input() set orders(value: Orders[]) {
    this.generateOrderSummary(value.Orders);
  }

  private generateOrderSummary(orders: Order[]) {
   // Logic to generate order summary
  }
}

Are there any better solutions?有没有更好的解决方案?

In this case you could skip the setter implementation of the @Input and use Angular OnChanges hook with SimpleChanges parameter.在这种情况下,您可以跳过@Input的 setter 实现并使用带有SimpleChanges参数的 Angular OnChanges钩子。 It allows you to check if it's the first invoke of the component and compare previous and current values of the @Input property.它允许您检查它是否是组件的第一次调用,并比较@Input属性的先前值和当前值。

Try the following尝试以下

order-summary.component.ts订单摘要.component.ts

import { Component, Input, OnChanges, SimpleChanges } from '@angular/core';

export class OrderSummary implements OnChanges {
  @Input() product: Product;

  ngOnChanges(changes: SimpleChanges) {
    if (!!changes.product) {
      if (changes.product.firstChange) {                 // <-- first time the component is rendered
        this.generateOrderSummary(this.product.orders);  // <-- could also be `changes.product.currentValue.orders`
      } else if (                                        // <-- true only if different `orders` value
        !!changes.product.previousValue &&
        !!changes.product.previousValue.orders &&
        changes.product.previousValue.orders !== changes.product.currentValue.orders
      ) {
        this.generateOrderSummary(product.orders);
      }
    }
  }

  private generateOrderSummary(orders: Order[]) {
    // Logic to generate order summary
  }
}

order-summary.component.html订单摘要.component.html

<b>{{ product?.ProductName }}</b>
<b> ... show other product details </b>
<table> ... show generated order summary ... </table>

I think you could use observables and rxjs logic like this.我认为你可以像这样使用 observables 和 rxjs 逻辑。

export class OrderSummary implements OnInit {
  product$: Observable<Product>;
  private productSubject$ = new Subject();

  @Input() set product(value: Product) {
    this.productSubject$.next(value);
  }
  
  ngOnInit(): void {
    this.product$ = this.productSubject$.pipe(
          distinctUntilChanged((prev: Product, curr: Product) => prev.ProductId === curr.ProductId), 
          map(prod => {
             this.generateOrderSummary(prod.orders);
             return prod;
          })
  }


  private generateOrderSummary(orders: Order[]) {
   // Logic to generate order summary
  }

}

and subscribe to product in your html并在您的 html 中订阅产品

<div *ngIf="product$ | async as product">
   <b>{{product.ProductName}}</b>
   <b> ... show other product details </b>
   <table> ... show generated order summary ... </table>
</div>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM