FormGroup в angular не правильно видит отдельные изменения своих дочерних элементов, если они слушают друг друга через valueChanges - PullRequest
3 голосов
/ 11 октября 2019

У меня простая ситуация. Существует HTML-форма с двумя полями:

  • firstName
  • lastName

Я хочу, чтобы lastName что-то изменило, когда пользователь изменит firstName,Я реализовал это через valueChanges, наблюдаемые в Angular (8).

Кроме того, у меня есть две подписки для прослушивания и регистрации изменений:

  • одна на всю форму
  • одна на lastName

Вот как это реализовано:

 ngOnInit(){
    this.form = new FormGroup({
      firstName: new FormControl('', {updateOn: 'blur'}),
      lastName: new FormControl('', {updateOn: 'blur'}),
    });
    this.form.get('lastName').valueChanges.subscribe(value => console.log('lastName', value));
    this.form.valueChanges.subscribe(value => console.log('Value', value));

    this.form.get('firstName').valueChanges
      .subscribe(firstName => {
        this.form.get('lastName').setValue(`firstName ${firstName} ${new Date().getMilliseconds()}`);
      });
  }

В общем - с точки зрения пользователя - это ведет себя как ожидалось. Пользователь меняет firstName, а затем lastName меняет сам.

Но когда я смотрю журнал консоли, вот что я получил:

lastName firstName test 850 
Value > {firstName: "test", lastName: "firstName test 850"}
Value > {firstName: "test", lastName: "firstName test 850"}

Я ожидал, что два журнала целиком, но один с первым именем изменен, а второй с lastNameизменилось. Примерно так:

Value > {firstName: "test", lastName: ""}
lastName firstName test 850 
Value > {firstName: "test", lastName: "firstName test 850"}

Вот целый пример stackblitz .

Хорошо, поэтому, когда я изменил способ, я обновляю lastName из этого:

this.form.get('lastName').setValue(`firstName ${firstName} ${new Date().getMilliseconds()}`);

на это:

setTimeout(() => this.form.get('lastName').setValue(`firstName ${firstName} ${new Date().getMilliseconds()}`));

тогда журналы в порядке, который я ожидал:

Value > {firstName: "test", lastName: ""}
lastName firstName test 850 
Value > {firstName: "test", lastName: "firstName test 850"}

Однако, setTimeout кажется хитрым взломом здесь,Вот весь код на stackblitz .

Вопрос: что здесь происходит? Почему FormGroups работает таким образом? Есть ли шаблон для обработки таких событий в Angular (когда одна форма влияет на другую)?

1 Ответ

3 голосов
/ 11 октября 2019

Вот как работает цикл обработки событий

Что происходит в обоих случаях:

Без setTimeout

  1. Пользовательское имя firstName
  2. firstName.valueChangesдобавляется в EventLoop очередь
  3. EventLoop выполняется и вызывается операция firstName.valueChanges
  4. lastName.setValue называется
  5. lastName.setValue добавляется lastName.valueChanges и form.valueChanges в очередь EventLoop
  6. lastName.valueChanges добавление form.valueChanges в очередь EventLoop
  7. lastName.valueChanges в очереди
  8. form.valueChanges (из lastName.valueChanges) в очереди
  9. form.valueChanges (из firstName.valueChanges) исключен из системы

С setTimeout

  1. Пользовательское имя firstName
  2. firstName.valueChanges добавлено вEventLoop очередь
  3. EventLoop выполняется и операция вызова firstName.valueChanges
  4. setTimeout(lastName.setValue) не вызывается, но добавляется в очередь цикла событий
  5. firstName.valueChanges добавляет form.valueChanges в очередь цикла событий
  6. setTimeout исключен из очереди, он устанавливает значение lastName и добавляет lastName.valueChanges в очередь цикла событий
  7. form.valueChanges (из firstName.valueChanges) в очереди
  8. lastName.valueChanges исключается из очереди и добавляет form.valueChanges в очередь цикла событий
  9. form.valueChanges (из lastName.valueChanges) снята с производства
...