Angular - 如何去除 PipeTransform 的抖动?

Angular - How to debounce PipeTransform?

我正在使用 *ngFor 来显示一个 collection,我还有一个 input 将用作过滤条件(这个 input 是一个 formControl).现在我添加了一个 PipeTransform 来根据 input 过滤我的 collection。 一切都按预期工作,但我不知道如何去抖动。我希望我的 filterPipeinput 中最后一次击键后 0.5 秒被调用,但目前它在我的 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
        );
      }
    }

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
      );
    });
  }
}

综上所述,我可能不会伸手去拿 angular 管道。

备用组件解决方案:

@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)
      );
    })
  );
}

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

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
      });
    })
  );
}