Only update search if input value has changed (key up)

Viewed 173

With the code below a user can make a search and press enter again, firing another api call without changing the search string. I'd like to make it so the api will only be called when the string has changed.

    <input
      matInput
      type="search"
      (keyup)="searchInputSubject.next($event)"
      placeholder="Search"
      #searchInput
    />
3 Answers

What about some inline logic?

    <input
      matInput
      type="search"
      (keyup)="if (!prevValue || searchInput.value != prevValue) { searchInputSubject.next($event); prevValue=searchInput.value;} "
      placeholder="Search"
      #searchInput
    />

Declare in your TS file a new variable

    public prevSearchTerm: string = '';

Also declare a new method to handle your keyup event

    keyupHandler(event: KeyboardEvent): void {
      if(this.prevSearchTerm && this.prevSearchTerm !== event.value) {
        this.searchInputSubject.next(event);
      }
    }

On top of that, you'll need a way to get the previous value.

    inputHandler(event: Event): void {
      this.prevSearchTerm = (event.target as HTMLInputElement).value;
    }

Then in your HTML must have something like this

    <input
      matInput
      type="search"
      (keyup.enter)="keyupHandler($event)"
      (input)="inputHandler($event)"
      placeholder="Search"
      #searchInput
    />

the keyup.enter will restrict to enter only event

From what I understood, Here you only want to call your logic when the user is done typing and the input is not equal to the previous input.

This can be archived by using rxjs operators.

You first need to get the reference of your input element in .ts this can be archived by @ViewChild and then in ngAfterViewInit() using fromEvent() convert our event into observable, then by use of rxjs operators we can achieve the following:

pluck('target', 'value'), : pluck allows us to pluck value property from our event object.

debounceTime(1000),: Discard emitted values that take less than the specified time in parameter(milliseconds) you can change it as per your requirement.

distinctUntilChanged(): Only emit when the current value is different than the last.

.ts

 import { Component, ElementRef, ViewChild } from '@angular/core';
    import { fromEvent, Subscription } from 'rxjs';
    import { debounceTime, distinctUntilChanged, pluck } from 'rxjs/operators';
    
    @Component({
      selector: 'my-app',
      templateUrl: './app.component.html',
      styleUrls: ['./app.component.css']
    })
    export class AppComponent {
      @ViewChild('searchInput') searchInput:ElementRef;
      serchObs: Subscription;
      ngAfterViewInit() {
        this.serchObs = fromEvent(this.searchInput.nativeElement, 'input')
          .pipe(
            pluck('target', 'value'),
            debounceTime(1000),
            distinctUntilChanged()
          )
          .subscribe(value => {
           // Your Logic
            searchInputSubject.next(value);
          });
      }
      ngDestroy() {
        this.serchObs.unsubscribe();
      }
    }

.HTML

<input
      matInput
      type="text"
      placeholder="Search"
      #searchInput
    />

 

To find documentation click -> debounceTime, distinctUntilChanged, pluck, RxJs Operators

Related