Angular2: * ngFor не обновляется при обновлении массива

У меня есть массив объектов (назовем его arr). В одном из моих компонентных входов в методе (change) я изменяю один из этих атрибутов объекта, но в представлении (*ngFor) ничего не меняется. Я читал, что обнаружение изменений Angular2 не проверяет содержимое массивов или объектов, поэтому я пробовал эти:

this.arr = this.arr.slice();

и

this.arr = [...this.arr];

Но представление не меняется, оно по-прежнему показывает старый атрибут. В методе (change) с console.log() я получил правильный массив. Странно, но это работает: this.arr = []; Я также пробовал NgZone и markForCheck().

Ответ 1

Попробуйте создать глубокую копию, выполнив

this.arr = Object.assign({}, NEW_VALUE);

Ответ 2

Вы также можете использовать опцию trackBy в своем выражении *ngFor, предоставляя уникальный идентификатор для каждого элемента в массиве. Это делает вас на 100% ответственным за обнаружение изменений, поэтому обновляйте это (уникальное) свойство каждый раз, когда изменяется элемент в массиве. Затем Angular будет перерисовывать список только в том случае, если какой-либо элемент в вашем массиве получил другое свойство trackBy:

*ngFor="let item of (itemList$ | async); trackBy: trackItem"

или же:

*ngFor="let item of itemList; trackBy: trackItem"

где:

trackItem - это публичный метод в вашем компоненте:

public trackItem (index: number, item: Item) {
  return item.trackId;
}

Ответ 3

  • Проверьте, настроен ли ваш компонент с помощью changeDetection: cHangeDetectionStrategy.OnPush, если вы собираетесь это делать, после обновления массива вы должны вызвать changeDetectorRef.markForCheck()
  • Вы также можете реализовать привязку жизненного цикла onChange и изменить значения массива внутри этой функции.

Ответ 4

Поскольку вы упомянули, что вы уже пробовали markForCheck(), вы должны попробовать вместо этого использовать DetectionChanges (это то, что у меня сработало, а markForCheck не сработало). Для тех, кому нужны шаги:

Добавьте ChangeDetectorRef в ваш импорт:

import { Component, OnInit, ChangeDetectorRef } from '@angular/core';

Добавьте ChangeDetectorRef в ваш конструктор:

constructor(
    private changeDetection: ChangeDetectorRef
  ) { }

Затем на следующей строке после обновления массива:

this.changeDetection.detectChanges();

Ответ 5

Я решил эту ошибку, добавив директиву changDetection в @component следующим образом

    @Component({
      selector: 'app-page',
      templateUrl: './page.component.html',
      styleUrls: ['./page.component.scss'],
      changeDetection: ChangeDetectionStrategy.Default
    })

Вам также нужно импортировать его

import { Component, OnInit, ChangeDetectionStrategy } from '@angular/core';

Есть две стратегии на Push и Default

OnPush использует стратегию CheckOnce, что означает, что автоматическое обнаружение изменений отключается до тех пор, пока не будет активировано снова, если для стратегии задано значение Default (CheckAlways). Обнаружение изменений все еще может быть вызвано явно.

в то время как Default использует стратегию CheckAlways, в которой обнаружение изменений происходит автоматически до явной деактивации.

Исходные документы

Ответ 6

Если кто-нибудь еще столкнется с моей ситуацией, убедитесь, что компонент, который обновляется, является той же копией, что и отображаемый.

Я использовал @ViewChild(MyComponent, { static: true }) private test: MyComponent для передачи данных в компонент с помощью ngfor. (В моем случае это привело к блокировке другой копии, о которой я не знал)

Мне удалось это исправить, добавив атрибут #mycomp к тегу моего компонента в html и изменив вышеприведенное значение на @ViewChild('mycomp', { static: true }) private test: MyComponent