【问题标题】:Angular - How to debounce PipeTransform?Angular - 如何去抖动 PipeTransform?
【发布时间】:2021-11-21 14:15:16
【问题描述】:

我使用*ngFor 来显示一个集合,我还有一个input 将用作过滤条件(这个input 是一个formControl)。现在我添加了一个PipeTransform 来根据input 过滤我的收藏。 一切都按预期工作,但我不知道如何去抖动。我希望我的filterPipeinput 内的最后一次击键后0.5s 被调用,但目前在我的input 内发生任何更改后立即调用它。

HTML:


    <div class="test-ctr">
      <div class="form-ctr">
        <form class="example-form" [formGroup]="filterForm">>
          <input formControlName="nick" placeholder="ex. hdw"> 
        </form>
      </div>
      <div class="app-cards-ctr">
        <div class="app-card-ctr" *ngFor="let nick of nicks | filterPipe: filterForm.get('nick')?.value">
          <app-card [nick]="nick"></app-card>
        </div>
      </div>
    </div>

Component.ts:


    import { Component, OnInit } from '@angular/core';
    import { FormBuilder } from '@angular/forms';
    
    @Component({
      selector: 'app-test',
      templateUrl: './test.component.html',
      styleUrls: ['./test.component.scss'],
    })
    export class TestComponent implements OnInit {
      nicks: string[] = ['Siema', 'Elo', 'Tu', 'Hdw3DCtV', 'and', 'Gównow', 'Zdzisiu11', 'Zdzisiu1','Zdzisiu2','Zdzisiu3','Zdzisiu4','Zdzisiu5'];
    
      constructor(private formBuilder: FormBuilder) {}
    
      filterForm = this.formBuilder.group({
        nick: ['']
      })
    
      ngOnInit(): void {}
    }

Pipe.ts:


    import { Pipe, PipeTransform } from '@angular/core';
    
    @Pipe({ name: 'filterPipe', pure: true })
    export class FilterPipe implements PipeTransform {
      transform(value: string[], arg: string): string[] {
        console.log(arg);
        return value.filter(
          (e) => e.toLowerCase().indexOf(arg.toLowerCase()) !== -1
        );
      }
    }

【问题讨论】:

  • 从未尝试过这个,但也许这个? filterPipe: (filterForm.get('nick')?.valueChanges.pipe(debounceTime(500)) | async)
  • @MikeOne 我已经尝试过了,但它仍然会立即触发 filterPipe 的任何更改。我没有对它进行太多调查,所以也许我做错了什么,但我认为如果我在那里订阅,而不是在调用 filterPipe 之前,这种情况下的去抖动会发生在 filterPipe 内部。我想我需要以某种方式延迟我的 from 所以它不会立即检测到变化,但我不知道这是否可能或者这是否是一个好的解决方案

标签: angular typescript filter pipe debounce


【解决方案1】:

对我来说,最好的方法是在组件内部而不是在模板中使用管道。

constructor(
  private filterPipe: FilterPipe
) {}

ngOnInit() {
 this.filterForm.controls.nick.valueChanges.pipe(
    startWith(''),
    debounceTime(500),
    map(value => {
      this.nicks.forEach(nick => {
          nick = this.filterPipe.transform(value, nick); // or what you want to do
      });
    })
  );
}

【讨论】:

    【解决方案2】:

    Working example in Stackblitz

    HTML:

    <h3>Filter:</h3>
    <form [formGroup]="filterForm">
      <input type="text" formControlName="nick" />
    </form>
    
    <h3>Nicks:</h3>
    <div *ngFor="let nick of nicks | filterPipe: (debouncedControl$ | async)">
      {{ nick }}
    </div>
    

    组件:

    @Component({
      selector: 'my-app',
      templateUrl: './app.component.html',
      styleUrls: ['./app.component.css'],
    })
    export class AppComponent {
      nicks: string[] = [
        'Siema',
        'Elo',
        'Tu',
        'Hdw3DCtV',
        'and',
        'Gównow',
        'Zdzisiu11',
        'Zdzisiu1',
        'Zdzisiu2',
        'Zdzisiu3',
        'Zdzisiu4',
        'Zdzisiu5',
      ];
    
      constructor(private formBuilder: FormBuilder) {}
    
      filterForm = this.formBuilder.group({
        nick: [''],
      });
    
      debouncedControl$ = this.filterForm.controls.nick.valueChanges.pipe(
        startWith(''),
        debounceTime(500)
      );
    }
    

    管道:

    @Pipe({
      name: 'filterPipe',
    })
    export class FilterPipe implements PipeTransform {
      transform(values: string[], inputValue: string): string[] {
        return values.filter((v) => {
          return (
            v.toLowerCase().indexOf((inputValue || '').toLocaleLowerCase()) > -1
          );
        });
      }
    }
    

    话虽如此,这可能不是我会伸手去拿角管的场景。

    替代组件解决方案:

    @Component({
      selector: 'alternate',
      template: `
        <form [formGroup]="filterForm">
            <input type="text" formControlName="nick" />
        </form>
    
        <ul>
          <li *ngFor="let nick of filteredNicks$ | async"> {{nick}} </li>
        </ul>
      `,
    })
    export class AlternateSolutionComponent {
      constructor(private formBuilder: FormBuilder) {}
    
      nicks = ['Siema', 'Elo', 'Tu'];
    
      lowercaseIncludes(a: string, b: string): boolean {
        return a.toLocaleLowerCase().indexOf(b.toLocaleLowerCase()) > -1;
      }
    
      filterForm = this.formBuilder.group({ nick: [''] });
    
      filteredNicks$ = this.filterForm.controls.nick.valueChanges.pipe(
        startWith(''),
        debounceTime(500),
        map((inputValue) => {
          return this.nicks.filter((nick) =>
            this.lowercaseIncludes(nick, inputValue)
          );
        })
      );
    }
    

    【讨论】:

    • 我喜欢您的替代解决方案,但我认为您的第一个建议与我正在寻找的有所不同。我正在寻找一种方法来延迟 filterPipe 内的 transform 函数的执行,而不是延迟过滤本身,这已经发生在 transform 函数内。换句话说,我如何才能以 transform 函数仅在某人完成输入后(例如最后一次击键后 0.5 秒)调用一次的方式来消除我的输入抖动
    • @hdw3 - 好的,我想我明白了。更新了答案和 stackblitz。除了处理过滤器管道内的 observable 之外,您还可以对组件中的输入进行去抖动处理并将其通过async 管道传递给您的filterPipe。第一个建议是否更符合您最初的问题?
    猜你喜欢
    • 2017-05-09
    • 2015-11-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多