angulartypescriptdebouncingangular2-pipe

Angular 2 add debounce function directly to pipe


I've written a pipe that filters out an array of objects based on a given query. It works great but what I'd like to do is add a debounce function to this pipe directly, instead of adding it to the input's keyup event, if possible.

I've been looking around for a solution but can't seem to find anything that's specific to what I'm looking for.

import {Pipe, PipeTransform} from '@angular/core';

@Pipe({
  name: 'filterBy'
})

export class FilterByPipe implements PipeTransform {

  transform(value: any, args: string[]): any[] {

    if (!args[0]) {
      return value;
    }
    else if (value) {

      return value.filter(item => {

        // TODO: Allow args[1] to be null, therefore searching in all object properties
        if ((typeof item[args[1]] === 'string' || item[args[1]] instanceof String) && (item[args[1]].toLowerCase().indexOf(args[0].toLowerCase()) !== -1)) {
          return true;
        }
      });
    }
  }
}

Any ideas on how I would implement this in this pipe?


Solution

  • The debounce or delay functions are async, in this case you need to return a promise or an observable from your pipe and use the async pipe. I created a simple example to show you how to do that with observable.

    @Pipe({
        name: 'myfilter'
    })
    
    export class MyFilterPipe implements PipeTransform {
        transform(items, filterBy) {
          const filteredItems = items.filter(item => item.title.indexOf(filterBy.title) !== -1);
          return Observable.of(filteredItems).delay(1000);
        }
    }
    
    
    @Component({
      selector: 'my-app',
      template: `
        <div>
          <ul>
            <li *ngFor="let item of items | myfilter:filterBy | async">
             {{item.title}}
            </li>
          </ul>
    
          <input type="text" (input)="filter($event)">
    
        </div>
      `,
    })
    export class App {
      filterBy;
      constructor() {
        this.filterBy = {title: 'hello world'};
        this.items = [{title: 'hello world'}, {title: 'hello kitty'}, {title: 'foo bar'}];
      }
    
      filter($event) {
        this.filterBy = {title: $event.target.value}
      }
    }
    

    Plunker