web-dev-qa-db-fra.com

La détection des modifications ne se déclenche pas lorsque les valeurs du groupe de formulaires changent

J'ai créé un exemple simple pour démontrer un problème étrange auquel je suis confronté.

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

J'ai trois composants et les voici:

1 - composant d'application

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 - composant bonjour

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 - composant d'entrée

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)
  }
}

Dans le composant bonjour et le composant d'entrée, j'ai défini la stratégie de détection modifiée sur onpush. Comme vous le voyez ci-dessus, je crée une instance de groupe de formulaires dans le composant d'application et la transmets aux composants enfants. Maintenant, lorsque je clique sur le bouton du composant d'application pour modifier la valeur du formulaire, il modifie la valeur dans les champs de saisie, mais pas les textes en clair. Cela ne fonctionne que si je supprime la détection de changement on Push des deux composants enfants. Même ngOnChanges n'est pas appelé même si les valeurs du groupe de formulaires changent.

enter image description here

N'est-ce pas bizarre. Comment fonctionne la détection des modifications pour les entrées et non pour les textes en clair ici?

Quelqu'un pourrait-il m'expliquer cela s'il vous plaît? Et quelle est la solution de contournement sans supprimer la détection de changement onpush.

6
Ansuman

Au cours de la détection automatique des modifications (cd), exécutez Angular remarquera que les valeurs de votre FormGroup ont été mises à jour et met à jour l'interface utilisateur respectivement.

En définissant la stratégie de détection des modifications sur OnPush, vous désactivez la détection automatique des modifications exécutée par Angular. Dans ce cas, seules les valeurs internes sont mises à jour, mais Angular ne vérifierait pas les valeurs de l'interface utilisateur.

C'est peut-être une explication trop superficielle de ChangeDetection d'Angular, donc je recommande ceci blog pour un examen plus approfondi de ce sujet.

ngOnChanges ne se déclenche pas, car la référence d'objet (adresse mémoire) de votre FormGroup n'a pas été modifiée. ngOnChanges n'est déclenché que si vous passez primitives au @Input de vos composants. Et cela déclencherait également une nouvelle détection de changement exécutée par Angular.

Pour mettre à jour l'interface utilisateur, vous pouvez déclencher la détection des modifications manuellement en injectant ChangeDetectorRef dans votre composant parent et en appelant detectChanges().

Cela pourrait ressembler à ceci:

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(); 
}

J'espère que c'est compréhensible ;-)

0
Batajus

Angular ne détecte les changements que si l'adresse mémoire de la variable change. La définition de la valeur ne modifie pas l'adresse mémoire, donc ne frappe pas ngOnChanges.

Il en va de même avec les tableaux. Un Push simple n'atteint pas ngOnChanges, doit changer l'adresse mémoire par = en un nouveau tableau.

Essayez ceci:

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)
  }
}
0
user1779362