Обнаружение изменений не срабатывает при изменении значений группы форм - PullRequest
0 голосов
/ 05 декабря 2018

Я создал простой пример, чтобы продемонстрировать странную проблему, с которой я сталкиваюсь.

Stackblitz - https://stackblitz.com/edit/angular-change-detection-form-group

У меня есть три компонента, и вот они:

1 - компонент приложения

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

@Component({
  selector: 'my-app',
  template: `<hello [form]="form"></hello>
  <hr />
  <button (click)="changeFormValue()">Change Form Value</button>`,
  styleUrls: ['./app.component.css'],
  changeDetection: ChangeDetectionStrategy.OnPush

})
export class AppComponent implements OnInit {
  name = 'Angular';

  form: FormGroup;

  ngOnInit() {
    this.form = new FormGroup({
      name: new FormControl('ABC'),
      age: new FormControl('24')
    });
  }

  changeFormValue() {
    this.form.setValue({
      name: 'XYZ',
      age: 35
    })
  }
}

2 - привет компонент

import { Component, Input, OnChanges, ChangeDetectionStrategy } from '@angular/core';
import { FormGroup } from '@angular/forms';

@Component({
  selector: 'hello',
  template: `<form [formGroup]="form">
  <app-input [form]="form"></app-input>
  </form>`,
  styles: [``],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class HelloComponent implements OnChanges {
  @Input() form: FormGroup;

  ngOnChanges(changes) {
    console.log(changes)
  }
}

3 - компонент ввода

import { Component, Input, OnInit, OnChanges, ChangeDetectionStrategy } from '@angular/core';
import { FormGroup } from '@angular/forms';

@Component({
  selector: 'app-input',
  template: `Name : <input type="text" [formControl]="nameFormcontrol" /> {{nameFormcontrol.value}} <br /><br />
  Age : <input type="text" [formControl]="ageFormcontrol" /> {{ageFormcontrol.value}}`,
  styles: [``],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class InputComponent implements OnInit, OnChanges {
  @Input() form: FormGroup;
  nameFormcontrol;
  ageFormcontrol;

  ngOnInit() {
    this.nameFormcontrol = this.form.get('name');
    this.ageFormcontrol = this.form.get('age');
  }

  ngOnChanges(changes) {
    console.log(changes)
  }
}

И в компоненте hello, и в компоненте ввода я установил стратегию обнаружения изменений на onpush.Как вы видите выше, я создаю экземпляр группы форм в компоненте приложения и передаю его дочерним компонентам.Теперь, когда я нажимаю кнопку на компоненте приложения, чтобы изменить значение формы, оно меняет значение в полях ввода, но не на простые тексты.Это работает только в том случае, если я удаляю обнаружение изменений при нажатии на обоих дочерних компонентах.Даже ngOnChanges не вызывается, даже если значения группы форм меняются.

enter image description here

Разве это не странно.Как обнаружение изменений работает для входов, а не для простых текстов здесь?

Может кто-нибудь объяснить мне это, пожалуйста?И как это обойти, не снимая обнаружение изменения толчка.

Ответы [ 3 ]

0 голосов
/ 06 декабря 2018

Во время запуска автоматического обнаружения изменений (cd) Angular заметит, что значения вашего FormGroup были обновлены, и обновит пользовательский интерфейс соответственно.

Установив стратегию обнаружения изменений на OnPush, вы деактивируете автоматический поиск изменений, запускаемый Angular.В этом случае обновляются только внутренние значения, но Angular не будет проверять значения пользовательского интерфейса.

Возможно, это слишком поверхностное объяснение ChangeDetection от Angular, поэтому я рекомендую этот blog дляболее глубокий взгляд на эту тему.

ngOnChanges не сработает, поскольку ссылка на объект (адрес памяти) вашего FormGroup не была изменена.ngOnChanges срабатывает только в том случае, если вы передаете примитивы @Input ваших компонентов.И это также вызовет запуск нового обнаружения изменений Angular.

Чтобы обновить пользовательский интерфейс, вы можете запустить обнаружение изменений вручную, введя ChangeDetectorRef в родительский компонент и вызвав detectChanges().

Это может выглядеть так:

constructor(private cd: ChangeDetectorRef) {}
...
changeFormValue() {
    this.form.setValue({
        name: 'XYZ',
        age: 35
    });
    // This will trigger the change detection and your input field are updated
    this.cd.detectChanges(); 
}

Надеюсь, это понятно; -)

0 голосов
/ 06 декабря 2018

Я нашел обходной путь для этой проблемы, хотя я не уверен, является ли это идеальным решением.

Мы можем прослушать изменения значения группы форм и затем запустить обнаружение изменений во входном компоненте

this.form.valueChanges.subscribe( () => {
  this.cdr.detectChanges()
});

Таким образом, он обновляет значения меток вместе со входами.

enter image description here

Вот решение:

https://stackblitz.com/edit/angular-change-detection-form-group-value-change-issue-resolved

Я не уверен, что это ошибка от Angular, но рад, что нашел какой-то обходной путь:)

0 голосов
/ 06 декабря 2018

Angular обнаруживает изменения только при изменении адреса памяти переменной.Установка значения не меняет адрес памяти, поэтому не затрагивает ngOnChanges.

То же самое относится и к массивам.Простое нажатие не затрагивает ngOnChanges, нужно изменить адрес памяти с помощью = на новый массив.

Попробуйте это:

import { Component, Input, OnInit, OnChanges, ChangeDetectionStrategy } from '@angular/core';
import { FormGroup } from '@angular/forms';

@Component({
  selector: 'app-input',
  template: `
  <div formGroupName="form">
      Name : <input type="text" formControlName="name" /> {{form.value.name}} <br /><br />
      Age : <input type="text" formControlName="age" /> {{form.value.age}}
  </div>`,
  styles: [``],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class InputComponent implements OnInit, OnChanges {
  @Input() form: FormGroup;

  ngOnInit() {
  }

  ngOnChanges(changes) {
    console.log(changes)
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...