Угловой: Выражение изменилось после проверки. Предыдущее значение: «не определено». Текущее значение: ‘[объект Объекта]’

#angular #core-js

Вопрос:

У меня возникла проблема после обновления angular и зависимостей до более поздних версий.

Приложение работает как и раньше, но я увидел сообщение об ошибке в консоли, которого у меня раньше не было:

 ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'undefined'. Current value: '[object Object]'.
 

Похоже, у меня эта проблема с более поздней версией «core-js».

После поиска в Интернете кажется, что ошибка может возникнуть с @ViewChild, используемым для автозаполнения, но я не понимаю, в чем дело. Кроме того, похоже, что код, ответственный за эту ошибку, следующий:

  • В html первого компонента я использую компонент с автозаполнением:
 <mat-form-field>
  <mat-placeholder>...</mat-placeholder>
  <input class="t-myClass" type="text" matInput
    [formControl]="myFormGroup.controls['myField']" (change)="resetValidity()"
    [matAutocomplete]="myAutocomplete.autocomplete" #myField>
  <app-my-autocomplete #myAutocomplete="appMyAutocomplete"
    [inputFormControl]="myFormGroup.controls['myField']" [inputElement]="myField">
  </app-my-autocomplete>
</mat-form-field> 
  • В компоненте с компонентом автозаполнения у меня есть это:
 export class MyAutocompleteComponent implements OnInit, OnChanges, OnDestroy {

  @Input()
  inputFormControl: FormControl;

  @Input()
  inputElement: HTMLInputElement;

  @ViewChild('autocomplete')
  autocomplete: MatAutocomplete;

  filteredObjects: Observable<MyElement[]>;

  //inputFormSubscription: Subscription;

  constructor(
    private myElementService: MyElementService,
    ...
  ) { }

  ngOnChanges() {
    
  }

  onSelection() {
    if (this.inputElement) {
      // Need to create a timeout cause the input is selected just after the option selection
      setTimeout(() => {
        this.inputElement.blur();
      }, 0);
    }
  }

  ngOnInit() {
    //this.inputFormSubscription = this.inputFormControl.valueChanges.subscribe(val => this.filteredObjects = this.geographyElementService.getGeographyElements(val));
    this.filteredObjects = this.inputFormControl.valueChanges.pipe(switchMap(val => this.geographyElementService.getGeographyElements(val)));
  }

  ngOnDestroy() {
    //this.inputFormSubscription.unsubscribe();
  }

  ...
} 
  • HTML, связанный с этим компонентом (с автозаполнением), является:
 <mat-autocomplete #autocomplete [displayWith]="label.bind(this)" panelWidth="240px">
    <mat-option *ngFor="let object of filteredObjects | async " [value]="object" (onSelectionChange)="onSelection()">
        {{ object.code }} - {{ object.description }}
    </mat-option>
</mat-autocomplete> 

При отладке я обнаружил, что текущее значение, соответствующее ошибке, является объектом MatAutocomplete, поэтому кажется, что он подтверждает, что это именно этот код, но я не понимаю, почему, потому что код работает.

Не могли бы вы помочь мне решить эту проблему, пожалуйста?

Изменить: Я обновил код в соответствии с данным ответом, но ошибка все равно возникает.

Комментарии:

1. Зачем вам подписываться на изменение значения элемента управления формой внутри цикла ngOnChanges жизненного цикла? Этот параметр вызывается несколько раз в течение срока службы компонента (при каждом изменении свойства). Можете ли вы попробовать перенести это ngOnInit вместо этого? Во-вторых, этой подпиской необходимо управлять, вам нужно отказаться от подписки, когда компонент будет уничтожен, иначе у вас произойдет утечка памяти.

2. И вам даже не нужна эта подписка: вместо этого сделайте this.filteredObjects = this.inputFormControl.valueChanges.pipe(switchMap(//... это .

3. Спасибо. Я сделал подобное изменение в методе ngOnInit (): this.filteredObjects = this.inputFormControl.valueChanges.pipe(switchMap(val => this.filteredObjects = this.myElementService.getMyElements(val))); Но ошибка все равно появляется.

4. Как filteredObjects они потребляются?

5. Я обновил сообщение с помощью html — кода для компонента с автозаполнением. Он потребляется в ngFor.

Ответ №1:

Решение состояло в том, чтобы использовать статику со значением true для автозаполнения:

 @ViewChild('autocomplete', { static: true })
autocomplete: MatAutocomplete;