Angular Reactive Forms:仅去抖某些特定的表单控件

问题描述 投票:0回答:8

我有一个简单的搜索组件,其中包含一个带有 2 个元素的反应式表单:

  • 文本输入(搜索任意匹配的文本)
  • 复选框(包括/排除已删除的结果)

到目前为止,我使用

myFormGroup.valueChanges.subscribe(...)
来执行我的搜索方法。

现在的问题是,我想去抖文本输入。同时 not debounce 复选框,所以搜索方法在点击复选框时立即执行。

使用

valueChanges.debounceTime(500)
当然会消除整个表单的抖动。那不是我想要的。

这是一个精简的例子。真实的形式有更多的输入。有些应该去抖,有些不应该。

有什么简单的方法可以做到这一点吗?还是我必须分别订阅每个表单控件?

很高兴看到你是如何解决这个问题的。

提前致谢。


编辑:代码

export class SearchComponent {

  myFormGroup: FormGroup;

  constructor(fb: FormBuilder) {
    this.myFormGroup = fb.group({
      textInput: '',
      checkbox: false
    });
  }

  ngOnInit() {
    this.myFormGroup.valueChanges.subscribe(val => {
      // debounce only the textInput,
      // and then execute search
    });
  }

}
angular angular-forms angular-reactive-forms debouncing
8个回答
35
投票

在将它们添加到表单组之前创建每个单独的 FormControl,然后您可以控制每个 FormControl 可观察到的 valueChanges

this.textInput.valueChanges
      .pipe(
        debounceTime(400),
        distinctUntilChanged()
      )
      .subscribe(res=> {
        console.log(`debounced text input value ${res}`);
      });

distinctUntilChanged 将确保只有当值不同时才会发出一些东西。


7
投票

Debounce 文本控件的

valueChanges
observable,然后使用
combineLatest()
将其与复选框控件的
valueChanges
observable 结合。

简单的例子


6
投票

表单组中单个控件的去抖可以通过

完成
   this.form.get('textInput')
  .valueChanges
  .pipe(debounceTime(500))
  .subscribe(dataValue => {
    console.log("dataValue", dataValue);
  });

5
投票

现在我有那个问题,我解决了如下!

// Reactive control
fieldOne = this.formBuilder.control('');

// Reactive form
formGroup = this.formBuilder.group({
  fieldOne: [],
  fieldTwo: [],
  fieldX: [],
});

this.fieldOne.valueChanges
  .pipe(debounceTime(300))
  .subscribe(value => {
    this.formGroup.get('fieldOne').setValue(value);
  });

您在表单组内的控件中有响应速度,并且从单个控件发出的事件有延迟,希望将来 formGroup 发出的 valueChanges 将呈现触发事件的控件并能够在中使用过滤器可观察的

问候!


1
投票

喜欢这个解决方案。可以根据需要检查任意数量的属性。

this.formGroup
  .valueChanges
  .pipe(
    startWith(this.formGroup.value),
    pairWise(),
    debounce(([p, c]) => p.textInput !== c.textInput ? timer(500) : timer(0))
  ).subscribe(([_, curr]) => this.usefullCallback(curr));

0
投票

GitHub 上有一个问题,将来可能(?!)解决这个问题:

https://github.com/angular/angular/issues/19705

然后应该可以(就像在 AngularJS 中一样)去抖动单个输入字段。


0
投票

我遇到了同样的问题,在我的例子中创建了一个新的输入组件并在没有任何自定义代码的情况下在 html 中提供了去抖动值解决了问题


0
投票

您可以在您的formGroup上获得valueChanges并仅添加debounceTime(或去抖动)如果某个字段发生变化

import { startWith } from 'rxjs/operators';
import { debounce, pairwise, timer } from 'rxjs';
...

this.formGroup
  .valueChanges
  .pipe(
    startWith(this.formGroup.value),
    pairWise(),
    debounce(
    ([p, c]) => beforeValueChanges.search !== afterValueChanges.search 
        ? timer(500) 
        : timer(0)
    )
  ).subscribe(([unusedValue, afterValueChanges]) => {
    // .. Do what you want with afterValueChanges
  }

管道说明:

  1. startWith() 获取 formGroup 值,在 valueChanges 之前
  2. pairWise() 将使用 [beforeValueChanges, afterValueChanges] 创建数组
  3. debounce() 检查前后的 textInput 是否不同,如果为真,则设置 debounce 500。

感谢Sasha的回答

© www.soinside.com 2019 - 2024. All rights reserved.