Как работает обнаружение изменений в элементе управления при исправлении формы?

#angular #angular-reactive-forms #angular-changedetection

#angular #angular-reactive-forms #angular-changedetection

Вопрос:

Мне было интересно, что происходит со следующим:

У меня есть FormGroup с этими элементами управления:

 {
  forename: new FormControl()
  surname: new FormControl()
}
  

теперь я отслеживаю изменения «фамилии» элемента управления следующим образом (просто пример):

 this.formGroup.get('surname').valueChanges.subscribe(changes => {
   if(this.formGroup.get('forename') == 'Max'){
      this.formGroup.get('forename').disable();
   }
})
  

и в конце я исправляю свою форму следующим образом:

this.formGroup.patchForm({surname: 'Muster', forename: 'Max'});

Будет ли отключен элемент управления ‘forename’? Потому что я не уверен, что это вызовет изменение «фамилии» элемента управления до того, как он сможет установить значение элемента управления «forename». Поэтому ‘forename’, вероятно, еще не имеет ‘правильного’ значения.

Я пытаюсь лучше понять, когда запускаются события exactle valueChanges, так как иногда у меня возникает проблема, что значения не установлены, хотя они должны быть.

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

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

1. попробуйте valueChanges для всего объекта формы. это сработает, если какое-либо значение в форме будет изменено, а затем вы можете использовать filter оператор для фильтрации типа. что-то вроде this.form.valueChanges.filter(x => x).subscribe(...)

2. Не уверен, как бы я сделал это для формы большего размера. Я могу сделать this.formGroup.valueChanges.subscribe(changes =>....) , что дало бы мне объект всех изменений, но тогда мне пришлось бы сравнить это с существующим объектом, чтобы определить, что на самом деле изменилось? У меня, вероятно, более 20 элементов управления, так что это не кажется хорошим решением. Не уверен, как я должен «фильтровать» его, поскольку нет чего-то вроде функции фильтра.

3. Если я изменю порядок реквизитов в объекте обновления на: { forname: 'Max', surname: 'Muster' } , то, похоже, все работает так, как задумано.

Ответ №1:

Причина:

valueChanges for surname сработает, как только patchValue() обновит первое свойство, поэтому вы получите null значение для forename , а условие this.formGroup.get('forename') == 'Max' будет false .

Решение 1:

Вы можете subscribe() использовать valueChanges весь formGroup элемент управления вместо одного, а затем проверить требуемое условие. Вот так:

 this.formGroup
      .valueChanges // subscribe to all changes
      .pipe(
        filter(form => form.forename === 'Max') // check if 'forname' is 'Max'
      ).subscribe(
        forename => this.formGroup.get('forename').disable() // disable control
      );
  

Решение 2:

Вы можете добиться желаемого поведения в своем коде, просто изменив порядок реквизитов в object для обновления. Вот так:

 this.formGroup.patchForm({ forename: 'Max', surname: 'Muster' });
  

Рабочая демонстрация с решением 1

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

1. Привет, спасибо за объяснение! На самом деле я рассматривал вариант решения 2, но я не хочу сталкиваться с ошибками только потому, что свойства в объекте не имеют определенного порядка.. Решение 1 также очень интересно! Наконец, я решил в основном указать другое значение Changes-Subscription в имени пользователя (я отвечу на свой собственный вопрос, чтобы продемонстрировать). Возможно, это не самый чистый вариант, но для моего проекта не было возможности перестроить все события valueChanges в соответствии с чем-то подобным первому решению.

Ответ №2:

Это то, что я закончил делать:

 this.formGroup.get('surname').valueChanges.subscribe(changes => {
   this.handleForenameControl();
})

this.formGroup.get('forename').valueChanges.subscribe(changes => {
   this.handleForenameControl();
})

private handleForenameControl():void{
  if(this.formGroup.get('forename') == 'Max'){
      this.formGroup.get('forename').disable();
   }
}
  

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

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

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

1. разве это не то же самое, что решение 1 ответа? Я имею в виду подписку на изменение всех значений формы или подписку на изменение всех значений по отдельности? по крайней мере, в этом случае, когда элементов управления всего 2. и да, это не самый чистый способ, но если это работает для вас, а не часть реального проекта, то я думаю, что это хорошо 🙂

2. наконец, если бы вы могли объяснить, почему вы не хотите использовать решение 1, тогда, возможно, я смог бы обновить его по мере необходимости.