How to only execute an Observable if term is not null/empty?
Asked Answered
D

4

24

I have the following code inside my constructor:

this.searchResults = this.searchTerm.valueChanges
    .debounceTime(500)
    .distinctUntilChanged()
    .switchMap(term => this.apiService.search({
        limit: this.searchResultsLimit,
        term: term
    }));

And this is my input

<input type="text" [formControl]="searchTerm" />

You can see the tutorial I followed to get the code here.

My API service method is as followed:

searchCompanies(options): Observable<any[]> {
    return this.jsonp.get('api/search', this.formatOptions(options)).map(res => {   
        return res.json();
    });
}

Each time searchTerm is changed inside my input, the API call is fired. My problem is that the call is fired even when my input is empty (such as typing a query, then backspacing it all).

My question is, how can I only get my observable to fire when the value of `searchTerm is not empty/null?

Dory answered 20/2, 2017 at 0:19 Comment(3)
You can have a if condition in the constructorVassallo
Wouldn't it be simply to do a check on your service?Runofthemill
@Runofthemill - My service is a straight observable. I'll make an edit to the question with the method now.Dory
T
9

If you want to avoid the API call and want the search results to be reset when the search term is empty, test for an empty string in switchMap and return an empty observable in that situation:

this.searchResults = this.searchTerm
  .valueChanges
  .debounceTime(500)
  .distinctUntilChanged()
  .switchMap(term => term ?
    this.apiService.search({
      limit: this.searchResultsLimit,
      term: term
    }) :
    // If search term is empty, return an empty array
    // or whatever the API's response for no matches
    // would be:
    Observable.of([]) 
  });
Territorialism answered 20/2, 2017 at 0:55 Comment(2)
Neat. But unfortunately, the searchResults does not get emptied when the term is empty/null.Dory
Well, in that case you should return whatever the API would return if there was no match. For example, to return an empty array, replace Observable.empty() with Observable.of([]).Territorialism
Q
40

Most easily just use the filter() operator to filter out all empty terms:

this.searchResults = this.searchTerm.valueChanges
    .filter(term => term) // or even better with `filter(Boolean)`
    .debounceTime(500)
    .distinctUntilChanged()
    .switchMap(term => this.apiService.search({
        limit: this.searchResultsLimit,
        term: term
    }));
Questor answered 20/2, 2017 at 0:29 Comment(5)
Works seamlessly. Although it then leaves the issue of this.searchResults being the value of the last returned results from the API service when term is empty. How could this.searchResults be set to null or undefined if the search term is empty?Dory
Your this.searchResults hold the Observable so you probably don't want to override it.Questor
filter saved my date.Aqua
use filter as.filter(term => term != null)Teenateenage
Really this should be the answerTantara
T
9

If you want to avoid the API call and want the search results to be reset when the search term is empty, test for an empty string in switchMap and return an empty observable in that situation:

this.searchResults = this.searchTerm
  .valueChanges
  .debounceTime(500)
  .distinctUntilChanged()
  .switchMap(term => term ?
    this.apiService.search({
      limit: this.searchResultsLimit,
      term: term
    }) :
    // If search term is empty, return an empty array
    // or whatever the API's response for no matches
    // would be:
    Observable.of([]) 
  });
Territorialism answered 20/2, 2017 at 0:55 Comment(2)
Neat. But unfortunately, the searchResults does not get emptied when the term is empty/null.Dory
Well, in that case you should return whatever the API would return if there was no match. For example, to return an empty array, replace Observable.empty() with Observable.of([]).Territorialism
L
2

In Rxjs 6 so updated to use pipe you can stop the observable from processing so nothing is propagated downstream using EMPTY:

this.searchResults = this.searchTerm.valueChanges
    .pipe(
      debounceTime(500)
      distinctUntilChanged()
      switchMap(term => 
        (term) 
          // If the term exists make a request
          ? this.apiService.search({ limit: this.searchResultsLimit, term: term })
          // Otherwise, stop all processing
          : EMPTY
      )
    )
);
Lytton answered 23/9, 2020 at 22:32 Comment(0)
P
0

Note to self... if you're going crazy thinking that null is still passing by the filter, then make sure it's not actually a string like 'null'.

Pennsylvania answered 15/2, 2023 at 0:19 Comment(1)
You might check for 'undefined', '0' 'false' then....Faction

© 2022 - 2024 — McMap. All rights reserved.