对象数组内对象数组的对象部分的模板内强制更改检测

问题描述

无论我尝试什么,我似乎都无法触发模板内的对象的更改检测,该对象是对象数组中对象数组的一部分。这是(顶部)对象结构:

export interface CompatibleCards {
  appid: number,banned: boolean,items: { addedToTrade: boolean,appPosition: number,classid: number,iconUrl: string,marketHashName: string,name: string,numberOfListings: number,position: number,price: number,quantity: number,type: string }[],numberOfCardsInBadge: number,numberOfDifferentCards: number,totalNumberOfItems: number
}

这是模板:

<ng-container *ngIf="this.compatibleCards?.length else no_compatible_cards">
  <h3>{{ numberOfCompatibleCards }} cartes compatibles</h3>
  <div class="conteneur-ensembles">
    <div *ngFor="let currentApp of compatibleCards" class="conteneur-ensemble-compatible">
      <h3><a href="https://steamcommunity.com/id/raggart/gamecards/{{ currentApp.appid }}/" target="_blank">{{ currentApp.name }} ({{ currentApp.numberOfDifferentCards }} / {{ currentApp.numberOfCardsInBadge }} cards)</a></h3>
      <div class="conteneur-images-cartes">
        <span *ngFor="let currentItem of currentApp.items" title="{{ currentItem.name }}" [ngClass]="{ 'conteneur-carte': true,'ajoute-echange': currentItem.addedToTrade }" (click)="ajouterRetirerObjetPourEchange(currentItem,'ajouter')">
          <img class="image-carte" src="http://cdn.steamcommunity.com/economy/image/{{ currentItem.iconUrl }}" alt="{{ currentItem.name }}" title="{{ currentItem.addedToTrade }}">
          <span *ngIf="currentItem.price && currentItem.price > 0" class="prix-carte" title="{{ currentItem.name }}">{{ currentItem.price / 100 | currency }}</span>
          <span *ngIf="currentApp.banned" class="prix-carte" title="{{ currentItem.name }}">--</span>
        </span>
      </div>
    </div>
  </div>
</ng-container>

如您所见,我使用 [ngClass] 指令填充基于 CompatibleCards.items 对象的 addedToTrade 属性的 css 类。它正确填充,这意味着如果我在第一次渲染之前更改 addedToTrade 属性,则该类存在。但是,当我稍后尝试使用下面的代码更新对象时,模板不会显示删除该类。

  ajouterRetirerObjetPourEchange(objetAEchanger: any,operation : "ajouter" | "retirer") : void {
    console.log(objetAEchanger);

    if(operation == "ajouter") {
      this.itemsForTrade.push({...objetAEchanger});
    } else {
      const positionObjetEchangeTrouve = this.itemsForTrade.findindex((currentItem: any) => currentItem.classid == objetAEchanger.classid && currentItem.position == objetAEchanger.position);
      this.itemsForTrade.splice(positionObjetEchangeTrouve,1);
    }

    this.compatibleCards[objetAEchanger.appPosition].items[objetAEchanger.position].addedToTrade = ! this.compatibleCards[objetAEchanger.appPosition].items[objetAEchanger.position].addedToTrade;
    // this.compatibleCards[objetAEchanger.appPosition].items = [].concat(this.compatibleCards[objetAEchanger.appPosition].items);
    // this.compatibleCards = [].concat(this.compatibleCards);
 }

即使使用 [].concat 重新分配数组(或使用扩展 [...this.compatibleCards] 也不会更新模板(请参阅上述函数末尾的注释)。

在更新 items 数组内的对象后,有什么方法可以强制我的模板自行更新吗?

解决方法

第一个解决方案

尝试以编程方式强制检测更改。

在组件的构造函数中使用(通过注入)changeDetectorRef: ChangeDetectorRef

然后在更新表的地方使用 this.changeDetectorRef.detectChanges()

angular doc

第二种解决方案

如果这不起作用,那么您也可以尝试第二种选择。 您可以声明您的组件具有不同的检测策略 changeDetection:ChangeDetectionStrategy.OnPush

这将应用于组件级别,如

@Component({
  selector: 'my-app',template: `some template code`,changeDetection: ChangeDetectionStrategy.OnPush
})

但是请注意,因为这可能会产生副作用。检测策略自上而下起作用。这意味着如果你在你的组件上声明这个策略,它的所有子组件也将遵循这个策略。

同样在这种类型的策略上,Angular 不会检测原始字段的变化。它仅检测引用的更改。

因此,当您执行 this.compatibleCards = [...this.compatibleCards] 时,您更改了该字段的引用,因此必须将其捕获为来自 Angular 的更改。

angular detection strategy doc