konradns
konradns

Reputation: 97

angular 2 search input with debounceTime and onFocusOut

I have a problem with search input. In Angular 2 project I have search input:

 <input [(ngModel)]="data.value" (keyup)="input$.next($event)" (focusout)="onFocusOut($event)" />

and on my typescrirpt:

input$ = new Subject<any>();
ngOnInit() {
  this.input$
    .do(this.keyUpEventHandler.bind(this))
    .debounceTime(3000)
    .distinctUntilChanged()
    .subscribe((value) => {
      console.log('afterDebounce', value);
// do http request in service
        });
  }

  onFocusOut(event) {
    //this.input$.skipLast(1);
   // do http request in service immediately 
  }

And my problem is when I typing... and click enter, simply lost focus from my input component, I call http request but after 3 seconds also call once again. Is any solution to dismiss that last next for input$ observable?

I don't like to unsubscribe whole observable, because I'd like to use it later (if user want to search data) Thanks!

Upvotes: 1

Views: 2285

Answers (1)

Gili Yaniv
Gili Yaniv

Reputation: 3221

You can create two streams of data, One for the 'keyUp' event and one for the 'blur' event. Than with a little bit of RxJs magic do the following :

@ViewChild('searchValueInput') searchValueInput: any;

constructor(private http: HttpClient) {
      }

ngAfterViewInit() {
    this.subscribeToInputChanges();
    }

subscribeToInputChanges(){
  let keyUp$:Observable<any>=Observable.fromEvent     
  (this.searchValueInput.nativeElement, 'keyup')
    .debounceTime(3000)
    .distinctUntilChanged();

let focusOut$:Observable<any>=Observable
.fromEvent(this.searchValueInput.nativeElement, 'blur');

  Observable.defer(()=>Observable.race(
    keyUp$,
    focusOut$
  ))
  .take(1)
  .repeat()
  .subscribe(res=>{
    this.http.get('someURL')
    .subscribe(response=>{
      //Handle response
    })
  })
}

Any your html:

  <input #searchValueInput type="text" class="search" placeholder="Search">

The keyUp$ observable is the same as you created. The focusOut$ observable is very slimier to keyUp$, It been created from 'blur' event and emit data immediately (Without debounceTime).

We combine them together using the race operator witch tell the observable to use the first observable that emits.

We also wrap this 'race' observable inside another defer observable. The defer observable with the take(1) and repeat() is responsible for keeping the subscription alive and not always use the same observable (keyUp$ or focusOut$).

Iv'e created a small stackblitz that show's all of the above in a working example.

Upvotes: 3

Related Questions