angular 仅当表单控件的先前值 !== 表单控件的当前值时才订阅更改

angular subscribe to changes only if previous value of the form control !== currentvalue of the formcontrol

仅当输入/选择的先前值 != 输入/选择的当前值时,我才想调用 onDataChange()。

但是我注意到,每当将光标放在输入字段上(但没有更改输入字段的任何值/更改下拉值的选择)时,它仍在调用 onDataChange()。

我已经使用了 startWith(null)、成对,然后是 filter(prev!=next),但它仍然执行 onDataChange(),即使前一个值与下一个值相同。

主要问题是将光标放在输入字段上但不更改任何值时,它仍然调用 onDataChange()。

我只想在输入值发生变化/下拉选择发生变化时调用 onDataChange() 。 onDataChange() 将调用 api 调用,这可能需要更长的时间来检索结果。

是否有人遇到类似问题并可以提供指导?谢谢

'

  <form class="form" [formGroup]="numberForm" noValidate [style.width.px]="width">
       <select name="types" id="dropdown-number-types" formControlName="dropdown">
           <option *ngFor="let type of types" [value]="type">{{type}}</option>
       </select>
    
       <input id="onValue" type="text" name="onValue" formControlName="onValue">
       <select name="equalsUnit" id="dropdown-number-unit" formControlName="onValueUnit">
            <option *ngFor="let unit of units" [value]="unit">{{unit}}</option>
       </select>
</form>

ngOnInit() {
  const valueChanges: Observable<any>[] = [
    this.numberForm.get('dropdown').valueChanges,
    this.numberForm.get('onValue').valueChanges,
    this.numberForm.get('onValueUnit').valueChanges
  ].map(obs =>
      obs.pipe(
          startWith(null), pairwise(),
          filter(([prev, next]) => prev !== next),
      )
  );

  // Merge all valueChanges observables into one - and debounce time for 250ms to avoid processing
  // events in quick succession which can happen if user is changing values quite fast in UI.
  merge(...valueChanges)
  .pipe(
      takeUntil(this.ngUnsubscribe),
      debounceTime(this.delay)
  )
  .subscribe(([prev, next]: [any, any]) => {
      this.onDataChange();
  });
  this.updateValidators();
  super.ngOnInit();
}

如果我删除合并并只观察 'onValue' 的 formcontrolname 的变化,那么它只会在值不同时执行 onDataChange()。

是否有任何替代方法可用于合并这 3 个 formcontrolname 并观察任何 formcontrolname 的更改?

如果理解正确,您需要 distinctUntilChanged 运算符,这就是我重构您的代码的方式:

const valueChanges: Observable<any>[] = [
  this.numberForm.get('dropdown').valueChanges,
  this.numberForm.get('onValue').valueChanges,
  this.numberForm.get('onValueUnit').valueChanges
].map(obs => obs.pipe(startWith(null)));

combineLatest(valueChanges).pipe(
  debounceTime(this.delay),
  distinctUntilChanged((prev, curr) =>
    prev[0] === curr[0] && prev[1] === curr[1] && prev[2] === curr[2]
  ),
  takeUntil(this.ngUnsubscribe),
).subscribe(() => {
  this.onDataChange();
});

注:

  • 我正在使用 combineLatest,因为 merge 将发出 3 个单独的事件,而 combineLatest 将在开始时发出 1 个组合事件。之后 combineLatest 将在每次更改时发出并为您提供 3 个 Observables 的更新组合值,其中 merge 只会为您提供一个更新值而不是组合值。
  • 使用 distinctUntilChanged 将新的合并值与之前的合并值进行比较。我特意把它放在 debounceTime 之后,因为你需要比较新的去抖值和旧的去抖值。