Angular formGroup, как определить, изменилась ли форма в подписке? - PullRequest
1 голос
/ 27 апреля 2020

Я пытаюсь создать функцию, которая обнаружит, если angular formGroup действительно изменит свои значения:

 subscribeToFormChanges() {
    const formSub = this.formGroup.valueChanges.subscribe(value => {
      console.log(this.formGroup.getRawValue());
      console.log(value);
      if (this.formGroup.getRawValue() == value) {
        console.log('equal');
      } else {
        console.log('not changed');
      }
    },
      (error) => {
        console.log(error)
      },
      () => {
        this.subs.add(formSub);
      })
  }

ПОЧЕМУ? - потому что есть выбор, где вы можете выбрать то же значение, и оно будет .setValue на control.

Но оно всегда возвращает не изменилось, даже если я изменяю значения. Как сделать это правильно?

Второй подход:

  subscribeToFormChanges() {
    const formSub = this.formGroup.valueChanges.pipe(startWith(null), pairwise()).subscribe(([prev, next]: [any, any]) => {
      if (prev == next) {
        console.log('equal');
      } else {
        console.log('not changed');
      }
    },
      (error) => {
        console.log(error)
      },
      () => {
        this.subs.add(formSub);
      })
  }

Возвраты не изменяются все время

1 Ответ

0 голосов
/ 27 апреля 2020

Вы получаете эти результаты, потому что вы сравниваете 2 разные ссылки.

Вы можете визуализировать дерево элементов управления следующим образом:

// FG - FormGroup
// FC - FormControl

    FG
  /   \
 FC   FG
     /  \
   FC   FC <-- <select formControlName="yourSelect">

Всякий раз, когда вызывается FormControl.setValue (например, из-за изменений, исходящих от пользователя), все его предки должны быть обновлены. Под updated я подразумеваю обновление статуса взаимодействия с пользователем (touched, pristine et c), вызова валидаторов и обновления статуса достоверности .

За это отвечает метод updateValueAndValidity. Он вызывается FormControl.setValue:

this._setInitialStatus();
this._updateValue();

if (this.enabled) {
  this._cancelExistingSubscription();
  (this as { errors: ValidationErrors | null }).errors = this._runValidator();
  (this as { status: string }).status = this._calculateStatus();

  if (this.status === VALID || this.status === PENDING) {
    this._runAsyncValidator(opts.emitEvent);
  }
}

if (opts.emitEvent !== false) {
  (this.valueChanges as EventEmitter<any>).emit(this.value);
  (this.statusChanges as EventEmitter<string>).emit(this.status);
}

if (this._parent && !opts.onlySelf) {
  this._parent.updateValueAndValidity(opts);
}

Обратите внимание, что этот метод одинаков для: FormControl, FormArray и FormGroup.

Как видите, это также место, где this.valueChanges излучает. Это означает, что узел root (например, ваш formGroup в примере) будет в конечном итоге достигнут, и вы получите накопленные значения от всех других потомков ( элементы управления формой *) 1037 *).

Интересующий вас объект присваивается this.value, который разрешается в this._updateValue(), то есть entity-speci c. Для FormGroup это то, как определяется значение:

_updateValue(): void {
    (this as {value: any}).value = this._reduceValue();
  }

_reduceValue() {
  return this._reduceChildren(
    {}, (acc: { [k: string]: AbstractControl }, control: AbstractControl, name: string) => {
      if (control.enabled || this.disabled) {
        acc[name] = control.value;
      }
      return acc;
    });
}

Из приведенного выше вы можете заметить {}, который является новой ссылкой по сравнению с предыдущим объектом значения, предоставленным pairwise(). Таким образом, это должно объяснить, почему вы всегда получаете этот результат.

Один из способов решить эту проблему - выполнить глубокое сравнение между предыдущим и текущим значениями объекта.

Другой способ будет чтобы предотвратить обновление дерева, если не введено новое значение. Это включает работу на уровне leaf (например, FormControl с). Вы можете создать пользовательский элемент доступа к значению элемента управления и сделать там логи c.

Однако я не думаю, что select будет генерировать событие change, если выбрано то же значение. Демонстрация .

Если вы хотите изучить Angular Формы, я бы рекомендовал проверить эту статью .

...