2
votes

I have an input search element that I detect keyup and I want to use debounce to limit request made to the API but I can't get it working. I'm just trying to test debounceTime and distinctUntilChanged.

I have already tried (Keyup) but can't get it working.

<input (keyup)="onKeyUp($event)"  id="testInput" autocomplete="off" type="text" name="searchFilterText" class="m-list-search__form-input" value="" placeholder="Search...">

Here is the code from the typescript file.

searchInput = document.getElementById('testInput');
observable: any;

/// <summary>
/// Process the search term provided on key up for the input field.
/// </summary>
/// <param name="searchTerm">The search term.</param>
onKeyUp(event: KeyboardEvent) {
    //console.log(event);
    let element = event.target as HTMLInputElement;
    let value = element.value;

    this.observable = fromEvent(this.searchInput, event.type)
        .debounceTime(500) // millisecs until value gets emitted.
        .distinctUntilChanged()
        .subscribe(function (event) {
            console.log(event.target.value);
        });
}

The expected result is a delayed search result value in the console log using debounceTime and distinctUntilChanged.

1

1 Answers

6
votes

You could try this:

Template

<input  
       id="testInput" autocomplete="off"
       type="text" #searchText
       name="searchFilterText" class="m-list-search__form-input"
       value=""
       placeholder="Search...">

Notice the template reference variable: #searchText. This allows access to the input element without needing getElementById (which is not normally recommended to use in an Angular app).

Component

import { Component, AfterViewInit, ViewChild } from '@angular/core';
import { fromEvent } from 'rxjs';
import { debounceTime } from 'rxjs/operators';

@Component({
   templateUrl: './search.component.html'
})
export class SearchComponent implements AfterViewInit {
  @ViewChild('searchText') searchTextRef;

  ngAfterViewInit() {
    if (this.searchTextRef) {
      fromEvent(this.searchTextRef.nativeElement, 'keyup')
        .pipe(
            debounceTime(500),
            distinctUntilChanged()
        ).subscribe(
          value => console.log(this.searchTextRef.nativeElement.value)
        )
    }
  }
}

This code uses @ViewChild to get the reference to the element marked with the #searchText template reference variable.

It then uses code similar to what you had for the debounceTime.

I have a stackblitz here: https://stackblitz.com/edit/angular-debounce-deborahk

And you can find more info here: Observable.fromEvent - RXJS

Note: This is even easier if you use reactive forms as you can directly access the valueChanges observable for any input element on a form.

Reactive Forms

Template

<input  
       id="testInput"
       [formControl]="search"
       autocomplete="off"
       type="text"
       class="m-list-search__form-input"
       value=""
       placeholder="Search...">

Notice the formControl directive.

Component

  // For reactive forms
  search = new FormControl();

  ngOnInit() {
    this.search.valueChanges
            .pipe(
          debounceTime(500),
          distinctUntilChanged()
        ).subscribe(
          value => console.log("Reactive Forms implementation: " + value)
        )
  }